@@ -76,6 +76,7 @@ import {
76
76
SSHPublicKeyValue ,
77
77
UserSSHPublicKeyValue ,
78
78
PrebuildEvent ,
79
+ RoleOrPermission ,
79
80
} from "@gitpod/gitpod-protocol" ;
80
81
import { BlockedRepository } from "@gitpod/gitpod-protocol/lib/blocked-repositories-protocol" ;
81
82
import {
@@ -154,6 +155,7 @@ import {
154
155
EnvVarWithValue ,
155
156
LinkedInProfile ,
156
157
ProjectEnvVar ,
158
+ UserFeatureSettings ,
157
159
WorkspaceTimeoutSetting ,
158
160
} from "@gitpod/gitpod-protocol/lib/protocol" ;
159
161
import { InstallationAdminSettings , TelemetryData } from "@gitpod/gitpod-protocol" ;
@@ -2891,19 +2893,46 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
2891
2893
throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2892
2894
}
2893
2895
2894
- adminGetBlockedRepositories (
2896
+ async adminGetBlockedRepositories (
2895
2897
ctx : TraceContext ,
2896
2898
req : AdminGetListRequest < BlockedRepository > ,
2897
2899
) : Promise < AdminGetListResult < BlockedRepository > > {
2898
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2900
+ traceAPIParams ( ctx , { req : censor ( req , "searchTerm" ) } ) ; // searchTerm may contain PII
2901
+
2902
+ await this . guardAdminAccess ( "adminGetBlockedRepositories" , { req } , Permission . ADMIN_USERS ) ;
2903
+
2904
+ try {
2905
+ const res = await this . blockedRepostoryDB . findAllBlockedRepositories (
2906
+ req . offset ,
2907
+ req . limit ,
2908
+ req . orderBy ,
2909
+ req . orderDir === "asc" ? "ASC" : "DESC" ,
2910
+ req . searchTerm ,
2911
+ ) ;
2912
+ return res ;
2913
+ } catch ( e ) {
2914
+ throw new ResponseError ( ErrorCodes . INTERNAL_SERVER_ERROR , e . toString ( ) ) ;
2915
+ }
2899
2916
}
2900
2917
2901
- adminCreateBlockedRepository ( ctx : TraceContext , urlRegexp : string , blockUser : boolean ) : Promise < BlockedRepository > {
2902
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2918
+ async adminCreateBlockedRepository (
2919
+ ctx : TraceContext ,
2920
+ urlRegexp : string ,
2921
+ blockUser : boolean ,
2922
+ ) : Promise < BlockedRepository > {
2923
+ traceAPIParams ( ctx , { urlRegexp, blockUser } ) ;
2924
+
2925
+ await this . guardAdminAccess ( "adminCreateBlockedRepository" , { urlRegexp, blockUser } , Permission . ADMIN_USERS ) ;
2926
+
2927
+ return await this . blockedRepostoryDB . createBlockedRepository ( urlRegexp , blockUser ) ;
2903
2928
}
2904
2929
2905
- adminDeleteBlockedRepository ( ctx : TraceContext , id : number ) : Promise < void > {
2906
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2930
+ async adminDeleteBlockedRepository ( ctx : TraceContext , id : number ) : Promise < void > {
2931
+ traceAPIParams ( ctx , { id } ) ;
2932
+
2933
+ await this . guardAdminAccess ( "adminDeleteBlockedRepository" , { id } , Permission . ADMIN_USERS ) ;
2934
+
2935
+ await this . blockedRepostoryDB . deleteBlockedRepository ( id ) ;
2907
2936
}
2908
2937
2909
2938
async adminGetUser ( ctx : TraceContext , id : string ) : Promise < User > {
@@ -2914,34 +2943,120 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
2914
2943
throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2915
2944
}
2916
2945
2917
- async adminDeleteUser ( ctx : TraceContext , _id : string ) : Promise < void > {
2918
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2946
+ async adminDeleteUser ( ctx : TraceContext , userId : string ) : Promise < void > {
2947
+ traceAPIParams ( ctx , { userId } ) ;
2948
+
2949
+ await this . guardAdminAccess ( "adminDeleteUser" , { id : userId } , Permission . ADMIN_USERS ) ;
2950
+
2951
+ try {
2952
+ await this . userDeletionService . deleteUser ( userId ) ;
2953
+ } catch ( e ) {
2954
+ throw new ResponseError ( ErrorCodes . INTERNAL_SERVER_ERROR , e . toString ( ) ) ;
2955
+ }
2919
2956
}
2920
2957
2921
- async adminVerifyUser ( ctx : TraceContext , _id : string ) : Promise < User > {
2922
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2958
+ async adminVerifyUser ( ctx : TraceContext , userId : string ) : Promise < User > {
2959
+ await this . guardAdminAccess ( "adminVerifyUser" , { id : userId } , Permission . ADMIN_USERS ) ;
2960
+ try {
2961
+ const user = await this . userDB . findUserById ( userId ) ;
2962
+ if ( ! user ) {
2963
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , `No user with id ${ userId } found.` ) ;
2964
+ }
2965
+ this . verificationService . markVerified ( user ) ;
2966
+ await this . userDB . updateUserPartial ( user ) ;
2967
+ return user ;
2968
+ } catch ( e ) {
2969
+ throw new ResponseError ( ErrorCodes . INTERNAL_SERVER_ERROR , e . toString ( ) ) ;
2970
+ }
2923
2971
}
2924
2972
2925
2973
async adminModifyRoleOrPermission ( ctx : TraceContext , req : AdminModifyRoleOrPermissionRequest ) : Promise < User > {
2926
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2974
+ traceAPIParams ( ctx , { req } ) ;
2975
+
2976
+ await this . guardAdminAccess ( "adminModifyRoleOrPermission" , { req } , Permission . ADMIN_USERS ) ;
2977
+
2978
+ const target = await this . userDB . findUserById ( req . id ) ;
2979
+ if ( ! target ) {
2980
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , "not found" ) ;
2981
+ }
2982
+
2983
+ const rolesOrPermissions = new Set ( ( target . rolesOrPermissions || [ ] ) as string [ ] ) ;
2984
+ req . rpp . forEach ( ( e ) => {
2985
+ if ( e . add ) {
2986
+ rolesOrPermissions . add ( e . r as string ) ;
2987
+ } else {
2988
+ rolesOrPermissions . delete ( e . r as string ) ;
2989
+ }
2990
+ } ) ;
2991
+ target . rolesOrPermissions = Array . from ( rolesOrPermissions . values ( ) ) as RoleOrPermission [ ] ;
2992
+
2993
+ await this . userDB . storeUser ( target ) ;
2994
+ // For some reason, neither returning the result of `this.userDB.storeUser(target)` nor returning `target` work.
2995
+ // The response never arrives the caller.
2996
+ // Returning the following works at the cost of an additional DB query:
2997
+ return this . censorUser ( ( await this . userDB . findUserById ( req . id ) ) ! ) ;
2927
2998
}
2928
2999
2929
3000
async adminModifyPermanentWorkspaceFeatureFlag (
2930
3001
ctx : TraceContext ,
2931
3002
req : AdminModifyPermanentWorkspaceFeatureFlagRequest ,
2932
3003
) : Promise < User > {
2933
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3004
+ traceAPIParams ( ctx , { req } ) ;
3005
+
3006
+ await this . guardAdminAccess ( "adminModifyPermanentWorkspaceFeatureFlag" , { req } , Permission . ADMIN_USERS ) ;
3007
+ const target = await this . userDB . findUserById ( req . id ) ;
3008
+ if ( ! target ) {
3009
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , "not found" ) ;
3010
+ }
3011
+
3012
+ const featureSettings : UserFeatureSettings = target . featureFlags || { } ;
3013
+ const featureFlags = new Set ( featureSettings . permanentWSFeatureFlags || [ ] ) ;
3014
+
3015
+ req . changes . forEach ( ( e ) => {
3016
+ if ( e . add ) {
3017
+ featureFlags . add ( e . featureFlag ) ;
3018
+ } else {
3019
+ featureFlags . delete ( e . featureFlag ) ;
3020
+ }
3021
+ } ) ;
3022
+ featureSettings . permanentWSFeatureFlags = Array . from ( featureFlags ) ;
3023
+ target . featureFlags = featureSettings ;
3024
+
3025
+ await this . userDB . storeUser ( target ) ;
3026
+ // For some reason, returning the result of `this.userDB.storeUser(target)` does not work. The response never arrives the caller.
3027
+ // Returning `target` instead (which should be equivalent).
3028
+ return this . censorUser ( target ) ;
2934
3029
}
2935
3030
2936
3031
async adminGetWorkspaces (
2937
3032
ctx : TraceContext ,
2938
3033
req : AdminGetWorkspacesRequest ,
2939
3034
) : Promise < AdminGetListResult < WorkspaceAndInstance > > {
2940
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3035
+ traceAPIParams ( ctx , { req } ) ;
3036
+
3037
+ await this . guardAdminAccess ( "adminGetWorkspaces" , { req } , Permission . ADMIN_WORKSPACES ) ;
3038
+
3039
+ return await this . workspaceDb
3040
+ . trace ( ctx )
3041
+ . findAllWorkspaceAndInstances (
3042
+ req . offset ,
3043
+ req . limit ,
3044
+ req . orderBy ,
3045
+ req . orderDir === "asc" ? "ASC" : "DESC" ,
3046
+ req ,
3047
+ ) ;
2941
3048
}
2942
3049
2943
- async adminGetWorkspace ( ctx : TraceContext , id : string ) : Promise < WorkspaceAndInstance > {
2944
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3050
+ async adminGetWorkspace ( ctx : TraceContext , workspaceId : string ) : Promise < WorkspaceAndInstance > {
3051
+ traceAPIParams ( ctx , { workspaceId } ) ;
3052
+
3053
+ await this . guardAdminAccess ( "adminGetWorkspace" , { id : workspaceId } , Permission . ADMIN_WORKSPACES ) ;
3054
+
3055
+ const result = await this . workspaceDb . trace ( ctx ) . findWorkspaceAndInstance ( workspaceId ) ;
3056
+ if ( ! result ) {
3057
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , "not found" ) ;
3058
+ }
3059
+ return result ;
2945
3060
}
2946
3061
2947
3062
async adminGetWorkspaceInstances ( ctx : TraceContext , workspaceId : string ) : Promise < WorkspaceInstance [ ] > {
@@ -2952,27 +3067,74 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
2952
3067
throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
2953
3068
}
2954
3069
2955
- async adminRestoreSoftDeletedWorkspace ( ctx : TraceContext , id : string ) : Promise < void > {
2956
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3070
+ async adminRestoreSoftDeletedWorkspace ( ctx : TraceContext , workspaceId : string ) : Promise < void > {
3071
+ traceAPIParams ( ctx , { workspaceId } ) ;
3072
+
3073
+ await this . guardAdminAccess (
3074
+ "adminRestoreSoftDeletedWorkspace" ,
3075
+ { id : workspaceId } ,
3076
+ Permission . ADMIN_WORKSPACES ,
3077
+ ) ;
3078
+
3079
+ await this . workspaceDb . trace ( ctx ) . transaction ( async ( db ) => {
3080
+ const ws = await db . findById ( workspaceId ) ;
3081
+ if ( ! ws ) {
3082
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , `No workspace with id '${ workspaceId } ' found.` ) ;
3083
+ }
3084
+ if ( ! ws . softDeleted ) {
3085
+ return ;
3086
+ }
3087
+ if ( ! ! ws . contentDeletedTime ) {
3088
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , "The workspace content was already garbage-collected." ) ;
3089
+ }
3090
+ // @ts -ignore
3091
+ ws . softDeleted = null ;
3092
+ ws . softDeletedTime = "" ;
3093
+ ws . pinned = true ;
3094
+ await db . store ( ws ) ;
3095
+ } ) ;
2957
3096
}
2958
3097
2959
3098
async adminGetProjectsBySearchTerm (
2960
3099
ctx : TraceContext ,
2961
3100
req : AdminGetListRequest < Project > ,
2962
3101
) : Promise < AdminGetListResult < Project > > {
2963
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3102
+ await this . guardAdminAccess ( "adminGetProjectsBySearchTerm" , { req } , Permission . ADMIN_PROJECTS ) ;
3103
+ return await this . projectDB . findProjectsBySearchTerm (
3104
+ req . offset ,
3105
+ req . limit ,
3106
+ req . orderBy ,
3107
+ req . orderDir === "asc" ? "ASC" : "DESC" ,
3108
+ req . searchTerm as string ,
3109
+ ) ;
2964
3110
}
2965
3111
2966
3112
async adminGetProjectById ( ctx : TraceContext , id : string ) : Promise < Project | undefined > {
2967
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3113
+ await this . guardAdminAccess ( "adminGetProjectById" , { id } , Permission . ADMIN_PROJECTS ) ;
3114
+ return await this . projectDB . findProjectById ( id ) ;
2968
3115
}
2969
3116
2970
3117
async adminGetTeams ( ctx : TraceContext , req : AdminGetListRequest < Team > ) : Promise < AdminGetListResult < Team > > {
2971
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3118
+ await this . guardAdminAccess ( "adminGetTeams" , { req } , Permission . ADMIN_WORKSPACES ) ;
3119
+
3120
+ return await this . teamDB . findTeams (
3121
+ req . offset ,
3122
+ req . limit ,
3123
+ req . orderBy ,
3124
+ req . orderDir === "asc" ? "ASC" : "DESC" ,
3125
+ req . searchTerm as string ,
3126
+ ) ;
2972
3127
}
2973
3128
2974
3129
async adminGetTeamMembers ( ctx : TraceContext , teamId : string ) : Promise < TeamMemberInfo [ ] > {
2975
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3130
+ await this . guardAdminAccess ( "adminGetTeamMembers" , { teamId } , Permission . ADMIN_WORKSPACES ) ;
3131
+
3132
+ const team = await this . teamDB . findTeamById ( teamId ) ;
3133
+ if ( ! team ) {
3134
+ throw new ResponseError ( ErrorCodes . NOT_FOUND , "Team not found" ) ;
3135
+ }
3136
+ const members = await this . teamDB . findMembersByTeam ( team . id ) ;
3137
+ return members ;
2976
3138
}
2977
3139
2978
3140
async adminSetTeamMemberRole (
@@ -2981,11 +3143,13 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
2981
3143
userId : string ,
2982
3144
role : TeamMemberRole ,
2983
3145
) : Promise < void > {
2984
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3146
+ await this . guardAdminAccess ( "adminSetTeamMemberRole" , { teamId, userId, role } , Permission . ADMIN_WORKSPACES ) ;
3147
+ return this . teamDB . setTeamMemberRole ( userId , teamId , role ) ;
2985
3148
}
2986
3149
2987
3150
async adminGetTeamById ( ctx : TraceContext , id : string ) : Promise < Team | undefined > {
2988
- throw new ResponseError ( ErrorCodes . EE_FEATURE , `Admin support is implemented in Gitpod's Enterprise Edition` ) ;
3151
+ await this . guardAdminAccess ( "adminGetTeamById" , { id } , Permission . ADMIN_WORKSPACES ) ;
3152
+ return await this . teamDB . findTeamById ( id ) ;
2989
3153
}
2990
3154
2991
3155
async adminFindPrebuilds ( ctx : TraceContext , params : FindPrebuildsParams ) : Promise < PrebuildWithStatus [ ] > {
0 commit comments