1 | 'use strict'
|
2 |
|
3 | const { default: fetch, Headers } = require('node-fetch')
|
4 |
|
5 | const { AUTH_ENDPOINT, REQUIRED } = require('./config')
|
6 | const { APIError, ArgumentError, ERRORS } = require('./errors')
|
7 |
|
8 | function extractToken (res) {
|
9 | const token = res.payload.user && res.payload.user.authToken
|
10 | if (token) { return Promise.resolve(token) }
|
11 | throw new APIError(res.status, res.statusText, 'Payload is missing token.')
|
12 | }
|
13 |
|
14 | async function parseAPIResponse (res) {
|
15 | const data = {
|
16 | payload: await res.json(),
|
17 | status: res.status,
|
18 | statusText: res.statusText
|
19 | }
|
20 | if (res.ok) { return data }
|
21 | throw new APIError(res.status, res.statusText, data.payload.error)
|
22 | }
|
23 |
|
24 | function validateOptions (options) {
|
25 | let missing = []
|
26 |
|
27 | if (!(options && options.constructor === Object)) {
|
28 | throw new ArgumentError(ERRORS.missingOptionsArg)
|
29 | }
|
30 | missing = (
|
31 | opts => REQUIRED.options.filter(k => !opts.includes(k))
|
32 | )(Object.keys(options))
|
33 | if (missing.length > 0) {
|
34 | throw new ArgumentError({ ...ERRORS.missingOptions, missing })
|
35 | }
|
36 | const { headers: hdrs, password: pw, username: un } = options
|
37 |
|
38 | if (!(
|
39 | hdrs &&
|
40 | (
|
41 | hdrs.constructor === Object ||
|
42 | hdrs.constructor === Headers
|
43 | ))) {
|
44 | throw new ArgumentError(ERRORS.missingHeadersOpt)
|
45 | }
|
46 | missing = REQUIRED.headers.filter(
|
47 | h => hdrs.get ? !hdrs.get(h) : !(typeof hdrs[h] === 'string' && hdrs[h])
|
48 | )
|
49 | if (missing.length > 0) {
|
50 | throw new ArgumentError({ ...ERRORS.missingHeaders, missing })
|
51 | }
|
52 |
|
53 | if (!(typeof pw === 'string' && !!pw)) {
|
54 | throw new ArgumentError(ERRORS.missingPassword)
|
55 | }
|
56 | if (!(typeof un === 'string' && !!un)) {
|
57 | throw new ArgumentError(ERRORS.missingUsername)
|
58 | }
|
59 |
|
60 | return true
|
61 | }
|
62 |
|
63 | class PlexAppAuthenticator {
|
64 | constructor ({ headers = {}, username = '', password = '' } = {}) {
|
65 | validateOptions(arguments[0])
|
66 |
|
67 | this.headers = new Headers(headers)
|
68 | this.options = { username, password }
|
69 | this.token = ''
|
70 |
|
71 | return this
|
72 | }
|
73 |
|
74 | authorize () {
|
75 | const params = new URLSearchParams()
|
76 |
|
77 | this.headers.set('Accept', 'application/json')
|
78 | this.headers.set('Content-Type', 'application/x-www-form-urlencoded')
|
79 | params.set('user[login]', this.options.username)
|
80 | params.set('user[password]', this.options.password)
|
81 |
|
82 | return fetch(AUTH_ENDPOINT, {
|
83 | method: 'POST',
|
84 | body: params,
|
85 | headers: this.headers
|
86 | })
|
87 | .then(parseAPIResponse)
|
88 | .then(extractToken)
|
89 | .then(token => {
|
90 | this.token = token
|
91 | return token
|
92 | })
|
93 | }
|
94 | }
|
95 |
|
96 | module.exports = exports = PlexAppAuthenticator
|
97 | module.exports.default = exports
|
98 | module.exports.APIError = APIError
|
99 | module.exports.ArgumentError = ArgumentError
|