Live video on the AT Protocol
1package statedb
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "os"
8
9 "github.com/lestrrat-go/jwx/v2/jwk"
10 oauth_helpers "github.com/streamplace/atproto-oauth-golang/helpers"
11 "stream.place/streamplace/pkg/log"
12)
13
14func (state *StatefulDB) EnsureJWK(ctx context.Context, name string) (jwk.Key, error) {
15 var key jwk.Key
16
17 conf, err := state.GetConfig(name)
18 if err != nil {
19 return nil, err
20 }
21
22 // happy path: we found the jwk in the database, use that
23 if conf != nil {
24 key, err = jwk.ParseKey(conf.Value)
25 if err != nil {
26 return nil, err
27 }
28 return key, nil
29 }
30
31 // migration path: maybe we have an old one on disk.
32 key, _ = state.getOldJWK(ctx, name)
33
34 // new path: found neither, generate a new one
35 if key == nil {
36 log.Warn(ctx, "no JWK found, generating new one", "name", name)
37 key, err = oauth_helpers.GenerateKey(nil)
38 if err != nil {
39 return nil, fmt.Errorf("failed to generate JWK: %w", err)
40 }
41 }
42
43 b, err := json.Marshal(key)
44 if err != nil {
45 return nil, fmt.Errorf("failed to marshal JWK: %w", err)
46 }
47 err = state.PutConfig(name, b)
48 if err != nil {
49 return nil, fmt.Errorf("failed to save JWK: %w", err)
50 }
51
52 return key, nil
53}
54
55// migration for the old one we stored on disk
56func (state *StatefulDB) getOldJWK(ctx context.Context, name string) (jwk.Key, error) {
57 var key jwk.Key
58 jwkPath := state.CLI.DataFilePath([]string{name + ".json"})
59 _, err := os.Stat(jwkPath)
60 if err == nil {
61 b, err := os.ReadFile(jwkPath)
62 if err != nil {
63 return nil, err
64 }
65 key, err = jwk.ParseKey(b)
66 if err != nil {
67 return nil, err
68 }
69 log.Warn(ctx, "found old JWK on disk, migrating to stateful database", "path", jwkPath)
70 return key, nil
71 }
72 return nil, nil
73}