d9639320b8d0ccd76fe6836a042c042b0ebde549

Author
Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Committer
GitHub <noreply@github.com>
Date

Message

Merge commit from fork

* sec: escape ansi sequences on user input

fixes HSA-fv2r-r8mp-pg48

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* Apply suggestion from @Tomer-PL

Co-authored-by: Tomer Fichman <tomer@irregular.com>

* chore: fmt

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Tomer Fichman <tomer@irregular.com>

Diff

  1diff --git a/pkg/backend/access_token.go b/pkg/backend/access_token.go
  2index 281ad8f174a1c67896594485c1958820fd2ac668..b8db671a1c3c78b78ea12c8620e0ac791310e2bc 100644
  3--- a/pkg/backend/access_token.go
  4+++ b/pkg/backend/access_token.go
  5@@ -7,12 +7,14 @@ import (
  6 
  7 	"github.com/charmbracelet/soft-serve/pkg/db"
  8 	"github.com/charmbracelet/soft-serve/pkg/proto"
  9+	"github.com/charmbracelet/soft-serve/pkg/utils"
 10 )
 11 
 12 // CreateAccessToken creates an access token for user.
 13 func (b *Backend) CreateAccessToken(ctx context.Context, user proto.User, name string, expiresAt time.Time) (string, error) {
 14 	token := GenerateToken()
 15 	tokenHash := HashToken(token)
 16+	name = utils.Sanitize(name)
 17 
 18 	if err := b.db.TransactionContext(ctx, func(tx *db.Tx) error {
 19 		_, err := b.store.CreateAccessToken(ctx, tx, name, user.ID(), tokenHash, expiresAt)
 20diff --git a/pkg/backend/repo.go b/pkg/backend/repo.go
 21index bacc8993848b638d4090b79e9f50a348446aa99a..e4eb3a7e12b4c290fad610cbeb9895fe1d17be43 100644
 22--- a/pkg/backend/repo.go
 23+++ b/pkg/backend/repo.go
 24@@ -544,6 +544,7 @@ func (d *Backend) SetHidden(ctx context.Context, name string, hidden bool) error
 25 // It implements backend.Backend.
 26 func (d *Backend) SetDescription(ctx context.Context, name string, desc string) error {
 27 	name = utils.SanitizeRepo(name)
 28+	desc = utils.Sanitize(desc)
 29 	rp := filepath.Join(d.repoPath(name))
 30 
 31 	// Delete cache
 32@@ -617,6 +618,7 @@ func (d *Backend) SetPrivate(ctx context.Context, name string, private bool) err
 33 // It implements backend.Backend.
 34 func (d *Backend) SetProjectName(ctx context.Context, repo string, name string) error {
 35 	repo = utils.SanitizeRepo(repo)
 36+	name = utils.Sanitize(name)
 37 
 38 	// Delete cache
 39 	d.cache.Delete(repo)
 40diff --git a/pkg/backend/user.go b/pkg/backend/user.go
 41index 4ad846c263df2dd42840a937b69d1850051e614f..736842f9fdddbc7fc83501ad02da1c5bd5f063f9 100644
 42--- a/pkg/backend/user.go
 43+++ b/pkg/backend/user.go
 44@@ -279,6 +279,7 @@ func (d *Backend) AddPublicKey(ctx context.Context, username string, pk ssh.Publ
 45 //
 46 // It implements backend.Backend.
 47 func (d *Backend) CreateUser(ctx context.Context, username string, opts proto.UserOptions) (proto.User, error) {
 48+	username = utils.Sanitize(username)
 49 	username = strings.ToLower(username)
 50 	if err := utils.ValidateUsername(username); err != nil {
 51 		return nil, err
 52diff --git a/pkg/backend/webhooks.go b/pkg/backend/webhooks.go
 53index cd3eb07e78ce3016c835c6ae00976f5b33fd427c..f217c30337f374f7ff0b1aace8c19a86bfb19073 100644
 54--- a/pkg/backend/webhooks.go
 55+++ b/pkg/backend/webhooks.go
 56@@ -9,6 +9,7 @@ import (
 57 	"github.com/charmbracelet/soft-serve/pkg/db/models"
 58 	"github.com/charmbracelet/soft-serve/pkg/proto"
 59 	"github.com/charmbracelet/soft-serve/pkg/store"
 60+	"github.com/charmbracelet/soft-serve/pkg/utils"
 61 	"github.com/charmbracelet/soft-serve/pkg/webhook"
 62 	"github.com/google/uuid"
 63 )
 64@@ -17,6 +18,7 @@ import (
 65 func (b *Backend) CreateWebhook(ctx context.Context, repo proto.Repository, url string, contentType webhook.ContentType, secret string, events []webhook.Event, active bool) error {
 66 	dbx := db.FromContext(ctx)
 67 	datastore := store.FromContext(ctx)
 68+	url = utils.Sanitize(url)
 69 
 70 	return dbx.TransactionContext(ctx, func(tx *db.Tx) error {
 71 		lastID, err := datastore.CreateWebhook(ctx, tx, repo.ID(), url, secret, int(contentType), active)
 72diff --git a/pkg/ssh/cmd/commit.go b/pkg/ssh/cmd/commit.go
 73index ad2020d36a2076e540f71c3eba380909fd7756b9..2dceace252e1552700926ccbb1d6b256465d416c 100644
 74--- a/pkg/ssh/cmd/commit.go
 75+++ b/pkg/ssh/cmd/commit.go
 76@@ -10,6 +10,7 @@ import (
 77 	"github.com/charmbracelet/soft-serve/pkg/backend"
 78 	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 79 	"github.com/charmbracelet/soft-serve/pkg/ui/styles"
 80+	"github.com/charmbracelet/soft-serve/pkg/utils"
 81 	"github.com/spf13/cobra"
 82 )
 83 
 84@@ -59,9 +60,9 @@ func commitCommand() *cobra.Command {
 85 
 86 			s := strings.Builder{}
 87 			commitLine := "commit " + commitSHA
 88-			authorLine := "Author: " + commit.Author.Name
 89+			authorLine := "Author: " + utils.Sanitize(commit.Author.Name)
 90 			dateLine := "Date:   " + commit.Committer.When.UTC().Format(time.UnixDate)
 91-			msgLine := strings.ReplaceAll(commit.Message, "\r\n", "\n")
 92+			msgLine := strings.ReplaceAll(utils.Sanitize(commit.Message), "\r\n", "\n")
 93 			statsLine := renderStats(diff, commonStyle, color)
 94 			diffLine := renderDiff(patch, color)
 95 
 96diff --git a/pkg/ssh/cmd/webhooks.go b/pkg/ssh/cmd/webhooks.go
 97index ca6e8978929c1ca283d3b5aff470ffed34358132..742127052107d2a8bd99f904d5e132e718e0a685 100644
 98--- a/pkg/ssh/cmd/webhooks.go
 99+++ b/pkg/ssh/cmd/webhooks.go
100@@ -7,6 +7,7 @@ import (
101 
102 	"github.com/charmbracelet/lipgloss/v2/table"
103 	"github.com/charmbracelet/soft-serve/pkg/backend"
104+	"github.com/charmbracelet/soft-serve/pkg/utils"
105 	"github.com/charmbracelet/soft-serve/pkg/webhook"
106 	"github.com/dustin/go-humanize"
107 	"github.com/google/uuid"
108@@ -69,7 +70,7 @@ func webhookListCommand() *cobra.Command {
109 
110 				table = table.Row(
111 					strconv.FormatInt(h.ID, 10),
112-					h.URL,
113+					utils.Sanitize(h.URL),
114 					strings.Join(events, ","),
115 					strconv.FormatBool(h.Active),
116 					humanize.Time(h.CreatedAt),
117@@ -122,7 +123,8 @@ func webhookCreateCommand() *cobra.Command {
118 				return webhook.ErrInvalidContentType
119 			}
120 
121-			return be.CreateWebhook(ctx, repo, strings.TrimSpace(args[1]), ct, secret, evs, active)
122+			url := utils.Sanitize(args[1])
123+			return be.CreateWebhook(ctx, repo, strings.TrimSpace(url), ct, secret, evs, active)
124 		},
125 	}
126 
127diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go
128index 559e8e1b70324bdcfc049d3a4140dd1bf0e7f6aa..2fb66e55dc3a5f745f55e6d1b80b4cc2177209f3 100644
129--- a/pkg/utils/utils.go
130+++ b/pkg/utils/utils.go
131@@ -5,10 +5,13 @@ import (
132 	"path"
133 	"strings"
134 	"unicode"
135+
136+	"github.com/charmbracelet/x/ansi"
137 )
138 
139 // SanitizeRepo returns a sanitized version of the given repository name.
140 func SanitizeRepo(repo string) string {
141+	repo = Sanitize(repo)
142 	// We need to use an absolute path for the path to be cleaned correctly.
143 	repo = strings.TrimPrefix(repo, "/")
144 	repo = "/" + repo
145@@ -20,6 +23,11 @@ func SanitizeRepo(repo string) string {
146 	return repo[1:]
147 }
148 
149+// Sanitize strips ANSI escape codes from the given string.
150+func Sanitize(s string) string {
151+	return ansi.Strip(s)
152+}
153+
154 // ValidateUsername returns an error if any of the given usernames are invalid.
155 func ValidateUsername(username string) error {
156 	if username == "" {