From 098febf8bbc04fdaeee4d4ddcc8dba8044a5dec5 Mon Sep 17 00:00:00 2001 From: kyokugirl Date: Sat, 7 Dec 2024 00:45:15 +0900 Subject: [PATCH] fix: prevent enumeration of private repo --- pkg/ssh/cmd/branch.go | 12 +++++------- pkg/ssh/cmd/cmd.go | 12 +++++++++++- pkg/ssh/cmd/collab.go | 6 +++--- pkg/ssh/cmd/delete.go | 2 +- pkg/ssh/cmd/description.go | 13 +++++-------- pkg/ssh/cmd/hidden.go | 13 +++++-------- pkg/ssh/cmd/private.go | 11 ++++------- pkg/ssh/cmd/project_name.go | 13 +++++-------- pkg/ssh/cmd/rename.go | 2 +- pkg/ssh/cmd/tag.go | 2 +- testscript/testdata/repo-perms.txtar | 28 ++++++++++++++-------------- 11 files changed, 55 insertions(+), 59 deletions(-) diff --git a/pkg/ssh/cmd/branch.go b/pkg/ssh/cmd/branch.go index daa0efaa0..85474606e 100644 --- a/pkg/ssh/cmd/branch.go +++ b/pkg/ssh/cmd/branch.go @@ -61,18 +61,16 @@ func branchListCommand() *cobra.Command { func branchDefaultCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "default REPOSITORY [BRANCH]", - Short: "Set or get the default branch", - Args: cobra.RangeArgs(1, 2), + Use: "default REPOSITORY [BRANCH]", + Short: "Set or get the default branch", + Args: cobra.RangeArgs(1, 2), + PersistentPreRunE: checkIfReadable, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) rn := strings.TrimSuffix(args[0], ".git") switch len(args) { case 1: - if err := checkIfReadable(cmd, args); err != nil { - return err - } rr, err := be.Repository(ctx, rn) if err != nil { return err @@ -149,7 +147,7 @@ func branchDeleteCommand() *cobra.Command { Aliases: []string{"remove", "rm", "del"}, Short: "Delete a branch", Args: cobra.ExactArgs(2), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) diff --git a/pkg/ssh/cmd/cmd.go b/pkg/ssh/cmd/cmd.go index 2d0b00c25..18624eb33 100644 --- a/pkg/ssh/cmd/cmd.go +++ b/pkg/ssh/cmd/cmd.go @@ -121,7 +121,7 @@ func checkIfReadable(cmd *cobra.Command, args []string) error { user := proto.UserFromContext(ctx) auth := be.AccessLevelForUser(cmd.Context(), rn, user) if auth < access.ReadOnlyAccess { - return proto.ErrUnauthorized + return proto.ErrRepoNotFound } return nil } @@ -185,3 +185,13 @@ func checkIfCollab(cmd *cobra.Command, args []string) error { } return nil } + +func checkIfReadableAndCollab(cmd *cobra.Command, args []string) error { + if err := checkIfReadable(cmd, args); err != nil { + return err + } + if err := checkIfCollab(cmd, args); err != nil { + return err + } + return nil +} diff --git a/pkg/ssh/cmd/collab.go b/pkg/ssh/cmd/collab.go index bc4e22d81..df1e059f5 100644 --- a/pkg/ssh/cmd/collab.go +++ b/pkg/ssh/cmd/collab.go @@ -28,7 +28,7 @@ func collabAddCommand() *cobra.Command { Short: "Add a collaborator to a repo", Long: "Add a collaborator to a repo. LEVEL can be one of: no-access, read-only, read-write, or admin-access. Defaults to read-write.", Args: cobra.RangeArgs(2, 3), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) @@ -54,7 +54,7 @@ func collabRemoveCommand() *cobra.Command { Use: "remove REPOSITORY USERNAME", Args: cobra.ExactArgs(2), Short: "Remove a collaborator from a repo", - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) @@ -73,7 +73,7 @@ func collabListCommand() *cobra.Command { Use: "list REPOSITORY", Short: "List collaborators for a repo", Args: cobra.ExactArgs(1), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) diff --git a/pkg/ssh/cmd/delete.go b/pkg/ssh/cmd/delete.go index a1c25cb29..09fe3de6b 100644 --- a/pkg/ssh/cmd/delete.go +++ b/pkg/ssh/cmd/delete.go @@ -11,7 +11,7 @@ func deleteCommand() *cobra.Command { Aliases: []string{"del", "remove", "rm"}, Short: "Delete a repository", Args: cobra.ExactArgs(1), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) diff --git a/pkg/ssh/cmd/description.go b/pkg/ssh/cmd/description.go index 9ca799891..3e11c61f4 100644 --- a/pkg/ssh/cmd/description.go +++ b/pkg/ssh/cmd/description.go @@ -9,20 +9,17 @@ import ( func descriptionCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "description REPOSITORY [DESCRIPTION]", - Aliases: []string{"desc"}, - Short: "Set or get the description for a repository", - Args: cobra.MinimumNArgs(1), + Use: "description REPOSITORY [DESCRIPTION]", + Aliases: []string{"desc"}, + Short: "Set or get the description for a repository", + Args: cobra.MinimumNArgs(1), + PersistentPreRunE: checkIfReadable, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) rn := strings.TrimSuffix(args[0], ".git") switch len(args) { case 1: - if err := checkIfReadable(cmd, args); err != nil { - return err - } - desc, err := be.Description(ctx, rn) if err != nil { return err diff --git a/pkg/ssh/cmd/hidden.go b/pkg/ssh/cmd/hidden.go index 79441b4a7..82f544307 100644 --- a/pkg/ssh/cmd/hidden.go +++ b/pkg/ssh/cmd/hidden.go @@ -7,20 +7,17 @@ import ( func hiddenCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "hidden REPOSITORY [TRUE|FALSE]", - Short: "Hide or unhide a repository", - Aliases: []string{"hide"}, - Args: cobra.MinimumNArgs(1), + Use: "hidden REPOSITORY [TRUE|FALSE]", + Short: "Hide or unhide a repository", + Aliases: []string{"hide"}, + Args: cobra.MinimumNArgs(1), + PersistentPreRunE: checkIfReadable, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) repo := args[0] switch len(args) { case 1: - if err := checkIfReadable(cmd, args); err != nil { - return err - } - hidden, err := be.IsHidden(ctx, repo) if err != nil { return err diff --git a/pkg/ssh/cmd/private.go b/pkg/ssh/cmd/private.go index 11340a6f0..9c91dbcda 100644 --- a/pkg/ssh/cmd/private.go +++ b/pkg/ssh/cmd/private.go @@ -10,9 +10,10 @@ import ( func privateCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "private REPOSITORY [true|false]", - Short: "Set or get a repository private property", - Args: cobra.RangeArgs(1, 2), + Use: "private REPOSITORY [true|false]", + Short: "Set or get a repository private property", + Args: cobra.RangeArgs(1, 2), + PersistentPreRunE: checkIfReadable, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) @@ -20,10 +21,6 @@ func privateCommand() *cobra.Command { switch len(args) { case 1: - if err := checkIfReadable(cmd, args); err != nil { - return err - } - isPrivate, err := be.IsPrivate(ctx, rn) if err != nil { return err diff --git a/pkg/ssh/cmd/project_name.go b/pkg/ssh/cmd/project_name.go index 469a2e16d..d24931f5d 100644 --- a/pkg/ssh/cmd/project_name.go +++ b/pkg/ssh/cmd/project_name.go @@ -9,20 +9,17 @@ import ( func projectName() *cobra.Command { cmd := &cobra.Command{ - Use: "project-name REPOSITORY [NAME]", - Aliases: []string{"project"}, - Short: "Set or get the project name for a repository", - Args: cobra.MinimumNArgs(1), + Use: "project-name REPOSITORY [NAME]", + Aliases: []string{"project"}, + Short: "Set or get the project name for a repository", + Args: cobra.MinimumNArgs(1), + PersistentPreRunE: checkIfReadable, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) rn := strings.TrimSuffix(args[0], ".git") switch len(args) { case 1: - if err := checkIfReadable(cmd, args); err != nil { - return err - } - pn, err := be.ProjectName(ctx, rn) if err != nil { return err diff --git a/pkg/ssh/cmd/rename.go b/pkg/ssh/cmd/rename.go index 77cdc74e7..fe74a293b 100644 --- a/pkg/ssh/cmd/rename.go +++ b/pkg/ssh/cmd/rename.go @@ -11,7 +11,7 @@ func renameCommand() *cobra.Command { Aliases: []string{"mv", "move"}, Short: "Rename an existing repository", Args: cobra.ExactArgs(2), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) diff --git a/pkg/ssh/cmd/tag.go b/pkg/ssh/cmd/tag.go index 811de2316..009ac0308 100644 --- a/pkg/ssh/cmd/tag.go +++ b/pkg/ssh/cmd/tag.go @@ -64,7 +64,7 @@ func tagDeleteCommand() *cobra.Command { Aliases: []string{"remove", "rm", "del"}, Short: "Delete a tag", Args: cobra.ExactArgs(2), - PersistentPreRunE: checkIfCollab, + PersistentPreRunE: checkIfReadableAndCollab, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() be := backend.FromContext(ctx) diff --git a/testscript/testdata/repo-perms.txtar b/testscript/testdata/repo-perms.txtar index a3e4515c0..b21c0c3ff 100644 --- a/testscript/testdata/repo-perms.txtar +++ b/testscript/testdata/repo-perms.txtar @@ -36,33 +36,33 @@ soft repo collab list repo1 # regular user can't access it ! usoft repo info repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo tree repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo tag list repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo tag delete repo1 v1.0.0 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo blob repo1 README.md -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo description repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo description repo1 'new desc' -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo project-name repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo private repo1 true -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo private repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo rename repo1 repo11 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo branch default repo1 -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo branch default repo1 main -stderr 'unauthorized' +stderr 'repository not found' ! usoft repo delete repo1 -stderr 'unauthorized' +stderr 'repository not found' # add user1 as collab ! soft repo collab add repo1 user1 foobar