@@ -11,7 +11,7 @@ import * as util from "util";
1111import express from "express" ;
1212import { inject , injectable } from "inversify" ;
1313import { BearerAuth } from "../auth/bearer-authenticator" ;
14- import { isWithFunctionAccessGuard } from "../auth/function-access" ;
14+ import { WithFunctionAccessGuard } from "../auth/function-access" ;
1515import { CodeSyncResourceDB , ALL_SERVER_RESOURCES , ServerResource , SyncResource } from "@gitpod/gitpod-db/lib" ;
1616import {
1717 DeleteRequest ,
@@ -26,6 +26,8 @@ import { v4 as uuidv4 } from "uuid";
2626import { accessCodeSyncStorage , UserRateLimiter } from "../auth/rate-limiter" ;
2727import { Config } from "../config" ;
2828import { CachingBlobServiceClientProvider } from "../util/content-service-sugar" ;
29+ import { Authorizer } from "../authorization/authorizer" ;
30+ import { FGAFunctionAccessGuard } from "../auth/resource-access" ;
2931
3032// By default: 5 kind of resources * 20 revs * 1Mb = 100Mb max in the content service for user data.
3133const defaultRevLimit = 20 ;
@@ -71,17 +73,22 @@ function toObjectName(resource: ServerResource, rev: string, collection: string
7173
7274@injectable ( )
7375export class CodeSyncService {
74- @inject ( Config )
75- private readonly config : Config ;
76+ constructor (
77+ @inject ( Config )
78+ private readonly config : Config ,
7679
77- @inject ( BearerAuth )
78- private readonly auth : BearerAuth ;
80+ @inject ( BearerAuth )
81+ private readonly auth : BearerAuth ,
7982
80- @inject ( CachingBlobServiceClientProvider )
81- private readonly blobsProvider : CachingBlobServiceClientProvider ;
83+ @inject ( CachingBlobServiceClientProvider )
84+ private readonly blobsProvider : CachingBlobServiceClientProvider ,
8285
83- @inject ( CodeSyncResourceDB )
84- private readonly db : CodeSyncResourceDB ;
86+ @inject ( CodeSyncResourceDB )
87+ private readonly db : CodeSyncResourceDB ,
88+
89+ @inject ( Authorizer )
90+ private readonly authorizer : Authorizer ,
91+ ) { }
8592
8693 get apiRouter ( ) : express . Router {
8794 const config = this . config . codeSync ;
@@ -91,16 +98,16 @@ export class CodeSyncService {
9198 res . setHeader ( "x-operation-id" , uuidv4 ( ) ) ;
9299 return next ( ) ;
93100 } ) ;
94- router . use ( this . auth . restHandler ) ;
101+ router . use ( this . auth . restHandler ) ; // expects Bearer token and authenticates req.user, throws otherwise
95102 router . use ( async ( req , res , next ) => {
96103 if ( ! User . is ( req . user ) ) {
97104 res . sendStatus ( 400 ) ;
98105 return ;
99106 }
100107
101- const id = req . user . id ;
108+ const userId = req . user . id ;
102109 try {
103- await UserRateLimiter . instance ( this . config . rateLimiter ) . consume ( id , accessCodeSyncStorage ) ;
110+ await UserRateLimiter . instance ( this . config . rateLimiter ) . consume ( userId , accessCodeSyncStorage ) ;
104111 } catch ( e ) {
105112 if ( e instanceof Error ) {
106113 throw e ;
@@ -110,20 +117,26 @@ export class CodeSyncService {
110117 return ;
111118 }
112119
113- if ( ! isWithFunctionAccessGuard ( req ) || ! req . functionGuard ?. canAccess ( accessCodeSyncStorage ) ) {
120+ const functionGuard = ( req . user as WithFunctionAccessGuard ) . functionGuard ;
121+ if ( ! ! functionGuard ) {
122+ // If we authorize with scopes, there is a FunctionGuard
123+ const guard = new FGAFunctionAccessGuard ( userId , functionGuard ) ;
124+ if ( ! ( await guard . canAccess ( accessCodeSyncStorage ) ) ) {
125+ res . sendStatus ( 403 ) ;
126+ return ;
127+ }
128+ }
129+
130+ if ( ! ( await this . authorizer . hasPermissionOnUser ( userId , "code_sync" , userId ) ) ) {
114131 res . sendStatus ( 403 ) ;
115132 return ;
116133 }
134+
117135 return next ( ) ;
118136 } ) ;
119137
120138 router . get ( "/v1/manifest" , async ( req , res ) => {
121- if ( ! User . is ( req . user ) ) {
122- res . sendStatus ( 400 ) ;
123- return ;
124- }
125-
126- const manifest = await this . db . getManifest ( req . user . id ) ;
139+ const manifest = await this . db . getManifest ( req . user ! . id ) ;
127140 if ( ! manifest ) {
128141 res . sendStatus ( 204 ) ;
129142 return ;
@@ -149,13 +162,8 @@ export class CodeSyncService {
149162 router . delete ( "/v1/collection/:collection/resource/:resource/:ref?" , this . deleteResource . bind ( this ) ) ;
150163 router . delete ( "/v1/resource/:resource/:ref?" , this . deleteResource . bind ( this ) ) ;
151164 router . delete ( "/v1/resource" , async ( req , res ) => {
152- if ( ! User . is ( req . user ) ) {
153- res . sendStatus ( 400 ) ;
154- return ;
155- }
156-
157165 // This endpoint is used to delete settings-sync data only
158- const userId = req . user . id ;
166+ const userId = req . user ! . id ;
159167 await this . db . deleteSettingsSyncResources ( userId , async ( ) => {
160168 const request = new DeleteRequest ( ) ;
161169 request . setOwnerId ( userId ) ;
@@ -173,36 +181,21 @@ export class CodeSyncService {
173181 } ) ;
174182
175183 router . get ( "/v1/collection" , async ( req , res ) => {
176- if ( ! User . is ( req . user ) ) {
177- res . sendStatus ( 400 ) ;
178- return ;
179- }
180-
181- const collections = await this . db . getCollections ( req . user . id ) ;
184+ const collections = await this . db . getCollections ( req . user ! . id ) ;
182185
183186 res . json ( collections ) ;
184187 return ;
185188 } ) ;
186189 router . post ( "/v1/collection" , async ( req , res ) => {
187- if ( ! User . is ( req . user ) ) {
188- res . sendStatus ( 400 ) ;
189- return ;
190- }
191-
192- const collection = await this . db . createCollection ( req . user . id ) ;
190+ const collection = await this . db . createCollection ( req . user ! . id ) ;
193191
194192 res . type ( "text/plain" ) ;
195193 res . send ( collection ) ;
196194 return ;
197195 } ) ;
198196 router . delete ( "/v1/collection/:collection?" , async ( req , res ) => {
199- if ( ! User . is ( req . user ) ) {
200- res . sendStatus ( 400 ) ;
201- return ;
202- }
203-
204197 const { collection } = req . params ;
205- await this . deleteCollection ( req . user . id , collection ) ;
198+ await this . deleteCollection ( req . user ! . id , collection ) ;
206199
207200 res . sendStatus ( 200 ) ;
208201 } ) ;
@@ -211,11 +204,6 @@ export class CodeSyncService {
211204 }
212205
213206 private async getResources ( req : express . Request < { resource : string ; collection ?: string } > , res : express . Response ) {
214- if ( ! User . is ( req . user ) ) {
215- res . sendStatus ( 400 ) ;
216- return ;
217- }
218-
219207 const { resource, collection } = req . params ;
220208 const resourceKey = ALL_SERVER_RESOURCES . find ( ( key ) => key === resource ) ;
221209 if ( ! resourceKey ) {
@@ -224,14 +212,14 @@ export class CodeSyncService {
224212 }
225213
226214 if ( collection ) {
227- const valid = await this . db . isCollection ( req . user . id , collection ) ;
215+ const valid = await this . db . isCollection ( req . user ! . id , collection ) ;
228216 if ( ! valid ) {
229217 res . sendStatus ( 405 ) ;
230218 return ;
231219 }
232220 }
233221
234- const revs = await this . db . getResources ( req . user . id , resourceKey , collection ) ;
222+ const revs = await this . db . getResources ( req . user ! . id , resourceKey , collection ) ;
235223 if ( ! revs . length ) {
236224 res . sendStatus ( 204 ) ;
237225 return ;
@@ -249,11 +237,6 @@ export class CodeSyncService {
249237 req : express . Request < { resource : string ; ref : string ; collection ?: string } > ,
250238 res : express . Response ,
251239 ) {
252- if ( ! User . is ( req . user ) ) {
253- res . sendStatus ( 400 ) ;
254- return ;
255- }
256-
257240 const { resource, ref, collection } = req . params ;
258241 const resourceKey = ALL_SERVER_RESOURCES . find ( ( key ) => key === resource ) ;
259242 if ( ! resourceKey ) {
@@ -262,14 +245,14 @@ export class CodeSyncService {
262245 }
263246
264247 if ( collection ) {
265- const valid = await this . db . isCollection ( req . user . id , collection ) ;
248+ const valid = await this . db . isCollection ( req . user ! . id , collection ) ;
266249 if ( ! valid ) {
267250 res . sendStatus ( 405 ) ;
268251 return ;
269252 }
270253 }
271254
272- const resourceRev = ( await this . db . getResource ( req . user . id , resourceKey , ref , collection ) ) ?. rev ;
255+ const resourceRev = ( await this . db . getResource ( req . user ! . id , resourceKey , ref , collection ) ) ?. rev ;
273256 if ( ! resourceRev ) {
274257 res . setHeader ( "etag" , "0" ) ;
275258 res . sendStatus ( 204 ) ;
@@ -283,7 +266,7 @@ export class CodeSyncService {
283266 let content : string ;
284267 const contentType = req . headers [ "content-type" ] || "*/*" ;
285268 const request = new DownloadUrlRequest ( ) ;
286- request . setOwnerId ( req . user . id ) ;
269+ request . setOwnerId ( req . user ! . id ) ;
287270 request . setName ( toObjectName ( resourceKey , resourceRev , collection ) ) ;
288271 request . setContentType ( contentType ) ;
289272 try {
@@ -317,11 +300,6 @@ export class CodeSyncService {
317300 }
318301
319302 private async postResource ( req : express . Request < { resource : string ; collection ?: string } > , res : express . Response ) {
320- if ( ! User . is ( req . user ) ) {
321- res . sendStatus ( 400 ) ;
322- return ;
323- }
324-
325303 const { resource, collection } = req . params ;
326304 const resourceKey = ALL_SERVER_RESOURCES . find ( ( key ) => key === resource ) ;
327305 if ( ! resourceKey ) {
@@ -330,7 +308,7 @@ export class CodeSyncService {
330308 }
331309
332310 if ( collection ) {
333- const valid = await this . db . isCollection ( req . user . id , collection ) ;
311+ const valid = await this . db . isCollection ( req . user ! . id , collection ) ;
334312 if ( ! valid ) {
335313 res . sendStatus ( 405 ) ;
336314 return ;
@@ -346,7 +324,7 @@ export class CodeSyncService {
346324 this . config . codeSync ?. revLimit ||
347325 defaultRevLimit ;
348326 const isEditSessionsResource = resourceKey === "editSessions" ;
349- const userId = req . user . id ;
327+ const userId = req . user ! . id ;
350328 const contentType = req . headers [ "content-type" ] || "*/*" ;
351329 const newRev = await this . db . insert (
352330 userId ,
@@ -403,11 +381,6 @@ export class CodeSyncService {
403381 req : express . Request < { resource : string ; ref ?: string ; collection ?: string } > ,
404382 res : express . Response ,
405383 ) {
406- if ( ! User . is ( req . user ) ) {
407- res . sendStatus ( 400 ) ;
408- return ;
409- }
410-
411384 // This endpoint is used to delete edit sessions data for now
412385
413386 const { resource, ref, collection } = req . params ;
@@ -418,14 +391,14 @@ export class CodeSyncService {
418391 }
419392
420393 if ( collection ) {
421- const valid = await this . db . isCollection ( req . user . id , collection ) ;
394+ const valid = await this . db . isCollection ( req . user ! . id , collection ) ;
422395 if ( ! valid ) {
423396 res . sendStatus ( 405 ) ;
424397 return ;
425398 }
426399 }
427400
428- await this . doDeleteResource ( req . user . id , resourceKey , ref , collection ) ;
401+ await this . doDeleteResource ( req . user ! . id , resourceKey , ref , collection ) ;
429402 res . sendStatus ( 200 ) ;
430403 return ;
431404 }
0 commit comments