@@ -43,22 +43,35 @@ export class TokenRolesGuard implements CanActivate {
43
43
throw new UnauthorizedException ( 'Missing or invalid token!' ) ;
44
44
}
45
45
46
- // Check role-based access for regular users
47
- if ( Array . isArray ( user . roles ) && requiredRoles . length > 0 ) {
48
- const normalizedUserRoles = user . roles
49
- . map ( ( role ) => String ( role ) . trim ( ) . toLowerCase ( ) )
50
- . filter ( ( role ) => role . length > 0 ) ;
46
+ const normalizedRequiredRoles = requiredRoles . map ( ( role ) =>
47
+ String ( role ) . trim ( ) . toLowerCase ( ) ,
48
+ ) ;
51
49
52
- const normalizedRequiredRoles = requiredRoles . map ( ( role ) =>
53
- String ( role ) . trim ( ) . toLowerCase ( ) ,
54
- ) ;
50
+ // Check role-based access for regular users
51
+ if ( normalizedRequiredRoles . length > 0 ) {
52
+ const normalizedUserRoles = Array . isArray ( user . roles )
53
+ ? user . roles
54
+ . map ( ( role ) => String ( role ) . trim ( ) . toLowerCase ( ) )
55
+ . filter ( ( role ) => role . length > 0 )
56
+ : [ ] ;
55
57
56
58
const hasRole = normalizedRequiredRoles . some ( ( role ) =>
57
59
normalizedUserRoles . includes ( role ) ,
58
60
) ;
59
61
if ( hasRole ) {
60
62
return true ;
61
63
}
64
+
65
+ if (
66
+ this . allowSubmissionListByChallenge (
67
+ context ,
68
+ request ,
69
+ normalizedRequiredRoles ,
70
+ user ,
71
+ )
72
+ ) {
73
+ return true ;
74
+ }
62
75
}
63
76
64
77
// Check scope-based access for M2M tokens
@@ -95,4 +108,54 @@ export class TokenRolesGuard implements CanActivate {
95
108
throw new UnauthorizedException ( 'Invalid token' ) ;
96
109
}
97
110
}
111
+
112
+ private allowSubmissionListByChallenge (
113
+ context : ExecutionContext ,
114
+ request : any ,
115
+ normalizedRequiredRoles : string [ ] ,
116
+ user : any ,
117
+ ) : boolean {
118
+ const generalUserRole = String ( UserRole . User ) . trim ( ) . toLowerCase ( ) ;
119
+
120
+ if ( user ?. isMachine || ! user ?. userId ) {
121
+ return false ;
122
+ }
123
+
124
+ if ( ! normalizedRequiredRoles . includes ( generalUserRole ) ) {
125
+ return false ;
126
+ }
127
+
128
+ const handler = context . getHandler ?.( ) ;
129
+ const controllerClass = context . getClass ?.( ) ;
130
+
131
+ const isSubmissionListHandler =
132
+ controllerClass ?. name === 'SubmissionController' &&
133
+ handler ?. name === 'listSubmissions' ;
134
+
135
+ if ( ! isSubmissionListHandler ) {
136
+ return false ;
137
+ }
138
+
139
+ const method = ( request ?. method || '' ) . toUpperCase ( ) ;
140
+ if ( method !== 'GET' ) {
141
+ return false ;
142
+ }
143
+
144
+ const challengeId = request ?. query ?. challengeId ;
145
+ if ( ! this . hasNonEmptyQueryParam ( challengeId ) ) {
146
+ return false ;
147
+ }
148
+
149
+ return true ;
150
+ }
151
+
152
+ private hasNonEmptyQueryParam ( value : unknown ) : boolean {
153
+ if ( typeof value === 'string' ) {
154
+ return value . trim ( ) . length > 0 ;
155
+ }
156
+ if ( Array . isArray ( value ) ) {
157
+ return value . some ( ( entry ) => this . hasNonEmptyQueryParam ( entry ) ) ;
158
+ }
159
+ return false ;
160
+ }
98
161
}
0 commit comments