···2424 if err != nil {
2525 log.Fatal(err)
2626 }
2727+2828+ if c.Server.Dev {
2929+ log.Println("running in dev mode, signature verification is disabled")
3030+ }
3131+2732 db, err := db.Setup(c.Server.DBPath)
2833 if err != nil {
2934 log.Fatalf("failed to setup db: %s", err)
+2
knotserver/config/config.go
···1717 Port int `env:"PORT, default=5555"`
1818 Secret string `env:"SECRET, required"`
1919 DBPath string `env:"DB_PATH, default=knotserver.db"`
2020+ // This disables signature verification so use with caution.
2121+ Dev bool `env:"DEV, default=false"`
2022}
21232224type Config struct {
+6-8
knotserver/db/init.go
···1717 }
18181919 _, err = db.Exec(`
2020+ create table if not exists known_dids (
2121+ did text primary key
2222+ );
2023 create table if not exists public_keys (
2124 id integer primary key autoincrement,
2225 did text not null,
2323- name text not null,
2426 key text not null,
2527 created timestamp default current_timestamp,
2626- unique(did, name, key)
2727- );
2828- create table if not exists users (
2929- id integer primary key autoincrement,
3030- did text not null,
3131- unique(did),
3232- foreign key (did) references public_keys(did) on delete cascade
2828+ unique(did, key),
2929+ foreign key (did) references known_dids(did) on delete cascade
3330 );
3131+3432 create table if not exists repos (
3533 id integer primary key autoincrement,
3634 did text not null,
+44
knotserver/db/known_dids.go
···11+package db
22+33+func (d *DB) AddDID(did string) error {
44+ _, err := d.db.Exec(`insert into known_dids (did) values (?)`, did)
55+ return err
66+}
77+88+func (d *DB) RemoveDID(did string) error {
99+ _, err := d.db.Exec(`delete from known_dids where did = ?`, did)
1010+ return err
1111+}
1212+1313+func (d *DB) GetAllDIDs() ([]string, error) {
1414+ var dids []string
1515+1616+ rows, err := d.db.Query(`select did from known_dids`)
1717+ if err != nil {
1818+ return nil, err
1919+ }
2020+ defer rows.Close()
2121+2222+ for rows.Next() {
2323+ var did string
2424+ if err := rows.Scan(&did); err != nil {
2525+ return nil, err
2626+ }
2727+ dids = append(dids, did)
2828+ }
2929+3030+ if err := rows.Err(); err != nil {
3131+ return nil, err
3232+ }
3333+3434+ return dids, nil
3535+}
3636+3737+func (d *DB) HasKnownDIDs() bool {
3838+ var count int
3939+ err := d.db.QueryRow(`select count(*) from known_dids`).Scan(&count)
4040+ if err != nil {
4141+ return false
4242+ }
4343+ return count > 0
4444+}
···11-package db
22-33-func (d *DB) AddUser(did string) error {
44- _, err := d.db.Exec(`insert into users (did) values (?)`, did)
55- return err
66-}
77-88-func (d *DB) RemoveUser(did string) error {
99- _, err := d.db.Exec(`delete from users where did = ?`, did)
1010- return err
1111-}
+17-9
knotserver/handler.go
···3939 return nil, fmt.Errorf("failed to start jetstream: %w", err)
4040 }
41414242- // TODO: close this channel and set h.knotInitialized *only after*
4343- // checking if we have an owner.
4444- close(h.init)
4545- h.knotInitialized = true
4242+ // Check if the knot knows about any DIDs;
4343+ // if it does, it is already initialized and we can repopulate the
4444+ // Jetstream subscriptions.
4545+ dids, err := db.GetAllDIDs()
4646+ if err != nil {
4747+ return nil, fmt.Errorf("failed to get all DIDs: %w", err)
4848+ }
4949+ if len(dids) > 0 {
5050+ h.knotInitialized = true
5151+ close(h.init)
5252+ h.js.UpdateDids(dids)
5353+ }
46544755 r.Get("/", h.Index)
4856 r.Route("/{did}", func(r chi.Router) {
···6775 })
6876 })
69777070- // Create a new repository
7878+ // Create a new repository.
7179 r.Route("/repo", func(r chi.Router) {
7280 r.Use(h.VerifySignature)
7381 r.Put("/new", h.NewRepo)
7482 })
75837676- // Add a new user to the knot
7777- r.With(h.VerifySignature).Put("/user", h.AddUser)
8484+ // Initialize the knot with an owner and public key.
7885 r.With(h.VerifySignature).Post("/init", h.Init)
79868087 // Health check. Used for two-way verification with appview.
8188 r.With(h.VerifySignature).Get("/health", h.Health)
82898383- // All public keys on the knot
9090+ // All public keys on the knot.
8491 r.Get("/keys", h.Keys)
85928693 return r, nil
···117124 record := commit["record"].(map[string]interface{})
118125 if err := h.db.AddPublicKeyFromRecord(did, record); err != nil {
119126 log.Printf("failed to add public key: %v", err)
127127+ } else {
128128+ log.Printf("added public key from firehose: %s", data["did"])
120129 }
121121- log.Printf("added public key from firehose: %s", data["did"])
122130 default:
123131 }
124132 }
+3
knotserver/middleware.go
···1010)
11111212func (h *Handle) VerifySignature(next http.Handler) http.Handler {
1313+ if h.c.Server.Dev {
1414+ return next
1515+ }
1316 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1417 signature := r.Header.Get("X-Signature")
1518 log.Println(signature)
+18-36
knotserver/routes.go
···391391 w.WriteHeader(http.StatusNoContent)
392392}
393393394394-func (h *Handle) AddUser(w http.ResponseWriter, r *http.Request) {
394394+// TODO: make this set the initial user as the owner
395395+func (h *Handle) Init(w http.ResponseWriter, r *http.Request) {
396396+ if h.knotInitialized {
397397+ writeError(w, "knot already initialized", http.StatusConflict)
398398+ return
399399+ }
400400+395401 data := struct {
396402 DID string `json:"did"`
397397- PublicKey string `json:"pubkey"`
403403+ PublicKey string `json:"key"`
404404+ Created string `json:"created"`
398405 }{}
399406400407 if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
···404411405412 did := data.DID
406413 key := data.PublicKey
414414+ created := data.Created
407415408408- if err := h.db.AddUser(did); err == nil {
409409- pk := db.PublicKey{
410410- Did: did,
411411- }
412412- pk.Key = key
413413- pk.Name = "default"
414414- err := h.db.AddPublicKey(pk)
415415- if err != nil {
416416- writeError(w, err.Error(), http.StatusInternalServerError)
417417- return
418418- }
419419- } else {
420420- writeError(w, err.Error(), http.StatusInternalServerError)
416416+ if did == "" {
417417+ writeError(w, "did is empty", http.StatusBadRequest)
421418 return
422419 }
423420424424- h.js.UpdateDids([]string{did})
425425-426426- w.WriteHeader(http.StatusNoContent)
427427-}
428428-429429-// TODO: make this set the initial user as the owner
430430-func (h *Handle) Init(w http.ResponseWriter, r *http.Request) {
431431- if h.knotInitialized {
432432- writeError(w, "knot already initialized", http.StatusConflict)
421421+ if key == "" {
422422+ writeError(w, "key is empty", http.StatusBadRequest)
433423 return
434424 }
435425436436- data := struct {
437437- DID string `json:"did"`
438438- PublicKey string `json:"pubkey"`
439439- }{}
440440-441441- if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
442442- writeError(w, "invalid request body", http.StatusBadRequest)
426426+ if created == "" {
427427+ writeError(w, "created timestamp is empty", http.StatusBadRequest)
443428 return
444429 }
445430446446- did := data.DID
447447- key := data.PublicKey
448448-449449- if err := h.db.AddUser(did); err == nil {
431431+ if err := h.db.AddDID(did); err == nil {
450432 pk := db.PublicKey{
451433 Did: did,
452434 }
453435 pk.Key = key
454454- pk.Name = "default"
436436+ pk.Created = created
455437 err := h.db.AddPublicKey(pk)
456438 if err != nil {
457439 writeError(w, err.Error(), http.StatusInternalServerError)