this repo has no description
1package knotserver
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7
8 "github.com/go-chi/chi/v5"
9 "github.com/sotangled/tangled/knotserver/config"
10 "github.com/sotangled/tangled/knotserver/db"
11 "github.com/sotangled/tangled/knotserver/jsclient"
12 "github.com/sotangled/tangled/rbac"
13)
14
15const (
16 ThisServer = "thisserver" // resource identifier for rbac enforcement
17)
18
19type Handle struct {
20 c *config.Config
21 db *db.DB
22 js *jsclient.JetstreamClient
23 e *rbac.Enforcer
24
25 // init is a channel that is closed when the knot has been initailized
26 // i.e. when the first user (knot owner) has been added.
27 init chan struct{}
28 knotInitialized bool
29}
30
31func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer) (http.Handler, error) {
32 r := chi.NewRouter()
33
34 h := Handle{
35 c: c,
36 db: db,
37 e: e,
38 init: make(chan struct{}),
39 }
40
41 err := e.AddDomain(ThisServer)
42 if err != nil {
43 return nil, fmt.Errorf("failed to setup enforcer: %w", err)
44 }
45
46 err = h.StartJetstream(ctx)
47 if err != nil {
48 return nil, fmt.Errorf("failed to start jetstream: %w", err)
49 }
50
51 // Check if the knot knows about any Dids;
52 // if it does, it is already initialized and we can repopulate the
53 // Jetstream subscriptions.
54 dids, err := db.GetAllDids()
55 if err != nil {
56 return nil, fmt.Errorf("failed to get all Dids: %w", err)
57 }
58 if len(dids) > 0 {
59 h.knotInitialized = true
60 close(h.init)
61 h.js.UpdateDids(dids)
62 }
63
64 r.Get("/", h.Index)
65 r.Route("/{did}", func(r chi.Router) {
66 // Repo routes
67 r.Route("/{name}", func(r chi.Router) {
68 r.Get("/", h.RepoIndex)
69 r.Get("/info/refs", h.InfoRefs)
70 r.Post("/git-upload-pack", h.UploadPack)
71
72 r.Route("/tree/{ref}", func(r chi.Router) {
73 r.Get("/*", h.RepoTree)
74 })
75
76 r.Route("/blob/{ref}", func(r chi.Router) {
77 r.Get("/*", h.FileContent)
78 })
79
80 r.Get("/log/{ref}", h.Log)
81 r.Get("/archive/{file}", h.Archive)
82 r.Get("/commit/{ref}", h.Diff)
83 r.Get("/refs/", h.Refs)
84 })
85 })
86
87 // Create a new repository.
88 r.Route("/repo", func(r chi.Router) {
89 r.Use(h.VerifySignature)
90 r.Put("/new", h.NewRepo)
91 })
92
93 r.Route("/member", func(r chi.Router) {
94 r.Use(h.VerifySignature)
95 r.Put("/add", h.AddMember)
96 })
97
98 // Initialize the knot with an owner and public key.
99 r.With(h.VerifySignature).Post("/init", h.Init)
100
101 // Health check. Used for two-way verification with appview.
102 r.With(h.VerifySignature).Get("/health", h.Health)
103
104 // All public keys on the knot.
105 r.Get("/keys", h.Keys)
106
107 return r, nil
108}