+1
appview/pages/templates/knots.html
+1
appview/pages/templates/knots.html
+3
-2
appview/state/repo.go
+3
-2
appview/state/repo.go
···
6
6
"io"
7
7
"log"
8
8
"net/http"
9
-
"path/filepath"
10
9
11
10
"github.com/bluesky-social/indigo/atproto/identity"
11
+
securejoin "github.com/cyphar/filepath-securejoin"
12
12
"github.com/go-chi/chi/v5"
13
13
"github.com/sotangled/tangled/appview/auth"
14
14
"github.com/sotangled/tangled/appview/pages"
···
419
419
}
420
420
421
421
func (f *FullyResolvedRepo) OwnerSlashRepo() string {
422
-
return filepath.Join(f.OwnerDid(), f.RepoName)
422
+
p, _ := securejoin.SecureJoin(f.OwnerDid(), f.RepoName)
423
+
return p
423
424
}
424
425
425
426
func fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) {
+3
-2
appview/state/state.go
+3
-2
appview/state/state.go
···
9
9
"fmt"
10
10
"log"
11
11
"net/http"
12
-
"path/filepath"
13
12
"strings"
14
13
"time"
15
14
···
17
16
"github.com/bluesky-social/indigo/atproto/syntax"
18
17
lexutil "github.com/bluesky-social/indigo/lex/util"
19
18
"github.com/bluesky-social/jetstream/pkg/models"
19
+
securejoin "github.com/cyphar/filepath-securejoin"
20
20
"github.com/go-chi/chi/v5"
21
21
tangled "github.com/sotangled/tangled/api/tangled"
22
22
"github.com/sotangled/tangled/appview"
···
529
529
}
530
530
531
531
// acls
532
-
err = s.enforcer.AddRepo(user.Did, domain, filepath.Join(user.Did, repoName))
532
+
p, _ := securejoin.SecureJoin(domain, repoName)
533
+
err = s.enforcer.AddRepo(user.Did, domain, p)
533
534
if err != nil {
534
535
s.pages.Notice(w, "repo", "Failed to set up repository permissions.")
535
536
return
+3
-4
cmd/repoguard/main.go
+3
-4
cmd/repoguard/main.go
···
9
9
"net/url"
10
10
"os"
11
11
"os/exec"
12
-
"path/filepath"
13
12
"strings"
14
13
"time"
15
14
15
+
securejoin "github.com/cyphar/filepath-securejoin"
16
16
"github.com/sotangled/tangled/appview"
17
17
)
18
18
···
79
79
didOrHandle := components[0]
80
80
did := resolveToDid(didOrHandle)
81
81
repoName := components[1]
82
-
qualifiedRepoName := filepath.Join(did, repoName)
82
+
qualifiedRepoName, _ := securejoin.SecureJoin(did, repoName)
83
83
84
84
validCommands := map[string]bool{
85
85
"git-receive-pack": true,
···
100
100
}
101
101
}
102
102
103
-
fullPath := filepath.Join(*baseDirFlag, qualifiedRepoName)
104
-
fullPath = filepath.Clean(fullPath)
103
+
fullPath, _ := securejoin.SecureJoin(*baseDirFlag, qualifiedRepoName)
105
104
106
105
logEvent("Processing command", map[string]interface{}{
107
106
"user": *incomingUser,
+1
-1
go.mod
+1
-1
go.mod
···
10
10
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20
11
11
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1
12
12
github.com/casbin/casbin/v2 v2.103.0
13
+
github.com/cyphar/filepath-securejoin v0.3.3
13
14
github.com/dustin/go-humanize v1.0.1
14
15
github.com/gliderlabs/ssh v0.3.5
15
16
github.com/go-chi/chi/v5 v5.2.0
···
36
37
github.com/casbin/govaluate v1.3.0 // indirect
37
38
github.com/cespare/xxhash/v2 v2.3.0 // indirect
38
39
github.com/cloudflare/circl v1.4.0 // indirect
39
-
github.com/cyphar/filepath-securejoin v0.3.3 // indirect
40
40
github.com/davecgh/go-spew v1.1.1 // indirect
41
41
github.com/emirpasic/gods v1.18.1 // indirect
42
42
github.com/felixge/httpsnoop v1.0.4 // indirect
+3
-2
knotserver/git.go
+3
-2
knotserver/git.go
···
6
6
"net/http"
7
7
"path/filepath"
8
8
9
+
securejoin "github.com/cyphar/filepath-securejoin"
9
10
"github.com/go-chi/chi/v5"
10
11
"github.com/sotangled/tangled/knotserver/git/service"
11
12
)
···
13
14
func (d *Handle) InfoRefs(w http.ResponseWriter, r *http.Request) {
14
15
did := chi.URLParam(r, "did")
15
16
name := chi.URLParam(r, "name")
16
-
repo := filepath.Join(d.c.Repo.ScanPath, did, name)
17
+
repo, _ := securejoin.SecureJoin(d.c.Repo.ScanPath, filepath.Join(did, name))
17
18
18
19
w.Header().Set("content-type", "application/x-git-upload-pack-advertisement")
19
20
w.WriteHeader(http.StatusOK)
···
33
34
func (d *Handle) UploadPack(w http.ResponseWriter, r *http.Request) {
34
35
did := chi.URLParam(r, "did")
35
36
name := chi.URLParam(r, "name")
36
-
repo := filepath.Join(d.c.Repo.ScanPath, did, name)
37
+
repo, _ := securejoin.SecureJoin(d.c.Repo.ScanPath, filepath.Join(did, name))
37
38
38
39
w.Header().Set("content-type", "application/x-git-upload-pack-result")
39
40
w.Header().Set("Connection", "Keep-Alive")
+11
-10
knotserver/routes.go
+11
-10
knotserver/routes.go
···
14
14
"strconv"
15
15
"strings"
16
16
17
+
securejoin "github.com/cyphar/filepath-securejoin"
17
18
"github.com/gliderlabs/ssh"
18
19
"github.com/go-chi/chi/v5"
19
20
"github.com/go-git/go-git/v5/plumbing"
···
29
30
}
30
31
31
32
func (h *Handle) RepoIndex(w http.ResponseWriter, r *http.Request) {
32
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
33
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
33
34
l := h.l.With("path", path, "handler", "RepoIndex")
34
35
35
36
gr, err := git.Open(path, "")
···
116
117
117
118
l := h.l.With("handler", "RepoTree", "ref", ref, "treePath", treePath)
118
119
119
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
120
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
120
121
gr, err := git.Open(path, ref)
121
122
if err != nil {
122
123
notFound(w)
···
148
149
149
150
l := h.l.With("handler", "FileContent", "ref", ref, "treePath", treePath)
150
151
151
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
152
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
152
153
gr, err := git.Open(path, ref)
153
154
if err != nil {
154
155
notFound(w)
···
192
193
setContentDisposition(w, filename)
193
194
setGZipMIME(w)
194
195
195
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
196
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
196
197
gr, err := git.Open(path, ref)
197
198
if err != nil {
198
199
notFound(w)
···
222
223
223
224
func (h *Handle) Log(w http.ResponseWriter, r *http.Request) {
224
225
ref := chi.URLParam(r, "ref")
225
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
226
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
226
227
227
228
l := h.l.With("handler", "Log", "ref", ref, "path", path)
228
229
···
288
289
289
290
l := h.l.With("handler", "Diff", "ref", ref)
290
291
291
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
292
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
292
293
gr, err := git.Open(path, ref)
293
294
if err != nil {
294
295
notFound(w)
···
312
313
}
313
314
314
315
func (h *Handle) Tags(w http.ResponseWriter, r *http.Request) {
315
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
316
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
316
317
l := h.l.With("handler", "Refs")
317
318
318
319
gr, err := git.Open(path, "")
···
353
354
}
354
355
355
356
func (h *Handle) Branches(w http.ResponseWriter, r *http.Request) {
356
-
path := filepath.Join(h.c.Repo.ScanPath, didPath(r))
357
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
357
358
l := h.l.With("handler", "Branches")
358
359
359
360
gr, err := git.Open(path, "")
···
445
446
name := data.Name
446
447
447
448
relativeRepoPath := filepath.Join(did, name)
448
-
repoPath := filepath.Join(h.c.Repo.ScanPath, relativeRepoPath)
449
+
repoPath, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, relativeRepoPath)
449
450
err := git.InitBare(repoPath)
450
451
if err != nil {
451
452
l.Error("initializing bare repo", "error", err.Error())
···
522
523
}
523
524
h.jc.AddDid(data.Did)
524
525
525
-
repoName := filepath.Join(ownerDid, repo)
526
+
repoName, _ := securejoin.SecureJoin(ownerDid, repo)
526
527
if err := h.e.AddCollaborator(data.Did, ThisServer, repoName); err != nil {
527
528
l.Error("adding repo collaborator", "error", err.Error())
528
529
writeError(w, err.Error(), http.StatusInternalServerError)
+2
-1
knotserver/util.go
+2
-1
knotserver/util.go
···
5
5
"os"
6
6
"path/filepath"
7
7
8
+
securejoin "github.com/cyphar/filepath-securejoin"
8
9
"github.com/go-chi/chi/v5"
9
10
"github.com/microcosm-cc/bluemonday"
10
11
)
···
16
17
func didPath(r *http.Request) string {
17
18
did := chi.URLParam(r, "did")
18
19
name := chi.URLParam(r, "name")
19
-
path := filepath.Join(did, name)
20
+
path, _ := securejoin.SecureJoin(did, name)
20
21
filepath.Clean(path)
21
22
return path
22
23
}