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
+ } ) ;
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,14 @@ 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 ) ;
85
+ const errors = extractErrorsFromResults ( results )
104
86
105
87
if ( success ) {
106
88
next ( ) ;
107
89
} else {
108
- throw firstError ;
90
+ const allErrors = errors . flatMap ( it => [ ...it ] ) ;
91
+ throw allErrors . find ( Boolean )
109
92
}
110
93
} catch ( e ) {
111
94
const message = e ?. error ?. message || 'unauthorized' ;
@@ -129,6 +112,7 @@ class SecuritySchemes {
129
112
private securitySchemes : SecuritySchemesMap ;
130
113
private securityHandlers : SecurityHandlers ;
131
114
private securities : OpenAPIV3 . SecurityRequirementObject [ ] ;
115
+
132
116
constructor (
133
117
securitySchemes : SecuritySchemesMap ,
134
118
securityHandlers : SecurityHandlers ,
@@ -213,6 +197,7 @@ class AuthValidator {
213
197
private scheme ;
214
198
private path : string ;
215
199
private scopes : string [ ] ;
200
+
216
201
constructor ( req : OpenApiRequest , scheme , scopes : string [ ] = [ ] ) {
217
202
const openapi = < OpenApiRequestMetadata > req . openapi ;
218
203
this . req = req ;
0 commit comments