@@ -30,13 +30,6 @@ import { APIStatsService as StatsServiceAPI } from "./stats";
30
30
import { APITeamsService as TeamsServiceAPI } from "./teams" ;
31
31
import { APIUserService as UserServiceAPI } from "./user" ;
32
32
import { WorkspaceServiceAPI } from "./workspace-service-api" ;
33
- import { IRateLimiterOptions , RateLimiterMemory , RateLimiterRedis , RateLimiterRes } from "rate-limiter-flexible" ;
34
- import { Redis } from "ioredis" ;
35
- import { RateLimited } from "./rate-limited" ;
36
- import { Config } from "../config" ;
37
- import { ApplicationError , ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error" ;
38
- import { UserService } from "../user/user-service" ;
39
- import { User } from "@gitpod/gitpod-protocol" ;
40
33
41
34
decorate ( injectable ( ) , PublicAPIConverter ) ;
42
35
@@ -53,9 +46,6 @@ export class API {
53
46
@inject ( HelloServiceAPI ) private readonly helloServiceApi : HelloServiceAPI ;
54
47
@inject ( SessionHandler ) private readonly sessionHandler : SessionHandler ;
55
48
@inject ( PublicAPIConverter ) private readonly apiConverter : PublicAPIConverter ;
56
- @inject ( Redis ) private readonly redis : Redis ;
57
- @inject ( Config ) private readonly config : Config ;
58
- @inject ( UserService ) private readonly userService : UserService ;
59
49
60
50
listenPrivate ( ) : http . Server {
61
51
const app = express ( ) ;
@@ -184,30 +174,9 @@ export class API {
184
174
185
175
const context = args [ 1 ] as HandlerContext ;
186
176
187
- const rateLimit = async ( subjectId : string ) => {
188
- const key = `${ grpc_service } /${ grpc_method } ` ;
189
- const options = self . config . rateLimits ?. [ key ] || RateLimited . getOptions ( target , prop ) ;
190
- try {
191
- await self . getRateLimitter ( options ) . consume ( `${ subjectId } _${ key } ` ) ;
192
- } catch ( e ) {
193
- if ( e instanceof RateLimiterRes ) {
194
- throw new ConnectError ( "rate limit exceeded" , Code . ResourceExhausted , {
195
- // http compatibility, can be respected by gRPC clients as well
196
- // instead of doing an ad-hoc retry, the client can wait for the given amount of seconds
197
- "Retry-After" : e . msBeforeNext / 1000 ,
198
- "X-RateLimit-Limit" : options . points ,
199
- "X-RateLimit-Remaining" : e . remainingPoints ,
200
- "X-RateLimit-Reset" : new Date ( Date . now ( ) + e . msBeforeNext ) ,
201
- } ) ;
202
- }
203
- throw e ;
204
- }
205
- } ;
206
-
207
177
const apply = async < T > ( ) : Promise < T > => {
208
- const subjectId = await self . verify ( context ) ;
209
- await rateLimit ( subjectId ) ;
210
- context . user = await self . ensureFgaMigration ( subjectId ) ;
178
+ const user = await self . verify ( context ) ;
179
+ context . user = user ;
211
180
212
181
return Reflect . apply ( target [ prop as any ] , target , args ) ;
213
182
} ;
@@ -242,49 +211,16 @@ export class API {
242
211
} ;
243
212
}
244
213
245
- private async verify ( context : HandlerContext ) : Promise < string > {
246
- const claims = await this . sessionHandler . verifyJWTCookie ( context . requestHeader . get ( "cookie" ) || "" ) ;
247
- const subjectId = claims ?. sub ;
248
- if ( ! subjectId ) {
214
+ private async verify ( context : HandlerContext ) {
215
+ const user = await this . sessionHandler . verify ( context . requestHeader . get ( "cookie" ) || "" ) ;
216
+ if ( ! user ) {
249
217
throw new ConnectError ( "unauthenticated" , Code . Unauthenticated ) ;
250
218
}
251
- return subjectId ;
252
- }
253
-
254
- private async ensureFgaMigration ( userId : string ) : Promise < User > {
255
- const fgaChecksEnabled = await isFgaChecksEnabled ( userId ) ;
219
+ const fgaChecksEnabled = await isFgaChecksEnabled ( user . id ) ;
256
220
if ( ! fgaChecksEnabled ) {
257
221
throw new ConnectError ( "unauthorized" , Code . PermissionDenied ) ;
258
222
}
259
- try {
260
- return await this . userService . findUserById ( userId , userId ) ;
261
- } catch ( e ) {
262
- if ( e instanceof ApplicationError && e . code === ErrorCodes . NOT_FOUND ) {
263
- throw new ConnectError ( "unauthorized" , Code . PermissionDenied ) ;
264
- }
265
- throw e ;
266
- }
267
- }
268
-
269
- private readonly rateLimiters = new Map < string , RateLimiterRedis > ( ) ;
270
- private getRateLimitter ( options : IRateLimiterOptions ) : RateLimiterRedis {
271
- const sortedKeys = Object . keys ( options ) . sort ( ) ;
272
- const sortedObject : { [ key : string ] : any } = { } ;
273
- for ( const key of sortedKeys ) {
274
- sortedObject [ key ] = options [ key as keyof IRateLimiterOptions ] ;
275
- }
276
- const key = JSON . stringify ( sortedObject ) ;
277
-
278
- let rateLimiter = this . rateLimiters . get ( key ) ;
279
- if ( ! rateLimiter ) {
280
- rateLimiter = new RateLimiterRedis ( {
281
- storeClient : this . redis ,
282
- ...options ,
283
- insuranceLimiter : new RateLimiterMemory ( options ) ,
284
- } ) ;
285
- this . rateLimiters . set ( key , rateLimiter ) ;
286
- }
287
- return rateLimiter ;
223
+ return user ;
288
224
}
289
225
290
226
static bindAPI ( bind : interfaces . Bind ) : void {
0 commit comments