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