1
1
import {
2
- OpenAPIV3 ,
2
+ HttpError ,
3
+ InternalServerError ,
3
4
OpenApiRequest ,
4
- SecurityHandlers ,
5
- OpenApiRequestMetadata ,
6
5
OpenApiRequestHandler ,
7
- InternalServerError ,
8
- HttpError ,
6
+ OpenApiRequestMetadata ,
7
+ OpenAPIV3 ,
8
+ SecurityHandlers ,
9
9
} from '../framework/types' ;
10
10
11
11
const defaultSecurityHandler = (
@@ -17,11 +17,30 @@ const defaultSecurityHandler = (
17
17
type SecuritySchemesMap = {
18
18
[ key : string ] : OpenAPIV3 . ReferenceObject | OpenAPIV3 . SecuritySchemeObject ;
19
19
} ;
20
+
20
21
interface SecurityHandlerResult {
21
22
success : boolean ;
22
23
status ?: number ;
23
24
error ?: string ;
24
25
}
26
+
27
+ function extractErrorsFromResults ( results : ( SecurityHandlerResult | SecurityHandlerResult [ ] ) [ ] ) {
28
+ return results . map ( result => {
29
+ if ( Array . isArray ( result ) ) {
30
+ return result . map ( it => it ) . filter ( it => ! it . success ) ;
31
+ }
32
+ return [ result ] . filter ( it => ! it . success ) ;
33
+ } ) . flatMap ( it => [ ...it ] ) ;
34
+ }
35
+
36
+ function didAllSecurityRequirementsPass ( results : SecurityHandlerResult [ ] ) {
37
+ return results . every ( it => it . success ) ;
38
+ }
39
+
40
+ function didOneSchemaPassValidation ( results : ( SecurityHandlerResult | SecurityHandlerResult [ ] ) [ ] ) {
41
+ return results . some ( result => Array . isArray ( result ) ? didAllSecurityRequirementsPass ( result ) : result . success ) ;
42
+ }
43
+
25
44
export function security (
26
45
apiDoc : OpenAPIV3 . Document ,
27
46
securityHandlers : SecurityHandlers ,
@@ -62,50 +81,13 @@ export function security(
62
81
63
82
// TODO handle AND'd and OR'd security
64
83
// This assumes OR only! i.e. at least one security passed authentication
65
- let firstError : SecurityHandlerResult = null ;
66
- let success = false ;
67
-
68
- function checkErrorWithOr ( res ) {
69
- return res . forEach ( ( r ) => {
70
- if ( r . success ) {
71
- success = true ;
72
- } else if ( ! firstError ) {
73
- firstError = r ;
74
- }
75
- } ) ;
76
- }
77
-
78
- function checkErrorsWithAnd ( res ) {
79
- let allSuccess = false ;
80
-
81
- res . forEach ( ( r ) => {
82
- if ( ! r . success ) {
83
- allSuccess = false ;
84
- if ( ! firstError ) {
85
- firstError = r ;
86
- }
87
- } else if ( ! firstError ) {
88
- allSuccess = true ;
89
- }
90
- } ) ;
91
-
92
- if ( allSuccess ) {
93
- success = true ;
94
- }
95
- }
96
-
97
- results . forEach ( ( result ) => {
98
- if ( Array . isArray ( result ) && result . length > 1 ) {
99
- checkErrorsWithAnd ( result ) ;
100
- } else {
101
- checkErrorWithOr ( result ) ;
102
- }
103
- } ) ;
84
+ const success = didOneSchemaPassValidation ( results ) ;
104
85
105
86
if ( success ) {
106
87
next ( ) ;
107
88
} else {
108
- throw firstError ;
89
+ const errors = extractErrorsFromResults ( results )
90
+ throw errors [ 0 ]
109
91
}
110
92
} catch ( e ) {
111
93
const message = e ?. error ?. message || 'unauthorized' ;
@@ -129,6 +111,7 @@ class SecuritySchemes {
129
111
private securitySchemes : SecuritySchemesMap ;
130
112
private securityHandlers : SecurityHandlers ;
131
113
private securities : OpenAPIV3 . SecurityRequirementObject [ ] ;
114
+
132
115
constructor (
133
116
securitySchemes : SecuritySchemesMap ,
134
117
securityHandlers : SecurityHandlers ,
@@ -213,6 +196,7 @@ class AuthValidator {
213
196
private scheme ;
214
197
private path : string ;
215
198
private scopes : string [ ] ;
199
+
216
200
constructor ( req : OpenApiRequest , scheme , scopes : string [ ] = [ ] ) {
217
201
const openapi = < OpenApiRequestMetadata > req . openapi ;
218
202
this . req = req ;
0 commit comments