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 == "" {