55 "fmt"
66 "io"
77 "path"
8- "slices"
98 "strings"
109 "time"
1110
@@ -86,6 +85,26 @@ func (bri *bucketReqImpl) displayPrefix(ctx context.Context) (string, error) {
8685 return bri .targetCfg .Bucket .GetRootPrefix () + seg , nil
8786}
8887
88+ // respondToUserIsolationError maps an error from generateStartKey or
89+ // displayPrefix to the right HTTP response on resHan. Returns true when
90+ // it wrote a response (caller should return early), false otherwise.
91+ // Centralising this keeps the four request-handling entry points
92+ // (Get/Put/Delete/listing) in lockstep on what errUserIsolationForbidden
93+ // means at the HTTP layer.
94+ func (bri * bucketReqImpl ) respondToUserIsolationError (resHan responsehandler.ResponseHandler , err error ) bool {
95+ if err == nil {
96+ return false
97+ }
98+
99+ if errors .Is (err , errUserIsolationForbidden ) {
100+ resHan .ForbiddenError (bri .LoadFileContent , err )
101+ } else {
102+ resHan .InternalServerError (bri .LoadFileContent , err )
103+ }
104+
105+ return true
106+ }
107+
89108func (bri * bucketReqImpl ) manageKeyRewrite (ctx context.Context , key string ) (string , error ) {
90109 // Check if key rewrite list exists
91110 if bri .targetCfg .KeyRewriteList != nil {
@@ -201,16 +220,7 @@ func (bri *bucketReqImpl) internalGetOrHead(ctx context.Context, input *GetInput
201220
202221 // Generate start key
203222 key , err := bri .generateStartKey (ctx , input .RequestPath )
204- // Check error
205- if err != nil {
206- if errors .Is (err , errUserIsolationForbidden ) {
207- resHan .ForbiddenError (bri .LoadFileContent , err )
208-
209- return
210- }
211-
212- resHan .InternalServerError (bri .LoadFileContent , err )
213-
223+ if bri .respondToUserIsolationError (resHan , err ) {
214224 return
215225 }
216226 // Manage key rewrite
@@ -429,15 +439,7 @@ func (bri *bucketReqImpl) manageGetFolder(ctx context.Context, key string, input
429439 // Use displayPrefix so the user-facing Path hides the injected identifier
430440 // for non-admin users under userIsolation.
431441 displayPfx , err := bri .displayPrefix (ctx )
432- if err != nil {
433- if errors .Is (err , errUserIsolationForbidden ) {
434- resHan .ForbiddenError (bri .LoadFileContent , err )
435-
436- return
437- }
438-
439- resHan .InternalServerError (bri .LoadFileContent , err )
440-
442+ if bri .respondToUserIsolationError (resHan , err ) {
441443 return
442444 }
443445
@@ -457,16 +459,7 @@ func (bri *bucketReqImpl) Put(ctx context.Context, inp *PutInput) {
457459
458460 // Generate start key
459461 key , err := bri .generateStartKey (ctx , inp .RequestPath )
460- // Check error
461- if err != nil {
462- if errors .Is (err , errUserIsolationForbidden ) {
463- resHan .ForbiddenError (bri .LoadFileContent , err )
464-
465- return
466- }
467-
468- resHan .InternalServerError (bri .LoadFileContent , err )
469-
462+ if bri .respondToUserIsolationError (resHan , err ) {
470463 return
471464 }
472465 // Add / at the end if not present
@@ -730,16 +723,7 @@ func (bri *bucketReqImpl) Delete(ctx context.Context, requestPath string) {
730723
731724 // Generate start key
732725 key , err := bri .generateStartKey (ctx , requestPath )
733- // Check error
734- if err != nil {
735- if errors .Is (err , errUserIsolationForbidden ) {
736- resHan .ForbiddenError (bri .LoadFileContent , err )
737-
738- return
739- }
740-
741- resHan .InternalServerError (bri .LoadFileContent , err )
742-
726+ if bri .respondToUserIsolationError (resHan , err ) {
743727 return
744728 }
745729 // Manage key rewrite
@@ -791,23 +775,35 @@ func (bri *bucketReqImpl) Delete(ctx context.Context, requestPath string) {
791775 )
792776}
793777
778+ // userIsolationCfg returns the GET-action config that owns the userIsolation
779+ // fields, or nil when the chain is incomplete. Centralising the nil walk
780+ // keeps the two consumers below as one-liners.
781+ func (bri * bucketReqImpl ) userIsolationCfg () * config.GetActionConfigConfig {
782+ if bri .targetCfg .Actions == nil || bri .targetCfg .Actions .GET == nil {
783+ return nil
784+ }
785+
786+ return bri .targetCfg .Actions .GET .Config
787+ }
788+
794789// isUserIsolationEnabled checks if userIsolation is configured on the GET action.
795790func (bri * bucketReqImpl ) isUserIsolationEnabled () bool {
796- return bri . targetCfg . Actions != nil && bri .targetCfg . Actions . GET != nil &&
797- bri . targetCfg . Actions . GET . Config != nil &&
798- bri . targetCfg . Actions . GET . Config .UserIsolation
791+ cfg := bri .userIsolationCfg ()
792+
793+ return cfg != nil && cfg .UserIsolation
799794}
800795
801796// isUserIsolationAdmin checks if the given user identifier is in the admin
802797// list. The identifier matches what GenericUser.GetIdentifier() returns
803798// (username for basic auth, preferred_username or email for OIDC, etc.).
799+ // Lookup is O(1) via the precomputed admin set populated at config validation.
804800func (bri * bucketReqImpl ) isUserIsolationAdmin (identifier string ) bool {
805- if bri . targetCfg . Actions == nil || bri .targetCfg . Actions . GET == nil ||
806- bri . targetCfg . Actions . GET . Config == nil {
801+ cfg := bri .userIsolationCfg ()
802+ if cfg == nil {
807803 return false
808804 }
809805
810- return slices . Contains ( bri . targetCfg . Actions . GET . Config . UserIsolationAdmins , identifier )
806+ return cfg . IsUserIsolationAdmin ( identifier )
811807}
812808
813809func transformS3Entries (
0 commit comments