Signed-off-by: Lewis lewis@tangled.org
+469
-37
Diff
round #11
+142
-2
appview/db/repos.go
+142
-2
appview/db/repos.go
···
577
577
return GetRepo(e, orm.FilterEq("repo_did", repoDid))
578
578
}
579
579
580
+
func EnqueuePdsRewritesForRepo(tx *sql.Tx, repoDid, repoAtUri string) error {
581
+
type record struct {
582
+
userDidCol string
583
+
table string
584
+
nsid string
585
+
fkCol string
586
+
}
587
+
sources := []record{
588
+
{"did", "repos", "sh.tangled.repo", "at_uri"},
589
+
{"did", "issues", "sh.tangled.repo.issue", "repo_at"},
590
+
{"owner_did", "pulls", "sh.tangled.repo.pull", "repo_at"},
591
+
{"did", "collaborators", "sh.tangled.repo.collaborator", "repo_at"},
592
+
{"did", "artifacts", "sh.tangled.repo.artifact", "repo_at"},
593
+
{"did", "stars", "sh.tangled.feed.star", "subject_at"},
594
+
}
595
+
596
+
for _, src := range sources {
597
+
rows, err := tx.Query(
598
+
fmt.Sprintf(`SELECT %s, rkey FROM %s WHERE %s = ?`, src.userDidCol, src.table, src.fkCol),
599
+
repoAtUri,
600
+
)
601
+
if err != nil {
602
+
return fmt.Errorf("query %s for pds rewrites: %w", src.table, err)
603
+
}
604
+
605
+
var pairs []struct{ did, rkey string }
606
+
for rows.Next() {
607
+
var d, r string
608
+
if scanErr := rows.Scan(&d, &r); scanErr != nil {
609
+
rows.Close()
610
+
return fmt.Errorf("scan %s for pds rewrites: %w", src.table, scanErr)
611
+
}
612
+
pairs = append(pairs, struct{ did, rkey string }{d, r})
613
+
}
614
+
rows.Close()
615
+
if rowsErr := rows.Err(); rowsErr != nil {
616
+
return fmt.Errorf("iterate %s for pds rewrites: %w", src.table, rowsErr)
617
+
}
618
+
619
+
for _, p := range pairs {
620
+
if err := EnqueuePdsRewrite(tx, p.did, repoDid, src.nsid, p.rkey, repoAtUri); err != nil {
621
+
return fmt.Errorf("enqueue pds rewrite for %s/%s: %w", src.table, p.rkey, err)
622
+
}
623
+
}
624
+
}
625
+
626
+
profileRows, err := tx.Query(
627
+
`SELECT DISTINCT did FROM profile_pinned_repositories WHERE at_uri = ?`,
628
+
repoAtUri,
629
+
)
630
+
if err != nil {
631
+
return fmt.Errorf("query profile_pinned_repositories for pds rewrites: %w", err)
632
+
}
633
+
var profileDids []string
634
+
for profileRows.Next() {
635
+
var d string
636
+
if scanErr := profileRows.Scan(&d); scanErr != nil {
637
+
profileRows.Close()
638
+
return fmt.Errorf("scan profile_pinned_repositories for pds rewrites: %w", scanErr)
639
+
}
640
+
profileDids = append(profileDids, d)
641
+
}
642
+
profileRows.Close()
643
+
if profileRowsErr := profileRows.Err(); profileRowsErr != nil {
644
+
return fmt.Errorf("iterate profile_pinned_repositories for pds rewrites: %w", profileRowsErr)
645
+
}
646
+
647
+
for _, d := range profileDids {
648
+
if err := EnqueuePdsRewrite(tx, d, repoDid, "sh.tangled.actor.profile", "self", repoAtUri); err != nil {
649
+
return fmt.Errorf("enqueue pds rewrite for profile/%s: %w", d, err)
650
+
}
651
+
}
652
+
653
+
return nil
654
+
}
655
+
656
+
type PdsRewrite struct {
657
+
Id int
658
+
RepoDid string
659
+
RecordNsid string
660
+
RecordRkey string
661
+
OldRepoAt string
662
+
}
663
+
664
+
func GetPendingPdsRewrites(e Execer, userDid string) ([]PdsRewrite, error) {
665
+
rows, err := e.Query(
666
+
`SELECT id, repo_did, record_nsid, record_rkey, old_repo_at
667
+
FROM pds_rewrite_status
668
+
WHERE user_did = ? AND status = 'pending'`,
669
+
userDid,
670
+
)
671
+
if err != nil {
672
+
return nil, err
673
+
}
674
+
defer rows.Close()
675
+
676
+
var rewrites []PdsRewrite
677
+
for rows.Next() {
678
+
var r PdsRewrite
679
+
if err := rows.Scan(&r.Id, &r.RepoDid, &r.RecordNsid, &r.RecordRkey, &r.OldRepoAt); err != nil {
680
+
return nil, err
681
+
}
682
+
rewrites = append(rewrites, r)
683
+
}
684
+
return rewrites, rows.Err()
685
+
}
686
+
687
+
func CompletePdsRewrite(e Execer, id int) error {
688
+
_, err := e.Exec(
689
+
`UPDATE pds_rewrite_status SET status = 'done', updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ?`,
690
+
id,
691
+
)
692
+
return err
693
+
}
694
+
580
695
func EnqueuePdsRewrite(e Execer, userDid, repoDid, recordNsid, recordRkey, oldRepoAt string) error {
581
696
_, err := e.Exec(
582
-
`INSERT OR IGNORE INTO pds_rewrite_status
697
+
`INSERT INTO pds_rewrite_status
583
698
(user_did, repo_did, record_nsid, record_rkey, old_repo_at, status)
584
-
VALUES (?, ?, ?, ?, ?, 'pending')`,
699
+
VALUES (?, ?, ?, ?, ?, 'pending')
700
+
ON CONFLICT(user_did, record_nsid, record_rkey) DO UPDATE SET
701
+
status = 'pending',
702
+
repo_did = excluded.repo_did,
703
+
old_repo_at = excluded.old_repo_at,
704
+
updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now')`,
585
705
userDid, repoDid, recordNsid, recordRkey, oldRepoAt,
586
706
)
587
707
return err
588
708
}
589
709
710
+
func CascadeRepoDid(tx *sql.Tx, repoAtUri, repoDid string) error {
711
+
_, err := tx.Exec(
712
+
`UPDATE repos SET repo_did = ? WHERE at_uri = ?`,
713
+
repoDid, repoAtUri,
714
+
)
715
+
if err != nil {
716
+
return fmt.Errorf("cascade repo_did to repos: %w", err)
717
+
}
718
+
719
+
_, err = tx.Exec(
720
+
`UPDATE repos SET source = ? WHERE source = ?`,
721
+
repoDid, repoAtUri,
722
+
)
723
+
if err != nil {
724
+
return fmt.Errorf("cascade repo_did to repos.source: %w", err)
725
+
}
726
+
727
+
return nil
728
+
}
729
+
590
730
func UpdateDescription(e Execer, repoAt, newDescription string) error {
591
731
_, err := e.Exec(
592
732
`update repos set description = ? where at_uri = ?`, newDescription, repoAt)
+134
appview/oauth/handler.go
+134
appview/oauth/handler.go
···
14
14
15
15
comatproto "github.com/bluesky-social/indigo/api/atproto"
16
16
"github.com/bluesky-social/indigo/atproto/auth/oauth"
17
+
atpclient "github.com/bluesky-social/indigo/atproto/client"
17
18
lexutil "github.com/bluesky-social/indigo/lex/util"
18
19
xrpc "github.com/bluesky-social/indigo/xrpc"
19
20
"github.com/go-chi/chi/v5"
···
95
96
go o.addToDefaultSpindle(sessData.AccountDID.String())
96
97
go o.ensureTangledProfile(sessData)
97
98
go o.autoClaimTnglShDomain(sessData.AccountDID.String())
99
+
go o.drainPdsRewrites(sessData)
98
100
99
101
if !o.Config.Core.Dev {
100
102
err = o.Posthog.Enqueue(posthog.Capture{
···
273
275
l.Debug("successfully created empty Tangled profile on PDS and DB")
274
276
}
275
277
278
+
func (o *OAuth) drainPdsRewrites(sessData *oauth.ClientSessionData) {
279
+
ctx := context.Background()
280
+
did := sessData.AccountDID.String()
281
+
l := o.Logger.With("did", did, "handler", "drainPdsRewrites")
282
+
283
+
rewrites, err := db.GetPendingPdsRewrites(o.Db, did)
284
+
if err != nil {
285
+
l.Error("failed to get pending rewrites", "err", err)
286
+
return
287
+
}
288
+
if len(rewrites) == 0 {
289
+
return
290
+
}
291
+
292
+
l.Info("draining pending PDS rewrites", "count", len(rewrites))
293
+
294
+
sess, err := o.ClientApp.ResumeSession(ctx, sessData.AccountDID, sessData.SessionID)
295
+
if err != nil {
296
+
l.Error("failed to resume session for PDS rewrites", "err", err)
297
+
return
298
+
}
299
+
client := sess.APIClient()
300
+
301
+
for _, rw := range rewrites {
302
+
if err := o.rewritePdsRecord(ctx, client, did, rw); err != nil {
303
+
l.Error("failed to rewrite PDS record",
304
+
"nsid", rw.RecordNsid,
305
+
"rkey", rw.RecordRkey,
306
+
"repo_did", rw.RepoDid,
307
+
"err", err)
308
+
continue
309
+
}
310
+
311
+
if err := db.CompletePdsRewrite(o.Db, rw.Id); err != nil {
312
+
l.Error("failed to mark rewrite complete", "id", rw.Id, "err", err)
313
+
}
314
+
}
315
+
}
316
+
317
+
func (o *OAuth) rewritePdsRecord(ctx context.Context, client *atpclient.APIClient, userDid string, rw db.PdsRewrite) error {
318
+
ex, err := comatproto.RepoGetRecord(ctx, client, "", rw.RecordNsid, userDid, rw.RecordRkey)
319
+
if err != nil {
320
+
return fmt.Errorf("get record: %w", err)
321
+
}
322
+
323
+
val := ex.Value.Val
324
+
repoDid := rw.RepoDid
325
+
326
+
switch rw.RecordNsid {
327
+
case tangled.RepoNSID:
328
+
rec, ok := val.(*tangled.Repo)
329
+
if !ok {
330
+
return fmt.Errorf("unexpected type for repo record")
331
+
}
332
+
rec.RepoDid = &repoDid
333
+
334
+
case tangled.RepoIssueNSID:
335
+
rec, ok := val.(*tangled.RepoIssue)
336
+
if !ok {
337
+
return fmt.Errorf("unexpected type for issue record")
338
+
}
339
+
rec.RepoDid = &repoDid
340
+
341
+
case tangled.RepoPullNSID:
342
+
rec, ok := val.(*tangled.RepoPull)
343
+
if !ok {
344
+
return fmt.Errorf("unexpected type for pull record")
345
+
}
346
+
if rec.Target != nil {
347
+
rec.Target.RepoDid = &repoDid
348
+
}
349
+
if rec.Source != nil && rec.Source.Repo != nil && *rec.Source.Repo == rw.OldRepoAt {
350
+
rec.Source.RepoDid = &repoDid
351
+
}
352
+
353
+
case tangled.RepoCollaboratorNSID:
354
+
rec, ok := val.(*tangled.RepoCollaborator)
355
+
if !ok {
356
+
return fmt.Errorf("unexpected type for collaborator record")
357
+
}
358
+
rec.RepoDid = &repoDid
359
+
360
+
case tangled.RepoArtifactNSID:
361
+
rec, ok := val.(*tangled.RepoArtifact)
362
+
if !ok {
363
+
return fmt.Errorf("unexpected type for artifact record")
364
+
}
365
+
rec.RepoDid = &repoDid
366
+
367
+
case tangled.FeedStarNSID:
368
+
rec, ok := val.(*tangled.FeedStar)
369
+
if !ok {
370
+
return fmt.Errorf("unexpected type for star record")
371
+
}
372
+
rec.SubjectDid = &repoDid
373
+
374
+
case tangled.ActorProfileNSID:
375
+
rec, ok := val.(*tangled.ActorProfile)
376
+
if !ok {
377
+
return fmt.Errorf("unexpected type for profile record")
378
+
}
379
+
var dids []string
380
+
var remaining []string
381
+
for _, pinUri := range rec.PinnedRepositories {
382
+
repo, repoErr := db.GetRepoByAtUri(o.Db, pinUri)
383
+
if repoErr != nil || repo.RepoDid == "" {
384
+
remaining = append(remaining, pinUri)
385
+
continue
386
+
}
387
+
dids = append(dids, repo.RepoDid)
388
+
}
389
+
rec.PinnedRepositoryDids = append(rec.PinnedRepositoryDids, dids...)
390
+
rec.PinnedRepositories = remaining
391
+
392
+
default:
393
+
return fmt.Errorf("unsupported NSID for PDS rewrite: %s", rw.RecordNsid)
394
+
}
395
+
396
+
_, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{
397
+
Collection: rw.RecordNsid,
398
+
Repo: userDid,
399
+
Rkey: rw.RecordRkey,
400
+
SwapRecord: ex.Cid,
401
+
Record: &lexutil.LexiconTypeDecoder{Val: val},
402
+
})
403
+
if err != nil {
404
+
return fmt.Errorf("put record: %w", err)
405
+
}
406
+
407
+
return nil
408
+
}
409
+
276
410
// create a AppPasswordSession using apppasswords
277
411
type AppPasswordSession struct {
278
412
AccessJwt string `json:"accessJwt"`
+90
appview/state/knotstream.go
+90
appview/state/knotstream.go
···
20
20
"tangled.org/core/appview/sites"
21
21
ec "tangled.org/core/eventconsumer"
22
22
"tangled.org/core/eventconsumer/cursor"
23
+
knotdb "tangled.org/core/knotserver/db"
23
24
"tangled.org/core/log"
24
25
"tangled.org/core/orm"
25
26
"tangled.org/core/rbac"
···
88
89
return ingestRefUpdate(ctx, d, enforcer, posthog, notifier, dev, c, cfClient, source, msg)
89
90
case tangled.PipelineNSID:
90
91
return ingestPipeline(d, source, msg)
92
+
case knotdb.RepoDIDAssignNSID:
93
+
return ingestDIDAssign(d, enforcer, source, msg, ctx)
91
94
}
92
95
93
96
return nil
···
375
378
376
379
return nil
377
380
}
381
+
382
+
func ingestDIDAssign(d *db.DB, enforcer *rbac.Enforcer, source ec.Source, msg ec.Message, ctx context.Context) error {
383
+
logger := log.FromContext(ctx)
384
+
385
+
var record knotdb.RepoDIDAssign
386
+
if err := json.Unmarshal(msg.EventJson, &record); err != nil {
387
+
return fmt.Errorf("unmarshal didAssign: %w", err)
388
+
}
389
+
390
+
if record.RepoDid == "" || record.OwnerDid == "" || record.RepoName == "" {
391
+
return fmt.Errorf("didAssign missing required fields: repoDid=%q ownerDid=%q repoName=%q",
392
+
record.RepoDid, record.OwnerDid, record.RepoName)
393
+
}
394
+
395
+
logger.Info("processing didAssign event",
396
+
"repo_did", record.RepoDid,
397
+
"owner_did", record.OwnerDid,
398
+
"repo_name", record.RepoName)
399
+
400
+
repos, err := db.GetRepos(d, 1,
401
+
orm.FilterEq("did", record.OwnerDid),
402
+
orm.FilterEq("name", record.RepoName),
403
+
)
404
+
if err != nil || len(repos) == 0 {
405
+
logger.Warn("didAssign for unknown repo, skipping",
406
+
"owner_did", record.OwnerDid,
407
+
"repo_name", record.RepoName)
408
+
return nil
409
+
}
410
+
repo := repos[0]
411
+
knot := source.Key()
412
+
413
+
if repo.Knot != knot {
414
+
return fmt.Errorf("didAssign from %s for repo hosted on %s, rejecting", knot, repo.Knot)
415
+
}
416
+
417
+
repoAtUri := repo.RepoAt().String()
418
+
legacyResource := record.OwnerDid + "/" + record.RepoName
419
+
420
+
if repo.RepoDid != record.RepoDid {
421
+
tx, err := d.Begin()
422
+
if err != nil {
423
+
return fmt.Errorf("begin didAssign txn: %w", err)
424
+
}
425
+
defer tx.Rollback()
426
+
427
+
if err := db.CascadeRepoDid(tx, repoAtUri, record.RepoDid); err != nil {
428
+
return fmt.Errorf("cascade repo_did: %w", err)
429
+
}
430
+
431
+
if err := db.EnqueuePdsRewritesForRepo(tx, record.RepoDid, repoAtUri); err != nil {
432
+
return fmt.Errorf("enqueue pds rewrites: %w", err)
433
+
}
434
+
435
+
if err := tx.Commit(); err != nil {
436
+
return fmt.Errorf("commit didAssign txn: %w", err)
437
+
}
438
+
}
439
+
440
+
if err := enforcer.RemoveRepo(record.OwnerDid, knot, legacyResource); err != nil {
441
+
return fmt.Errorf("remove legacy RBAC policies for %s: %w", legacyResource, err)
442
+
}
443
+
if err := enforcer.AddRepo(record.OwnerDid, knot, record.RepoDid); err != nil {
444
+
return fmt.Errorf("add RBAC policies for %s: %w", record.RepoDid, err)
445
+
}
446
+
447
+
collabs, collabErr := db.GetCollaborators(d, orm.FilterEq("repo_at", repoAtUri))
448
+
if collabErr != nil {
449
+
return fmt.Errorf("get collaborators for RBAC update: %w", collabErr)
450
+
}
451
+
for _, c := range collabs {
452
+
collabDid := c.SubjectDid.String()
453
+
if err := enforcer.RemoveCollaborator(collabDid, knot, legacyResource); err != nil {
454
+
return fmt.Errorf("remove collaborator RBAC for %s: %w", collabDid, err)
455
+
}
456
+
if err := enforcer.AddCollaborator(collabDid, knot, record.RepoDid); err != nil {
457
+
return fmt.Errorf("add collaborator RBAC for %s: %w", collabDid, err)
458
+
}
459
+
}
460
+
461
+
logger.Info("didAssign processed successfully",
462
+
"repo_did", record.RepoDid,
463
+
"owner_did", record.OwnerDid,
464
+
"repo_name", record.RepoName)
465
+
466
+
return nil
467
+
}
+10
knotserver/db/didassign.go
+10
knotserver/db/didassign.go
+22
knotserver/db/events.go
+22
knotserver/db/events.go
···
1
1
package db
2
2
3
3
import (
4
+
"encoding/json"
4
5
"fmt"
5
6
"time"
6
7
7
8
"tangled.org/core/notifier"
9
+
"tangled.org/core/tid"
8
10
)
9
11
10
12
type Event struct {
···
29
31
return err
30
32
}
31
33
34
+
func (d *DB) EmitDIDAssign(n *notifier.Notifier, ownerDid, repoName, repoDid, oldRepoAt string) error {
35
+
payload := RepoDIDAssign{
36
+
OwnerDid: ownerDid,
37
+
RepoName: repoName,
38
+
RepoDid: repoDid,
39
+
OldRepoAt: oldRepoAt,
40
+
}
41
+
42
+
eventJson, err := json.Marshal(payload)
43
+
if err != nil {
44
+
return fmt.Errorf("marshal didAssign event: %w", err)
45
+
}
46
+
47
+
return d.InsertEvent(Event{
48
+
Rkey: tid.TID(),
49
+
Nsid: RepoDIDAssignNSID,
50
+
EventJson: string(eventJson),
51
+
}, n)
52
+
}
53
+
32
54
func (d *DB) GetEvents(cursor int64) ([]Event, error) {
33
55
whereClause := ""
34
56
args := []any{}
+26
-14
knotserver/events.go
+26
-14
knotserver/events.go
···
54
54
cursor = defaultCursor
55
55
}
56
56
57
-
// complete backfill first before going to live data
58
57
l.Debug("going through backfill", "cursor", cursor)
59
-
if err := h.streamOps(conn, &cursor); err != nil {
58
+
if err := h.drainBackfill(conn, &cursor, 10_000); err != nil {
60
59
l.Error("failed to backfill", "err", err)
61
60
return
62
61
}
···
68
67
l.Debug("stopping stream: client closed connection")
69
68
return
70
69
case <-ch:
71
-
// we have been notified of new data
72
70
l.Debug("going through live data", "cursor", cursor)
73
-
if err := h.streamOps(conn, &cursor); err != nil {
71
+
if _, err := h.streamOps(conn, &cursor); err != nil {
74
72
l.Error("failed to stream", "err", err)
75
73
return
76
74
}
···
83
81
}
84
82
}
85
83
86
-
func (h *Knot) streamOps(conn *websocket.Conn, cursor *int64) error {
84
+
func (h *Knot) drainBackfill(conn *websocket.Conn, cursor *int64, maxBatches int) error {
85
+
for range maxBatches {
86
+
n, err := h.streamOps(conn, cursor)
87
+
if err != nil {
88
+
return err
89
+
}
90
+
if n < 100 {
91
+
return nil
92
+
}
93
+
}
94
+
h.l.Warn("backfill hit batch limit", "maxBatches", maxBatches, "cursor", *cursor)
95
+
return nil
96
+
}
97
+
98
+
func (h *Knot) streamOps(conn *websocket.Conn, cursor *int64) (int, error) {
87
99
events, err := h.db.GetEvents(*cursor)
88
100
if err != nil {
89
101
h.l.Error("failed to fetch events from db", "err", err, "cursor", cursor)
90
-
return err
102
+
return 0, err
91
103
}
92
104
93
105
for _, event := range events {
94
-
// first extract the inner json into a map
95
106
var eventJson map[string]any
96
107
err := json.Unmarshal([]byte(event.EventJson), &eventJson)
97
108
if err != nil {
98
109
h.l.Error("failed to unmarshal event", "err", err)
99
-
return err
110
+
return 0, err
100
111
}
101
112
102
113
jsonMsg, err := json.Marshal(map[string]any{
103
-
"rkey": event.Rkey,
104
-
"nsid": event.Nsid,
105
-
"event": eventJson,
114
+
"rkey": event.Rkey,
115
+
"nsid": event.Nsid,
116
+
"event": eventJson,
117
+
"created": event.Created,
106
118
})
107
119
if err != nil {
108
120
h.l.Error("failed to marshal record", "err", err)
109
-
return err
121
+
return 0, err
110
122
}
111
123
112
124
if err := conn.WriteMessage(websocket.TextMessage, jsonMsg); err != nil {
113
125
h.l.Debug("err", "err", err)
114
-
return err
126
+
return 0, err
115
127
}
116
128
*cursor = event.Created
117
129
}
118
130
119
-
return nil
131
+
return len(events), nil
120
132
}
+14
-5
knotserver/git.go
+14
-5
knotserver/git.go
···
6
6
"io"
7
7
"net/http"
8
8
"os"
9
+
"path/filepath"
9
10
"strings"
10
11
12
+
securejoin "github.com/cyphar/filepath-securejoin"
11
13
"github.com/go-chi/chi/v5"
12
14
"tangled.org/core/knotserver/git/service"
13
15
)
···
25
27
}
26
28
27
29
repoDid, err := h.db.GetRepoDid(did, name)
28
-
if err != nil {
29
-
return "", "", fmt.Errorf("repo not found: %w", err)
30
+
if err == nil {
31
+
repoPath, _, _, resolveErr := h.db.ResolveRepoDIDOnDisk(h.c.Repo.ScanPath, repoDid)
32
+
if resolveErr == nil {
33
+
return repoPath, name, nil
34
+
}
30
35
}
31
-
repoPath, _, _, err := h.db.ResolveRepoDIDOnDisk(h.c.Repo.ScanPath, repoDid)
32
-
if err != nil {
33
-
return "", "", fmt.Errorf("repo not found: %w", err)
36
+
37
+
repoPath, joinErr := securejoin.SecureJoin(h.c.Repo.ScanPath, filepath.Join(did, name))
38
+
if joinErr != nil {
39
+
return "", "", fmt.Errorf("repo not found: %w", joinErr)
40
+
}
41
+
if _, statErr := os.Stat(repoPath); statErr != nil {
42
+
return "", "", fmt.Errorf("repo not found: %w", statErr)
34
43
}
35
44
return repoPath, name, nil
36
45
}
+28
-13
knotserver/internal.go
+28
-13
knotserver/internal.go
···
6
6
"fmt"
7
7
"log/slog"
8
8
"net/http"
9
+
"os"
9
10
"path/filepath"
10
11
"strings"
11
12
13
+
securejoin "github.com/cyphar/filepath-securejoin"
12
14
"github.com/go-chi/chi/v5"
13
15
"github.com/go-chi/chi/v5/middleware"
14
16
"github.com/go-git/go-git/v5/plumbing"
···
124
126
ownerDid := repoOwnerIdent.DID.String()
125
127
repoName := components[1]
126
128
repoDid, didErr := h.db.GetRepoDid(ownerDid, repoName)
127
-
if didErr != nil {
128
-
w.WriteHeader(http.StatusNotFound)
129
-
l.Error("repo DID not found", "owner", ownerDid, "name", repoName, "err", didErr)
130
-
fmt.Fprintln(w, "repo not found")
131
-
return
132
-
}
133
-
repoPath, _, _, lookupErr := h.db.ResolveRepoDIDOnDisk(h.c.Repo.ScanPath, repoDid)
134
-
if lookupErr != nil {
135
-
w.WriteHeader(http.StatusNotFound)
136
-
l.Error("repo not found on disk", "repoDid", repoDid, "err", lookupErr)
137
-
fmt.Fprintln(w, "repo not found")
138
-
return
129
+
var repoPath string
130
+
if didErr == nil {
131
+
var lookupErr error
132
+
repoPath, _, _, lookupErr = h.db.ResolveRepoDIDOnDisk(h.c.Repo.ScanPath, repoDid)
133
+
if lookupErr != nil {
134
+
w.WriteHeader(http.StatusNotFound)
135
+
l.Error("repo not found on disk", "repoDid", repoDid, "err", lookupErr)
136
+
fmt.Fprintln(w, "repo not found")
137
+
return
138
+
}
139
+
rbacResource = repoDid
140
+
} else {
141
+
legacyPath, joinErr := securejoin.SecureJoin(h.c.Repo.ScanPath, filepath.Join(ownerDid, repoName))
142
+
if joinErr != nil {
143
+
w.WriteHeader(http.StatusNotFound)
144
+
fmt.Fprintln(w, "repo not found")
145
+
return
146
+
}
147
+
if _, statErr := os.Stat(legacyPath); statErr != nil {
148
+
w.WriteHeader(http.StatusNotFound)
149
+
l.Error("repo not found on disk (legacy)", "owner", ownerDid, "name", repoName)
150
+
fmt.Fprintln(w, "repo not found")
151
+
return
152
+
}
153
+
repoPath = legacyPath
154
+
rbacResource = ownerDid + "/" + repoName
139
155
}
140
-
rbacResource = repoDid
141
156
rel, relErr := filepath.Rel(h.c.Repo.ScanPath, repoPath)
142
157
if relErr != nil {
143
158
w.WriteHeader(http.StatusInternalServerError)
+2
-2
rbac/rbac.go
+2
-2
rbac/rbac.go
···
34
34
)
35
35
36
36
type Enforcer struct {
37
-
E *casbin.Enforcer
37
+
E *casbin.SyncedEnforcer
38
38
}
39
39
40
40
func NewEnforcer(path string) (*Enforcer, error) {
···
53
53
return nil, err
54
54
}
55
55
56
-
e, err := casbin.NewEnforcer(m, a)
56
+
e, err := casbin.NewSyncedEnforcer(m, a)
57
57
if err != nil {
58
58
return nil, err
59
59
}
History
12 rounds
1 comment
oyster.cafe
submitted
#11
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
merge conflicts detected
expand
collapse
expand
collapse
- go.mod:34
- go.sum:339
expand 0 comments
oyster.cafe
submitted
#10
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#9
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 1 comment
oyster.cafe
submitted
#8
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#7
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#6
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#5
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#4
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#3
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#2
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#1
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
expand 0 comments
oyster.cafe
submitted
#0
1 commit
expand
collapse
appview, knotserver: add didAssign event and PDS rewrite on login
Signed-off-by: Lewis <lewis@tangled.org>
knotserver/xrpc/xrpc.go:88can you absorb this?knotserver/db/events.go:12can be replaced withtid.TID()appview/oauth/handler.go:340I think we should better keep that information just in case. Especially considering users cannot found the target repo without ingesting entire knotstream events.everything else lgtm!