UNPKG

2.95 kBJavaScriptView Raw
1'use strict'
2
3const fileAuthorizers = require('./fileAuthorizers')
4
5exports.getAuthorizers = getAuthorizers
6exports.createAuthCheck = createAuthCheck
7
8function getAuthorizers(securityDefinitions, options) {
9 return getDefinitionIds(securityDefinitions)
10 .map(id => ({ id, auth: getAuthorizer(id, securityDefinitions[id], options) }))
11 .reduce((authorizers, info) => authorizers.set(info.id, info.auth), new Map())
12}
13
14function getDefinitionIds(security) {
15 return Object.keys(security || {})
16 .filter(id => !id.startsWith('x-'))
17}
18
19function getAuthorizer(id, securityScheme, options) {
20 let authorizer
21 if (typeof options.authorizers.create === 'function') authorizer = options.authorizers.create(id, securityScheme)
22 if (authorizer) fileAuthorizers.disableAuthorizer(id, options)
23 else authorizer = requireAuthorizer(id, securityScheme, options)
24 if (authorizer && authorizer.default) authorizer = authorizer.default
25 return authorizer
26}
27
28function requireAuthorizer(id, securityScheme, options) {
29 const fileInfo = fileAuthorizers.enableAuthorizer(id, securityScheme, options)
30 try { return require(fileInfo.path) }
31 catch(e) {
32 if (e.code === 'MODULE_NOT_FOUND') return null
33 else throw e
34 }
35}
36
37function createAuthCheck(operation, authorizers) {
38 let security = operation.security || []
39 if (security && !Array.isArray(security)) security = [ security ]
40 if (!security.length) return null
41
42 return function authorize(req, res, next) {
43 return Promise.all(security.map(scheme => {
44 const id = Object.keys(scheme)[0]
45 if (!id || id.startsWith('x-')) return null
46
47 return new Promise((resolve, reject) => {
48 const authorizer = authorizers.get(id)
49 if (typeof authorizer === 'function') {
50 const requiredScopes = scheme[id]
51 req.verifyScopes = function verifyScopes(scopes) {
52 return verifyRequiredScopes(requiredScopes, scopes)
53 }
54 try {
55 const result = authorizer(req, res, err => err ? reject(err) : resolve())
56 if (result && result.catch) result.catch(e => reject(e))
57 } catch(e) {
58 reject(e)
59 }
60 } else {
61 // Unable to determine at this point if authorized but don't
62 // have correct scope(s), or if authorization is required.
63 // Assume the latter.
64 const e = new Error('Unauthorized')
65 e.statusCode = e.status = 401
66 reject(e)
67 }
68 })
69 }))
70 .then(() => next())
71 .catch(e => next(e))
72 }
73}
74
75function verifyRequiredScopes(requiredScopes, scopes) {
76 if (!requiredScopes || !requiredScopes.length) return undefined
77 if (!scopes) scopes = []
78
79 const hasRequiredScopes = requiredScopes.every(scope => scopes.indexOf(scope) !== -1)
80 if (!hasRequiredScopes) {
81 const e = new Error('Forbidden')
82 e.statusCode = e.status = 403
83 e.requiredScopes = requiredScopes
84 return e
85 }
86 return undefined
87}