+7
cmd/cocoon/main.go
+7
cmd/cocoon/main.go
···
9
9
"os"
10
10
"time"
11
11
12
+
"github.com/bluesky-social/go-util/pkg/telemetry"
12
13
"github.com/bluesky-social/indigo/atproto/atcrypto"
13
14
"github.com/bluesky-social/indigo/atproto/syntax"
14
15
"github.com/haileyok/cocoon/internal/helpers"
···
154
155
Name: "fallback-proxy",
155
156
EnvVars: []string{"COCOON_FALLBACK_PROXY"},
156
157
},
158
+
telemetry.CLIFlagDebug,
159
+
telemetry.CLIFlagMetricsListenAddress,
157
160
},
158
161
Commands: []*cli.Command{
159
162
runServe,
···
177
180
Flags: []cli.Flag{},
178
181
Action: func(cmd *cli.Context) error {
179
182
183
+
logger := telemetry.StartLogger(cmd)
184
+
telemetry.StartMetrics(cmd)
185
+
180
186
s, err := server.New(&server.Args{
187
+
Logger: logger,
181
188
Addr: cmd.String("addr"),
182
189
DbName: cmd.String("db-name"),
183
190
DbType: cmd.String("db-type"),
+18
-16
go.mod
+18
-16
go.mod
···
1
1
module github.com/haileyok/cocoon
2
2
3
-
go 1.24.1
3
+
go 1.24.5
4
4
5
5
require (
6
6
github.com/Azure/go-autorest/autorest/to v0.4.1
7
7
github.com/aws/aws-sdk-go v1.55.7
8
+
github.com/bluesky-social/go-util v0.0.0-20251012040650-2ebbf57f5934
8
9
github.com/bluesky-social/indigo v0.0.0-20251009212240-20524de167fe
9
10
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792
10
11
github.com/domodwyer/mailyak/v3 v3.6.2
11
12
github.com/go-pkgz/expirable-cache/v3 v3.0.0
12
13
github.com/go-playground/validator v9.31.0+incompatible
13
14
github.com/golang-jwt/jwt/v4 v4.5.2
14
-
github.com/google/uuid v1.4.0
15
+
github.com/google/uuid v1.6.0
15
16
github.com/gorilla/sessions v1.4.0
16
17
github.com/gorilla/websocket v1.5.1
17
18
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
···
24
25
github.com/joho/godotenv v1.5.1
25
26
github.com/labstack/echo-contrib v0.17.4
26
27
github.com/labstack/echo/v4 v4.13.3
27
-
github.com/lestrrat-go/jwx/v2 v2.0.12
28
+
github.com/lestrrat-go/jwx/v2 v2.0.21
28
29
github.com/multiformats/go-multihash v0.2.3
30
+
github.com/prometheus/client_golang v1.23.2
29
31
github.com/samber/slog-echo v1.16.1
30
32
github.com/urfave/cli/v2 v2.27.6
31
33
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e
32
34
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b
33
-
golang.org/x/crypto v0.38.0
35
+
golang.org/x/crypto v0.41.0
34
36
gorm.io/driver/postgres v1.5.7
35
37
gorm.io/driver/sqlite v1.5.7
36
38
gorm.io/gorm v1.25.12
···
57
59
github.com/gorilla/securecookie v1.1.2 // indirect
58
60
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
59
61
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
60
-
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
62
+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
61
63
github.com/hashicorp/golang-lru v1.0.2 // indirect
62
64
github.com/ipfs/bbloom v0.0.4 // indirect
63
65
github.com/ipfs/go-blockservice v0.5.2 // indirect
···
77
79
github.com/ipld/go-ipld-prime v0.21.0 // indirect
78
80
github.com/jackc/pgpassfile v1.0.0 // indirect
79
81
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
80
-
github.com/jackc/pgx/v5 v5.5.0 // indirect
82
+
github.com/jackc/pgx/v5 v5.5.4 // indirect
81
83
github.com/jackc/puddle/v2 v2.2.1 // indirect
82
84
github.com/jbenet/goprocess v0.1.4 // indirect
83
85
github.com/jinzhu/inflection v1.0.0 // indirect
···
86
88
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
87
89
github.com/labstack/gommon v0.4.2 // indirect
88
90
github.com/leodido/go-urn v1.4.0 // indirect
89
-
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
91
+
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
90
92
github.com/lestrrat-go/httpcc v1.0.1 // indirect
91
-
github.com/lestrrat-go/httprc v1.0.4 // indirect
93
+
github.com/lestrrat-go/httprc v1.0.5 // indirect
92
94
github.com/lestrrat-go/iter v1.0.2 // indirect
93
95
github.com/lestrrat-go/option v1.0.1 // indirect
94
96
github.com/mattn/go-colorable v0.1.14 // indirect
···
103
105
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
104
106
github.com/opentracing/opentracing-go v1.2.0 // indirect
105
107
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
106
-
github.com/prometheus/client_golang v1.22.0 // indirect
107
108
github.com/prometheus/client_model v0.6.2 // indirect
108
-
github.com/prometheus/common v0.63.0 // indirect
109
+
github.com/prometheus/common v0.66.1 // indirect
109
110
github.com/prometheus/procfs v0.16.1 // indirect
110
111
github.com/russross/blackfriday/v2 v2.1.0 // indirect
111
112
github.com/samber/lo v1.49.1 // indirect
···
115
116
github.com/valyala/fasttemplate v1.2.2 // indirect
116
117
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
117
118
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
118
-
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
119
+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
119
120
go.opentelemetry.io/otel v1.29.0 // indirect
120
121
go.opentelemetry.io/otel/metric v1.29.0 // indirect
121
122
go.opentelemetry.io/otel/trace v1.29.0 // indirect
122
123
go.uber.org/atomic v1.11.0 // indirect
123
124
go.uber.org/multierr v1.11.0 // indirect
124
125
go.uber.org/zap v1.26.0 // indirect
125
-
golang.org/x/net v0.40.0 // indirect
126
-
golang.org/x/sync v0.14.0 // indirect
127
-
golang.org/x/sys v0.33.0 // indirect
128
-
golang.org/x/text v0.25.0 // indirect
126
+
go.yaml.in/yaml/v2 v2.4.2 // indirect
127
+
golang.org/x/net v0.43.0 // indirect
128
+
golang.org/x/sync v0.16.0 // indirect
129
+
golang.org/x/sys v0.35.0 // indirect
130
+
golang.org/x/text v0.28.0 // indirect
129
131
golang.org/x/time v0.11.0 // indirect
130
132
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
131
-
google.golang.org/protobuf v1.36.6 // indirect
133
+
google.golang.org/protobuf v1.36.9 // indirect
132
134
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
133
135
gopkg.in/inf.v0 v0.9.1 // indirect
134
136
lukechampine.com/blake3 v1.2.1 // indirect
+50
-74
go.sum
+50
-74
go.sum
···
16
16
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
17
17
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
18
18
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
19
+
github.com/bluesky-social/go-util v0.0.0-20251012040650-2ebbf57f5934 h1:btHMur2kTRgWEnCHn6LaI3BE9YRgsqTpwpJ1UdB7VEk=
20
+
github.com/bluesky-social/go-util v0.0.0-20251012040650-2ebbf57f5934/go.mod h1:LWamyZfbQGW7PaVc5jumFfjgrshJ5mXgDUnR6fK7+BI=
19
21
github.com/bluesky-social/indigo v0.0.0-20251009212240-20524de167fe h1:VBhaqE5ewQgXbY5SfSWFZC/AwHFo7cHxZKFYi2ce9Yo=
20
22
github.com/bluesky-social/indigo v0.0.0-20251009212240-20524de167fe/go.mod h1:RuQVrCGm42QNsgumKaR6se+XkFKfCPNwdCiTvqKRUck=
21
23
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
···
34
36
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35
37
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
36
38
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
37
-
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
38
39
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
39
40
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
40
41
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
41
42
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
43
+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
44
+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
42
45
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
43
46
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
44
47
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
···
77
80
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
78
81
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
79
82
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
80
-
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
81
-
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
83
+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
84
+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
82
85
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
83
86
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
84
87
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
···
95
98
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0=
96
99
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
97
100
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
98
-
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
99
-
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
100
-
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
101
-
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
101
+
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
102
+
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
103
+
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
104
+
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
102
105
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
103
106
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
104
107
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
···
172
175
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
173
176
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
174
177
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
175
-
github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
176
-
github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
178
+
github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
179
+
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
177
180
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
178
181
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
179
182
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
···
195
198
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
196
199
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
197
200
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
201
+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
202
+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
198
203
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
199
204
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
200
205
github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8=
···
206
211
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
207
212
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
208
213
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
214
+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
215
+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
209
216
github.com/labstack/echo-contrib v0.17.4 h1:g5mfsrJfJTKv+F5uNKCyrjLK7js+ZW6HTjg4FnDxxgk=
210
217
github.com/labstack/echo-contrib v0.17.4/go.mod h1:9O7ZPAHUeMGTOAfg80YqQduHzt0CzLak36PZRldYrZ0=
211
218
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
···
214
221
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
215
222
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
216
223
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
217
-
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
218
-
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
224
+
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
225
+
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
219
226
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
220
227
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
221
-
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
222
-
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
228
+
github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk=
229
+
github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
223
230
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
224
231
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
225
-
github.com/lestrrat-go/jwx/v2 v2.0.12 h1:3d589+5w/b9b7S3DneICPW16AqTyYXB7VRjgluSDWeA=
226
-
github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G/0y2qUjAQuQ=
227
-
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
232
+
github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0=
233
+
github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM=
228
234
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
229
235
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
230
236
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
···
289
295
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
290
296
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
291
297
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
292
-
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
293
-
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
298
+
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
299
+
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
294
300
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
295
301
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
296
-
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
297
-
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
302
+
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
303
+
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
298
304
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
299
305
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
300
306
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
···
317
323
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
318
324
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
319
325
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
320
-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
321
-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
322
-
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
323
326
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
324
327
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
325
328
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
326
329
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
327
330
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
328
-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
329
-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
330
-
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
331
-
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
331
+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
332
+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
332
333
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
333
334
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
334
335
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
···
349
350
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
350
351
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
351
352
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
352
-
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
353
353
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
354
354
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
355
355
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
356
356
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
357
-
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
358
-
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
357
+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
358
+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
359
359
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
360
360
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
361
361
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
···
367
367
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
368
368
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
369
369
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
370
-
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
371
-
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
370
+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
371
+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
372
372
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
373
373
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
374
374
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
···
378
378
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
379
379
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
380
380
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
381
+
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
382
+
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
381
383
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
382
384
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
383
385
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
384
386
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
385
-
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
386
-
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
387
-
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
388
-
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
387
+
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
388
+
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
389
389
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
390
390
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
391
391
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
···
393
393
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
394
394
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
395
395
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
396
-
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
397
-
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
398
-
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
399
-
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
396
+
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
397
+
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
400
398
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
401
399
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
402
400
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
403
401
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
404
402
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
405
-
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
406
403
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
407
-
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
408
-
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
409
-
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
410
-
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
411
-
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
404
+
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
405
+
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
412
406
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
413
407
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
414
408
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
415
409
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
416
-
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
417
-
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
418
-
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
419
-
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
410
+
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
411
+
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
420
412
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
421
413
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
422
414
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
423
415
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
424
416
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
425
417
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
426
-
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
427
418
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
428
-
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
429
-
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
430
-
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
431
419
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
432
420
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
433
-
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
434
-
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
435
-
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
436
-
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
421
+
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
422
+
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
437
423
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
438
-
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
439
-
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
440
-
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
441
-
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
442
424
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
443
425
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
444
-
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
445
-
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
446
-
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
447
-
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
448
-
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
449
-
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
426
+
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
427
+
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
450
428
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
451
429
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
452
430
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
···
459
437
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
460
438
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
461
439
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
462
-
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
463
-
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
464
-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
465
-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
440
+
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
441
+
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
466
442
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
467
443
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
468
444
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
469
445
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
470
446
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
471
447
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
472
-
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
473
-
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
448
+
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
449
+
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
474
450
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
475
451
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
476
452
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+3
-21
internal/db/db.go
+3
-21
internal/db/db.go
···
2
2
3
3
import (
4
4
"context"
5
-
"sync"
6
5
7
6
"gorm.io/gorm"
8
7
"gorm.io/gorm/clause"
···
10
9
11
10
type DB struct {
12
11
cli *gorm.DB
13
-
mu sync.Mutex
14
12
}
15
13
16
14
func NewDB(cli *gorm.DB) *DB {
17
15
return &DB{
18
16
cli: cli,
19
-
mu: sync.Mutex{},
20
17
}
21
18
}
22
19
23
20
func (db *DB) Create(ctx context.Context, value any, clauses []clause.Expression) *gorm.DB {
24
-
db.mu.Lock()
25
-
defer db.mu.Unlock()
26
21
return db.cli.WithContext(ctx).Clauses(clauses...).Create(value)
27
22
}
28
23
29
24
func (db *DB) Save(ctx context.Context, value any, clauses []clause.Expression) *gorm.DB {
30
-
db.mu.Lock()
31
-
defer db.mu.Unlock()
32
25
return db.cli.WithContext(ctx).Clauses(clauses...).Save(value)
33
26
}
34
27
35
28
func (db *DB) Exec(ctx context.Context, sql string, clauses []clause.Expression, values ...any) *gorm.DB {
36
-
db.mu.Lock()
37
-
defer db.mu.Unlock()
38
29
return db.cli.WithContext(ctx).Clauses(clauses...).Exec(sql, values...)
39
30
}
40
31
···
47
38
}
48
39
49
40
func (db *DB) Delete(ctx context.Context, value any, clauses []clause.Expression) *gorm.DB {
50
-
db.mu.Lock()
51
-
defer db.mu.Unlock()
52
41
return db.cli.WithContext(ctx).Clauses(clauses...).Delete(value)
53
42
}
54
43
···
56
45
return db.cli.WithContext(ctx).First(dest, conds...)
57
46
}
58
47
59
-
// TODO: this isn't actually good. we can commit even if the db is locked here. this is probably okay for the time being, but need to figure
60
-
// out a better solution. right now we only do this whenever we're importing a repo though so i'm mostly not worried, but it's still bad.
61
-
// e.g. when we do apply writes we should also be using a transcation but we don't right now
62
-
func (db *DB) BeginDangerously(ctx context.Context) *gorm.DB {
48
+
func (db *DB) Begin(ctx context.Context) *gorm.DB {
63
49
return db.cli.WithContext(ctx).Begin()
64
50
}
65
51
66
-
func (db *DB) Lock() {
67
-
db.mu.Lock()
68
-
}
69
-
70
-
func (db *DB) Unlock() {
71
-
db.mu.Unlock()
52
+
func (db *DB) Client() *gorm.DB {
53
+
return db.cli
72
54
}
+30
metrics/metrics.go
+30
metrics/metrics.go
···
1
+
package metrics
2
+
3
+
import (
4
+
"github.com/prometheus/client_golang/prometheus"
5
+
"github.com/prometheus/client_golang/prometheus/promauto"
6
+
)
7
+
8
+
const (
9
+
NAMESPACE = "cocoon"
10
+
)
11
+
12
+
var (
13
+
RelaysConnected = promauto.NewGaugeVec(prometheus.GaugeOpts{
14
+
Namespace: NAMESPACE,
15
+
Name: "relays_connected",
16
+
Help: "number of connected relays, by host",
17
+
}, []string{"host"})
18
+
19
+
RelaySends = promauto.NewCounterVec(prometheus.CounterOpts{
20
+
Namespace: NAMESPACE,
21
+
Name: "relay_sends",
22
+
Help: "number of events sent to a relay, by host",
23
+
}, []string{"host", "kind"})
24
+
25
+
RepoOperations = promauto.NewCounterVec(prometheus.CounterOpts{
26
+
Namespace: NAMESPACE,
27
+
Name: "repo_operations",
28
+
Help: "number of operations made against repos",
29
+
}, []string{"kind"})
30
+
)
+12
-2
models/models.go
+12
-2
models/models.go
···
8
8
"github.com/bluesky-social/indigo/atproto/atcrypto"
9
9
)
10
10
11
+
type TwoFactorType string
12
+
13
+
var (
14
+
TwoFactorTypeNone = TwoFactorType("none")
15
+
TwoFactorTypeEmail = TwoFactorType("email")
16
+
)
17
+
11
18
type Repo struct {
12
19
Did string `gorm:"primaryKey"`
13
20
CreatedAt time.Time
···
29
36
Root []byte
30
37
Preferences []byte
31
38
Deactivated bool
39
+
TwoFactorCode *string
40
+
TwoFactorCodeExpiresAt *time.Time
41
+
TwoFactorType TwoFactorType `gorm:"default:none"`
32
42
}
33
43
34
44
func (r *Repo) SignFor(ctx context.Context, did string, msg []byte) ([]byte, error) {
···
121
131
}
122
132
123
133
type ReservedKey struct {
124
-
KeyDid string `gorm:"primaryKey"`
125
-
Did *string `gorm:"index"`
134
+
KeyDid string `gorm:"primaryKey"`
135
+
Did *string `gorm:"index"`
126
136
PrivateKey []byte
127
137
CreatedAt time.Time `gorm:"index"`
128
138
}
+1
-1
oauth/dpop/jti_cache.go
+1
-1
oauth/dpop/jti_cache.go
···
14
14
}
15
15
16
16
func newJTICache(size int) *jtiCache {
17
-
cache := cache.NewCache[string, bool]().WithTTL(24 * time.Hour).WithLRU().WithTTL(constants.JTITtl)
17
+
cache := cache.NewCache[string, bool]().WithTTL(24 * time.Hour).WithLRU().WithTTL(constants.JTITtl).WithMaxKeys(size)
18
18
return &jtiCache{
19
19
cache: cache,
20
20
mu: sync.Mutex{},
+4
-4
oauth/dpop/manager.go
+4
-4
oauth/dpop/manager.go
···
75
75
}
76
76
77
77
proof := extractProof(headers)
78
-
79
78
if proof == "" {
80
79
return nil, nil
81
80
}
···
197
196
198
197
nonce, _ := claims["nonce"].(string)
199
198
if nonce == "" {
200
-
// WARN: this _must_ be `use_dpop_nonce` for clients know they should make another request
199
+
// reference impl checks if self.nonce is not null before returning an error, but we always have a
200
+
// nonce so we do not bother checking
201
201
return nil, ErrUseDpopNonce
202
202
}
203
203
204
204
if nonce != "" && !dm.nonce.Check(nonce) {
205
-
// WARN: this _must_ be `use_dpop_nonce` so that clients will fetch a new nonce
205
+
// dpop nonce mismatch
206
206
return nil, ErrUseDpopNonce
207
207
}
208
208
···
237
237
}
238
238
239
239
func extractProof(headers http.Header) string {
240
-
dpopHeaders := headers["Dpop"]
240
+
dpopHeaders := headers.Values("dpop")
241
241
switch len(dpopHeaders) {
242
242
case 0:
243
243
return ""
+3
-3
oauth/provider/client_auth.go
+3
-3
oauth/provider/client_auth.go
···
19
19
}
20
20
21
21
type AuthenticateClientRequestBase struct {
22
-
ClientID string `form:"client_id" json:"client_id" validate:"required"`
23
-
ClientAssertionType *string `form:"client_assertion_type" json:"client_assertion_type,omitempty"`
24
-
ClientAssertion *string `form:"client_assertion" json:"client_assertion,omitempty"`
22
+
ClientID string `form:"client_id" json:"client_id" query:"client_id" validate:"required"`
23
+
ClientAssertionType *string `form:"client_assertion_type" json:"client_assertion_type,omitempty" query:"client_assertion_type"`
24
+
ClientAssertion *string `form:"client_assertion" json:"client_assertion,omitempty" query:"client_assertion"`
25
25
}
26
26
27
27
func (p *Provider) AuthenticateClient(ctx context.Context, req AuthenticateClientRequestBase, proof *dpop.Proof, opts *AuthenticateClientOptions) (*client.Client, *ClientAuth, error) {
+9
-8
oauth/provider/models.go
+9
-8
oauth/provider/models.go
···
32
32
33
33
type ParRequest struct {
34
34
AuthenticateClientRequestBase
35
-
ResponseType string `form:"response_type" json:"response_type" validate:"required"`
36
-
CodeChallenge *string `form:"code_challenge" json:"code_challenge" validate:"required"`
37
-
CodeChallengeMethod string `form:"code_challenge_method" json:"code_challenge_method" validate:"required"`
38
-
State string `form:"state" json:"state" validate:"required"`
39
-
RedirectURI string `form:"redirect_uri" json:"redirect_uri" validate:"required"`
40
-
Scope string `form:"scope" json:"scope" validate:"required"`
41
-
LoginHint *string `form:"login_hint" json:"login_hint,omitempty"`
42
-
DpopJkt *string `form:"dpop_jkt" json:"dpop_jkt,omitempty"`
35
+
ResponseType string `form:"response_type" json:"response_type" query:"response_type" validate:"required"`
36
+
CodeChallenge *string `form:"code_challenge" json:"code_challenge" query:"code_challenge" validate:"required"`
37
+
CodeChallengeMethod string `form:"code_challenge_method" json:"code_challenge_method" query:"code_challenge_method" validate:"required"`
38
+
State string `form:"state" json:"state" query:"state" validate:"required"`
39
+
RedirectURI string `form:"redirect_uri" json:"redirect_uri" query:"redirect_uri" validate:"required"`
40
+
Scope string `form:"scope" json:"scope" query:"scope" validate:"required"`
41
+
LoginHint *string `form:"login_hint" query:"login_hint" json:"login_hint,omitempty"`
42
+
DpopJkt *string `form:"dpop_jkt" query:"dpop_jkt" json:"dpop_jkt,omitempty"`
43
+
ResponseMode *string `form:"response_mode" json:"response_mode,omitempty" query:"response_mode"`
43
44
}
44
45
45
46
func (opr *ParRequest) Scan(value any) error {
+2
-1
server/handle_account.go
+2
-1
server/handle_account.go
···
12
12
13
13
func (s *Server) handleAccount(e echo.Context) error {
14
14
ctx := e.Request().Context()
15
+
logger := s.logger.With("name", "handleAuth")
15
16
16
17
repo, sess, err := s.getSessionRepoOrErr(e)
17
18
if err != nil {
···
22
23
23
24
var tokens []provider.OauthToken
24
25
if err := s.db.Raw(ctx, "SELECT * FROM oauth_tokens WHERE sub = ? AND created_at < ? ORDER BY created_at ASC", nil, repo.Repo.Did, oldestPossibleSession).Scan(&tokens).Error; err != nil {
25
-
s.logger.Error("couldnt fetch oauth sessions for account", "did", repo.Repo.Did, "error", err)
26
+
logger.Error("couldnt fetch oauth sessions for account", "did", repo.Repo.Did, "error", err)
26
27
sess.AddFlash("Unable to fetch sessions. See server logs for more details.", "error")
27
28
sess.Save(e.Request(), e.Response())
28
29
return e.Render(200, "account.html", map[string]any{
+3
-2
server/handle_account_revoke.go
+3
-2
server/handle_account_revoke.go
···
11
11
12
12
func (s *Server) handleAccountRevoke(e echo.Context) error {
13
13
ctx := e.Request().Context()
14
+
logger := s.logger.With("name", "handleAcocuntRevoke")
14
15
15
16
var req AccountRevokeInput
16
17
if err := e.Bind(&req); err != nil {
17
-
s.logger.Error("could not bind account revoke request", "error", err)
18
+
logger.Error("could not bind account revoke request", "error", err)
18
19
return helpers.ServerError(e, nil)
19
20
}
20
21
···
24
25
}
25
26
26
27
if err := s.db.Exec(ctx, "DELETE FROM oauth_tokens WHERE sub = ? AND token = ?", nil, repo.Repo.Did, req.Token).Error; err != nil {
27
-
s.logger.Error("couldnt delete oauth session for account", "did", repo.Repo.Did, "token", req.Token, "error", err)
28
+
logger.Error("couldnt delete oauth session for account", "did", repo.Repo.Did, "token", req.Token, "error", err)
28
29
sess.AddFlash("Unable to revoke session. See server logs for more details.", "error")
29
30
sess.Save(e.Request(), e.Response())
30
31
return e.Redirect(303, "/account")
+58
-10
server/handle_account_signin.go
+58
-10
server/handle_account_signin.go
···
2
2
3
3
import (
4
4
"errors"
5
+
"fmt"
5
6
"strings"
7
+
"time"
6
8
7
9
"github.com/bluesky-social/indigo/atproto/syntax"
8
10
"github.com/gorilla/sessions"
···
15
17
)
16
18
17
19
type OauthSigninInput struct {
18
-
Username string `form:"username"`
19
-
Password string `form:"password"`
20
-
QueryParams string `form:"query_params"`
20
+
Username string `form:"username"`
21
+
Password string `form:"password"`
22
+
AuthFactorToken string `form:"token"`
23
+
QueryParams string `form:"query_params"`
21
24
}
22
25
23
26
func (s *Server) getSessionRepoOrErr(e echo.Context) (*models.RepoActor, *sessions.Session, error) {
···
44
47
func getFlashesFromSession(e echo.Context, sess *sessions.Session) map[string]any {
45
48
defer sess.Save(e.Request(), e.Response())
46
49
return map[string]any{
47
-
"errors": sess.Flashes("error"),
48
-
"successes": sess.Flashes("success"),
50
+
"errors": sess.Flashes("error"),
51
+
"successes": sess.Flashes("success"),
52
+
"tokenrequired": sess.Flashes("tokenrequired"),
49
53
}
50
54
}
51
55
···
63
67
64
68
func (s *Server) handleAccountSigninPost(e echo.Context) error {
65
69
ctx := e.Request().Context()
70
+
logger := s.logger.With("name", "handleAccountSigninPost")
66
71
67
72
var req OauthSigninInput
68
73
if err := e.Bind(&req); err != nil {
69
-
s.logger.Error("error binding sign in req", "error", err)
74
+
logger.Error("error binding sign in req", "error", err)
70
75
return helpers.ServerError(e, nil)
71
76
}
72
77
···
82
87
idtype = "email"
83
88
}
84
89
90
+
queryParams := ""
91
+
if req.QueryParams != "" {
92
+
queryParams = fmt.Sprintf("?%s", req.QueryParams)
93
+
}
94
+
85
95
// TODO: we should make this a helper since we do it for the base create_session as well
86
96
var repo models.RepoActor
87
97
var err error
···
100
110
sess.AddFlash("Something went wrong!", "error")
101
111
}
102
112
sess.Save(e.Request(), e.Response())
103
-
return e.Redirect(303, "/account/signin")
113
+
return e.Redirect(303, "/account/signin"+queryParams)
104
114
}
105
115
106
116
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
···
110
120
sess.AddFlash("Something went wrong!", "error")
111
121
}
112
122
sess.Save(e.Request(), e.Response())
113
-
return e.Redirect(303, "/account/signin")
123
+
return e.Redirect(303, "/account/signin"+queryParams)
124
+
}
125
+
126
+
// if repo requires 2FA token and one hasn't been provided, return error prompting for one
127
+
if repo.TwoFactorType != models.TwoFactorTypeNone && req.AuthFactorToken == "" {
128
+
err = s.createAndSendTwoFactorCode(ctx, repo)
129
+
if err != nil {
130
+
sess.AddFlash("Something went wrong!", "error")
131
+
sess.Save(e.Request(), e.Response())
132
+
return e.Redirect(303, "/account/signin"+queryParams)
133
+
}
134
+
135
+
sess.AddFlash("requires 2FA token", "tokenrequired")
136
+
sess.Save(e.Request(), e.Response())
137
+
return e.Redirect(303, "/account/signin"+queryParams)
138
+
}
139
+
140
+
// if 2FAis required, now check that the one provided is valid
141
+
if repo.TwoFactorType != models.TwoFactorTypeNone {
142
+
if repo.TwoFactorCode == nil || repo.TwoFactorCodeExpiresAt == nil {
143
+
err = s.createAndSendTwoFactorCode(ctx, repo)
144
+
if err != nil {
145
+
sess.AddFlash("Something went wrong!", "error")
146
+
sess.Save(e.Request(), e.Response())
147
+
return e.Redirect(303, "/account/signin"+queryParams)
148
+
}
149
+
150
+
sess.AddFlash("requires 2FA token", "tokenrequired")
151
+
sess.Save(e.Request(), e.Response())
152
+
return e.Redirect(303, "/account/signin"+queryParams)
153
+
}
154
+
155
+
if *repo.TwoFactorCode != req.AuthFactorToken {
156
+
return helpers.InvalidTokenError(e)
157
+
}
158
+
159
+
if time.Now().UTC().After(*repo.TwoFactorCodeExpiresAt) {
160
+
return helpers.ExpiredTokenError(e)
161
+
}
114
162
}
115
163
116
164
sess.Options = &sessions.Options{
···
126
174
return err
127
175
}
128
176
129
-
if req.QueryParams != "" {
130
-
return e.Redirect(303, "/oauth/authorize?"+req.QueryParams)
177
+
if queryParams != "" {
178
+
return e.Redirect(303, "/oauth/authorize"+queryParams)
131
179
} else {
132
180
return e.Redirect(303, "/account")
133
181
}
+4
-2
server/handle_identity_get_recommended_did_credentials.go
+4
-2
server/handle_identity_get_recommended_did_credentials.go
···
8
8
)
9
9
10
10
func (s *Server) handleGetRecommendedDidCredentials(e echo.Context) error {
11
+
logger := s.logger.With("name", "handleIdentityGetRecommendedDidCredentials")
12
+
11
13
repo := e.Get("repo").(*models.RepoActor)
12
14
k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey)
13
15
if err != nil {
14
-
s.logger.Error("error parsing key", "error", err)
16
+
logger.Error("error parsing key", "error", err)
15
17
return helpers.ServerError(e, nil)
16
18
}
17
19
creds, err := s.plcClient.CreateDidCredentials(k, "", repo.Actor.Handle)
18
20
if err != nil {
19
-
s.logger.Error("error crating did credentials", "error", err)
21
+
logger.Error("error crating did credentials", "error", err)
20
22
return helpers.ServerError(e, nil)
21
23
}
22
24
+3
-2
server/handle_identity_request_plc_operation.go
+3
-2
server/handle_identity_request_plc_operation.go
···
11
11
12
12
func (s *Server) handleIdentityRequestPlcOperationSignature(e echo.Context) error {
13
13
ctx := e.Request().Context()
14
+
logger := s.logger.With("name", "handleIdentityRequestPlcOperationSignature")
14
15
15
16
urepo := e.Get("repo").(*models.RepoActor)
16
17
···
18
19
eat := time.Now().Add(10 * time.Minute).UTC()
19
20
20
21
if err := s.db.Exec(ctx, "UPDATE repos SET plc_operation_code = ?, plc_operation_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil {
21
-
s.logger.Error("error updating user", "error", err)
22
+
logger.Error("error updating user", "error", err)
22
23
return helpers.ServerError(e, nil)
23
24
}
24
25
25
26
if err := s.sendPlcTokenReset(urepo.Email, urepo.Handle, code); err != nil {
26
-
s.logger.Error("error sending mail", "error", err)
27
+
logger.Error("error sending mail", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
+7
-5
server/handle_identity_sign_plc_operation.go
+7
-5
server/handle_identity_sign_plc_operation.go
···
27
27
}
28
28
29
29
func (s *Server) handleSignPlcOperation(e echo.Context) error {
30
+
logger := s.logger.With("name", "handleSignPlcOperation")
31
+
30
32
repo := e.Get("repo").(*models.RepoActor)
31
33
32
34
var req ComAtprotoSignPlcOperationRequest
33
35
if err := e.Bind(&req); err != nil {
34
-
s.logger.Error("error binding", "error", err)
36
+
logger.Error("error binding", "error", err)
35
37
return helpers.ServerError(e, nil)
36
38
}
37
39
···
54
56
ctx := context.WithValue(e.Request().Context(), "skip-cache", true)
55
57
log, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did)
56
58
if err != nil {
57
-
s.logger.Error("error fetching doc", "error", err)
59
+
logger.Error("error fetching doc", "error", err)
58
60
return helpers.ServerError(e, nil)
59
61
}
60
62
···
83
85
84
86
k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey)
85
87
if err != nil {
86
-
s.logger.Error("error parsing signing key", "error", err)
88
+
logger.Error("error parsing signing key", "error", err)
87
89
return helpers.ServerError(e, nil)
88
90
}
89
91
90
92
if err := s.plcClient.SignOp(k, &op); err != nil {
91
-
s.logger.Error("error signing plc operation", "error", err)
93
+
logger.Error("error signing plc operation", "error", err)
92
94
return helpers.ServerError(e, nil)
93
95
}
94
96
95
97
if err := s.db.Exec(ctx, "UPDATE repos SET plc_operation_code = NULL, plc_operation_code_expires_at = NULL WHERE did = ?", nil, repo.Repo.Did).Error; err != nil {
96
-
s.logger.Error("error updating repo", "error", err)
98
+
logger.Error("error updating repo", "error", err)
97
99
return helpers.ServerError(e, nil)
98
100
}
99
101
+6
-4
server/handle_identity_submit_plc_operation.go
+6
-4
server/handle_identity_submit_plc_operation.go
···
21
21
}
22
22
23
23
func (s *Server) handleSubmitPlcOperation(e echo.Context) error {
24
+
logger := s.logger.With("name", "handleIdentitySubmitPlcOperation")
25
+
24
26
repo := e.Get("repo").(*models.RepoActor)
25
27
26
28
var req ComAtprotoSubmitPlcOperationRequest
27
29
if err := e.Bind(&req); err != nil {
28
-
s.logger.Error("error binding", "error", err)
30
+
logger.Error("error binding", "error", err)
29
31
return helpers.ServerError(e, nil)
30
32
}
31
33
···
40
42
41
43
k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey)
42
44
if err != nil {
43
-
s.logger.Error("error parsing key", "error", err)
45
+
logger.Error("error parsing key", "error", err)
44
46
return helpers.ServerError(e, nil)
45
47
}
46
48
required, err := s.plcClient.CreateDidCredentials(k, "", repo.Actor.Handle)
47
49
if err != nil {
48
-
s.logger.Error("error crating did credentials", "error", err)
50
+
logger.Error("error crating did credentials", "error", err)
49
51
return helpers.ServerError(e, nil)
50
52
}
51
53
···
72
74
}
73
75
74
76
if err := s.passport.BustDoc(context.TODO(), repo.Repo.Did); err != nil {
75
-
s.logger.Warn("error busting did doc", "error", err)
77
+
logger.Warn("error busting did doc", "error", err)
76
78
}
77
79
78
80
s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{
+7
-5
server/handle_identity_update_handle.go
+7
-5
server/handle_identity_update_handle.go
···
22
22
}
23
23
24
24
func (s *Server) handleIdentityUpdateHandle(e echo.Context) error {
25
+
logger := s.logger.With("name", "handleIdentityUpdateHandle")
26
+
25
27
repo := e.Get("repo").(*models.RepoActor)
26
28
27
29
var req ComAtprotoIdentityUpdateHandleRequest
28
30
if err := e.Bind(&req); err != nil {
29
-
s.logger.Error("error binding", "error", err)
31
+
logger.Error("error binding", "error", err)
30
32
return helpers.ServerError(e, nil)
31
33
}
32
34
···
41
43
if strings.HasPrefix(repo.Repo.Did, "did:plc:") {
42
44
log, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did)
43
45
if err != nil {
44
-
s.logger.Error("error fetching doc", "error", err)
46
+
logger.Error("error fetching doc", "error", err)
45
47
return helpers.ServerError(e, nil)
46
48
}
47
49
···
68
70
69
71
k, err := atcrypto.ParsePrivateBytesK256(repo.SigningKey)
70
72
if err != nil {
71
-
s.logger.Error("error parsing signing key", "error", err)
73
+
logger.Error("error parsing signing key", "error", err)
72
74
return helpers.ServerError(e, nil)
73
75
}
74
76
···
82
84
}
83
85
84
86
if err := s.passport.BustDoc(context.TODO(), repo.Repo.Did); err != nil {
85
-
s.logger.Warn("error busting did doc", "error", err)
87
+
logger.Warn("error busting did doc", "error", err)
86
88
}
87
89
88
90
s.evtman.AddEvent(context.TODO(), &events.XRPCStreamEvent{
···
95
97
})
96
98
97
99
if err := s.db.Exec(ctx, "UPDATE actors SET handle = ? WHERE did = ?", nil, req.Handle, repo.Repo.Did).Error; err != nil {
98
-
s.logger.Error("error updating handle in db", "error", err)
100
+
logger.Error("error updating handle in db", "error", err)
99
101
return helpers.ServerError(e, nil)
100
102
}
101
103
+12
-11
server/handle_import_repo.go
+12
-11
server/handle_import_repo.go
···
19
19
20
20
func (s *Server) handleRepoImportRepo(e echo.Context) error {
21
21
ctx := e.Request().Context()
22
+
logger := s.logger.With("name", "handleImportRepo")
22
23
23
24
urepo := e.Get("repo").(*models.RepoActor)
24
25
25
26
b, err := io.ReadAll(e.Request().Body)
26
27
if err != nil {
27
-
s.logger.Error("could not read bytes in import request", "error", err)
28
+
logger.Error("could not read bytes in import request", "error", err)
28
29
return helpers.ServerError(e, nil)
29
30
}
30
31
···
32
33
33
34
cs, err := car.NewCarReader(bytes.NewReader(b))
34
35
if err != nil {
35
-
s.logger.Error("could not read car in import request", "error", err)
36
+
logger.Error("could not read car in import request", "error", err)
36
37
return helpers.ServerError(e, nil)
37
38
}
38
39
39
40
orderedBlocks := []blocks.Block{}
40
41
currBlock, err := cs.Next()
41
42
if err != nil {
42
-
s.logger.Error("could not get first block from car", "error", err)
43
+
logger.Error("could not get first block from car", "error", err)
43
44
return helpers.ServerError(e, nil)
44
45
}
45
46
currBlockCt := 1
46
47
47
48
for currBlock != nil {
48
-
s.logger.Info("someone is importing their repo", "block", currBlockCt)
49
+
logger.Info("someone is importing their repo", "block", currBlockCt)
49
50
orderedBlocks = append(orderedBlocks, currBlock)
50
51
next, _ := cs.Next()
51
52
currBlock = next
···
55
56
slices.Reverse(orderedBlocks)
56
57
57
58
if err := bs.PutMany(context.TODO(), orderedBlocks); err != nil {
58
-
s.logger.Error("could not insert blocks", "error", err)
59
+
logger.Error("could not insert blocks", "error", err)
59
60
return helpers.ServerError(e, nil)
60
61
}
61
62
62
63
r, err := repo.OpenRepo(context.TODO(), bs, cs.Header.Roots[0])
63
64
if err != nil {
64
-
s.logger.Error("could not open repo", "error", err)
65
+
logger.Error("could not open repo", "error", err)
65
66
return helpers.ServerError(e, nil)
66
67
}
67
68
68
-
tx := s.db.BeginDangerously(ctx)
69
+
tx := s.db.Begin(ctx)
69
70
70
71
clock := syntax.NewTIDClock(0)
71
72
···
76
77
cidStr := cid.String()
77
78
b, err := bs.Get(context.TODO(), cid)
78
79
if err != nil {
79
-
s.logger.Error("record bytes don't exist in blockstore", "error", err)
80
+
logger.Error("record bytes don't exist in blockstore", "error", err)
80
81
return helpers.ServerError(e, nil)
81
82
}
82
83
···
96
97
return nil
97
98
}); err != nil {
98
99
tx.Rollback()
99
-
s.logger.Error("record bytes don't exist in blockstore", "error", err)
100
+
logger.Error("record bytes don't exist in blockstore", "error", err)
100
101
return helpers.ServerError(e, nil)
101
102
}
102
103
···
104
105
105
106
root, rev, err := r.Commit(context.TODO(), urepo.SignFor)
106
107
if err != nil {
107
-
s.logger.Error("error committing", "error", err)
108
+
logger.Error("error committing", "error", err)
108
109
return helpers.ServerError(e, nil)
109
110
}
110
111
111
112
if err := s.UpdateRepo(context.TODO(), urepo.Repo.Did, root, rev); err != nil {
112
-
s.logger.Error("error updating repo after commit", "error", err)
113
+
logger.Error("error updating repo after commit", "error", err)
113
114
return helpers.ServerError(e, nil)
114
115
}
115
116
+9
-7
server/handle_oauth_par.go
+9
-7
server/handle_oauth_par.go
···
20
20
21
21
func (s *Server) handleOauthPar(e echo.Context) error {
22
22
ctx := e.Request().Context()
23
+
logger := s.logger.With("name", "handleOauthPar")
23
24
24
25
var parRequest provider.ParRequest
25
26
if err := e.Bind(&parRequest); err != nil {
26
-
s.logger.Error("error binding for par request", "error", err)
27
+
logger.Error("error binding for par request", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
if err := e.Validate(parRequest); err != nil {
31
-
s.logger.Error("missing parameters for par request", "error", err)
32
+
logger.Error("missing parameters for par request", "error", err)
32
33
return helpers.InputError(e, nil)
33
34
}
34
35
···
41
42
e.Response().Header().Set("DPoP-Nonce", nonce)
42
43
e.Response().Header().Add("access-control-expose-headers", "DPoP-Nonce")
43
44
}
45
+
logger.Error("nonce error: use_dpop_nonce", "headers", e.Request().Header)
44
46
return e.JSON(400, map[string]string{
45
47
"error": "use_dpop_nonce",
46
48
})
47
49
}
48
-
s.logger.Error("error getting dpop proof", "error", err)
50
+
logger.Error("error getting dpop proof", "error", err)
49
51
return helpers.InputError(e, nil)
50
52
}
51
53
···
55
57
AllowMissingDpopProof: true,
56
58
})
57
59
if err != nil {
58
-
s.logger.Error("error authenticating client", "client_id", parRequest.ClientID, "error", err)
60
+
logger.Error("error authenticating client", "client_id", parRequest.ClientID, "error", err)
59
61
return helpers.InputError(e, to.StringPtr(err.Error()))
60
62
}
61
63
···
66
68
} else {
67
69
if !client.Metadata.DpopBoundAccessTokens {
68
70
msg := "dpop bound access tokens are not enabled for this client"
69
-
s.logger.Error(msg)
71
+
logger.Error(msg)
70
72
return helpers.InputError(e, &msg)
71
73
}
72
74
73
75
if dpopProof.JKT != *parRequest.DpopJkt {
74
76
msg := "supplied dpop jkt does not match header dpop jkt"
75
-
s.logger.Error(msg)
77
+
logger.Error(msg)
76
78
return helpers.InputError(e, &msg)
77
79
}
78
80
}
···
89
91
}
90
92
91
93
if err := s.db.Create(ctx, authRequest, nil).Error; err != nil {
92
-
s.logger.Error("error creating auth request in db", "error", err)
94
+
logger.Error("error creating auth request in db", "error", err)
93
95
return helpers.ServerError(e, nil)
94
96
}
95
97
+9
-8
server/handle_oauth_token.go
+9
-8
server/handle_oauth_token.go
···
39
39
40
40
func (s *Server) handleOauthToken(e echo.Context) error {
41
41
ctx := e.Request().Context()
42
+
logger := s.logger.With("name", "handleOauthToken")
42
43
43
44
var req OauthTokenRequest
44
45
if err := e.Bind(&req); err != nil {
45
-
s.logger.Error("error binding token request", "error", err)
46
+
logger.Error("error binding token request", "error", err)
46
47
return helpers.ServerError(e, nil)
47
48
}
48
49
···
58
59
"error": "use_dpop_nonce",
59
60
})
60
61
}
61
-
s.logger.Error("error getting dpop proof", "error", err)
62
+
logger.Error("error getting dpop proof", "error", err)
62
63
return helpers.InputError(e, nil)
63
64
}
64
65
···
66
67
AllowMissingDpopProof: true,
67
68
})
68
69
if err != nil {
69
-
s.logger.Error("error authenticating client", "client_id", req.ClientID, "error", err)
70
+
logger.Error("error authenticating client", "client_id", req.ClientID, "error", err)
70
71
return helpers.InputError(e, to.StringPtr(err.Error()))
71
72
}
72
73
···
87
88
var authReq provider.OauthAuthorizationRequest
88
89
// get the lil guy and delete him
89
90
if err := s.db.Raw(ctx, "DELETE FROM oauth_authorization_requests WHERE code = ? RETURNING *", nil, *req.Code).Scan(&authReq).Error; err != nil {
90
-
s.logger.Error("error finding authorization request", "error", err)
91
+
logger.Error("error finding authorization request", "error", err)
91
92
return helpers.ServerError(e, nil)
92
93
}
93
94
···
112
113
case "S256":
113
114
inputChal, err := base64.RawURLEncoding.DecodeString(*authReq.Parameters.CodeChallenge)
114
115
if err != nil {
115
-
s.logger.Error("error decoding code challenge", "error", err)
116
+
logger.Error("error decoding code challenge", "error", err)
116
117
return helpers.ServerError(e, nil)
117
118
}
118
119
···
173
174
RefreshToken: refreshToken,
174
175
Ip: authReq.Ip,
175
176
}, nil).Error; err != nil {
176
-
s.logger.Error("error creating token in db", "error", err)
177
+
logger.Error("error creating token in db", "error", err)
177
178
return helpers.ServerError(e, nil)
178
179
}
179
180
···
202
203
203
204
var oauthToken provider.OauthToken
204
205
if err := s.db.Raw(ctx, "SELECT * FROM oauth_tokens WHERE refresh_token = ?", nil, req.RefreshToken).Scan(&oauthToken).Error; err != nil {
205
-
s.logger.Error("error finding oauth token by refresh token", "error", err, "refresh_token", req.RefreshToken)
206
+
logger.Error("error finding oauth token by refresh token", "error", err, "refresh_token", req.RefreshToken)
206
207
return helpers.ServerError(e, nil)
207
208
}
208
209
···
260
261
}
261
262
262
263
if err := s.db.Exec(ctx, "UPDATE oauth_tokens SET token = ?, refresh_token = ?, expires_at = ?, updated_at = ? WHERE refresh_token = ?", nil, accessString, nextRefreshToken, eat, now, *req.RefreshToken).Error; err != nil {
263
-
s.logger.Error("error updating token", "error", err)
264
+
logger.Error("error updating token", "error", err)
264
265
return helpers.ServerError(e, nil)
265
266
}
266
267
+6
-6
server/handle_proxy.go
+6
-6
server/handle_proxy.go
···
47
47
}
48
48
49
49
func (s *Server) handleProxy(e echo.Context) error {
50
-
lgr := s.logger.With("handler", "handleProxy")
50
+
logger := s.logger.With("handler", "handleProxy")
51
51
52
52
repo, isAuthed := e.Get("repo").(*models.RepoActor)
53
53
···
58
58
59
59
endpoint, svcDid, err := s.getAtprotoProxyEndpointFromRequest(e)
60
60
if err != nil {
61
-
lgr.Error("could not get atproto proxy", "error", err)
61
+
logger.Error("could not get atproto proxy", "error", err)
62
62
return helpers.ServerError(e, nil)
63
63
}
64
64
···
90
90
}
91
91
hj, err := json.Marshal(header)
92
92
if err != nil {
93
-
lgr.Error("error marshaling header", "error", err)
93
+
logger.Error("error marshaling header", "error", err)
94
94
return helpers.ServerError(e, nil)
95
95
}
96
96
···
118
118
}
119
119
pj, err := json.Marshal(payload)
120
120
if err != nil {
121
-
lgr.Error("error marashaling payload", "error", err)
121
+
logger.Error("error marashaling payload", "error", err)
122
122
return helpers.ServerError(e, nil)
123
123
}
124
124
···
129
129
130
130
sk, err := secp256k1secec.NewPrivateKey(repo.SigningKey)
131
131
if err != nil {
132
-
lgr.Error("can't load private key", "error", err)
132
+
logger.Error("can't load private key", "error", err)
133
133
return err
134
134
}
135
135
136
136
R, S, _, err := sk.SignRaw(rand.Reader, hash[:])
137
137
if err != nil {
138
-
lgr.Error("error signing", "error", err)
138
+
logger.Error("error signing", "error", err)
139
139
}
140
140
141
141
rBytes := R.Bytes()
+5
-4
server/handle_repo_apply_writes.go
+5
-4
server/handle_repo_apply_writes.go
···
27
27
28
28
func (s *Server) handleApplyWrites(e echo.Context) error {
29
29
ctx := e.Request().Context()
30
+
logger := s.logger.With("name", "handleRepoApplyWrites")
30
31
31
32
var req ComAtprotoRepoApplyWritesInput
32
33
if err := e.Bind(&req); err != nil {
33
-
s.logger.Error("error binding", "error", err)
34
+
logger.Error("error binding", "error", err)
34
35
return helpers.ServerError(e, nil)
35
36
}
36
37
37
38
if err := e.Validate(req); err != nil {
38
-
s.logger.Error("error validating", "error", err)
39
+
logger.Error("error validating", "error", err)
39
40
return helpers.InputError(e, nil)
40
41
}
41
42
42
43
repo := e.Get("repo").(*models.RepoActor)
43
44
44
45
if repo.Repo.Did != req.Repo {
45
-
s.logger.Warn("mismatched repo/auth")
46
+
logger.Warn("mismatched repo/auth")
46
47
return helpers.InputError(e, nil)
47
48
}
48
49
···
58
59
59
60
results, err := s.repoman.applyWrites(ctx, repo.Repo, ops, req.SwapCommit)
60
61
if err != nil {
61
-
s.logger.Error("error applying writes", "error", err)
62
+
logger.Error("error applying writes", "error", err)
62
63
return helpers.ServerError(e, nil)
63
64
}
64
65
+5
-4
server/handle_repo_create_record.go
+5
-4
server/handle_repo_create_record.go
···
18
18
19
19
func (s *Server) handleCreateRecord(e echo.Context) error {
20
20
ctx := e.Request().Context()
21
+
logger := s.logger.With("name", "handleCreateRecord")
21
22
22
23
repo := e.Get("repo").(*models.RepoActor)
23
24
24
25
var req ComAtprotoRepoCreateRecordInput
25
26
if err := e.Bind(&req); err != nil {
26
-
s.logger.Error("error binding", "error", err)
27
+
logger.Error("error binding", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
if err := e.Validate(req); err != nil {
31
-
s.logger.Error("error validating", "error", err)
32
+
logger.Error("error validating", "error", err)
32
33
return helpers.InputError(e, nil)
33
34
}
34
35
35
36
if repo.Repo.Did != req.Repo {
36
-
s.logger.Warn("mismatched repo/auth")
37
+
logger.Warn("mismatched repo/auth")
37
38
return helpers.InputError(e, nil)
38
39
}
39
40
···
53
54
},
54
55
}, req.SwapCommit)
55
56
if err != nil {
56
-
s.logger.Error("error applying writes", "error", err)
57
+
logger.Error("error applying writes", "error", err)
57
58
return helpers.ServerError(e, nil)
58
59
}
59
60
+5
-4
server/handle_repo_delete_record.go
+5
-4
server/handle_repo_delete_record.go
···
16
16
17
17
func (s *Server) handleDeleteRecord(e echo.Context) error {
18
18
ctx := e.Request().Context()
19
+
logger := s.logger.With("name", "handleDeleteRecord")
19
20
20
21
repo := e.Get("repo").(*models.RepoActor)
21
22
22
23
var req ComAtprotoRepoDeleteRecordInput
23
24
if err := e.Bind(&req); err != nil {
24
-
s.logger.Error("error binding", "error", err)
25
+
logger.Error("error binding", "error", err)
25
26
return helpers.ServerError(e, nil)
26
27
}
27
28
28
29
if err := e.Validate(req); err != nil {
29
-
s.logger.Error("error validating", "error", err)
30
+
logger.Error("error validating", "error", err)
30
31
return helpers.InputError(e, nil)
31
32
}
32
33
33
34
if repo.Repo.Did != req.Repo {
34
-
s.logger.Warn("mismatched repo/auth")
35
+
logger.Warn("mismatched repo/auth")
35
36
return helpers.InputError(e, nil)
36
37
}
37
38
···
44
45
},
45
46
}, req.SwapCommit)
46
47
if err != nil {
47
-
s.logger.Error("error applying writes", "error", err)
48
+
logger.Error("error applying writes", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
+4
-3
server/handle_repo_describe_repo.go
+4
-3
server/handle_repo_describe_repo.go
···
21
21
22
22
func (s *Server) handleDescribeRepo(e echo.Context) error {
23
23
ctx := e.Request().Context()
24
+
logger := s.logger.With("name", "handleDescribeRepo")
24
25
25
26
did := e.QueryParam("repo")
26
27
repo, err := s.getRepoActorByDid(ctx, did)
···
29
30
return helpers.InputError(e, to.StringPtr("RepoNotFound"))
30
31
}
31
32
32
-
s.logger.Error("error looking up repo", "error", err)
33
+
logger.Error("error looking up repo", "error", err)
33
34
return helpers.ServerError(e, nil)
34
35
}
35
36
···
37
38
38
39
diddoc, err := s.passport.FetchDoc(e.Request().Context(), repo.Repo.Did)
39
40
if err != nil {
40
-
s.logger.Error("error fetching diddoc", "error", err)
41
+
logger.Error("error fetching diddoc", "error", err)
41
42
return helpers.ServerError(e, nil)
42
43
}
43
44
···
67
68
68
69
var records []models.Record
69
70
if err := s.db.Raw(ctx, "SELECT DISTINCT(nsid) FROM records WHERE did = ?", nil, repo.Repo.Did).Scan(&records).Error; err != nil {
70
-
s.logger.Error("error getting collections", "error", err)
71
+
logger.Error("error getting collections", "error", err)
71
72
return helpers.ServerError(e, nil)
72
73
}
73
74
+2
-1
server/handle_repo_list_missing_blobs.go
+2
-1
server/handle_repo_list_missing_blobs.go
···
23
23
24
24
func (s *Server) handleListMissingBlobs(e echo.Context) error {
25
25
ctx := e.Request().Context()
26
+
logger := s.logger.With("name", "handleListMissingBlos")
26
27
27
28
urepo := e.Get("repo").(*models.RepoActor)
28
29
···
38
39
39
40
var records []models.Record
40
41
if err := s.db.Raw(ctx, "SELECT * FROM records WHERE did = ?", nil, urepo.Repo.Did).Scan(&records).Error; err != nil {
41
-
s.logger.Error("failed to get records for listMissingBlobs", "error", err)
42
+
logger.Error("failed to get records for listMissingBlobs", "error", err)
42
43
return helpers.ServerError(e, nil)
43
44
}
44
45
+3
-2
server/handle_repo_list_records.go
+3
-2
server/handle_repo_list_records.go
···
47
47
48
48
func (s *Server) handleListRecords(e echo.Context) error {
49
49
ctx := e.Request().Context()
50
+
logger := s.logger.With("name", "handleListRecords")
50
51
51
52
var req ComAtprotoRepoListRecordsRequest
52
53
if err := e.Bind(&req); err != nil {
53
-
s.logger.Error("could not bind list records request", "error", err)
54
+
logger.Error("could not bind list records request", "error", err)
54
55
return helpers.ServerError(e, nil)
55
56
}
56
57
···
96
97
97
98
var records []models.Record
98
99
if err := s.db.Raw(ctx, "SELECT * FROM records WHERE did = ? AND nsid = ? "+cursorquery+" ORDER BY created_at "+sort+" limit ?", nil, params...).Scan(&records).Error; err != nil {
99
-
s.logger.Error("error getting records", "error", err)
100
+
logger.Error("error getting records", "error", err)
100
101
return helpers.ServerError(e, nil)
101
102
}
102
103
+5
-4
server/handle_repo_put_record.go
+5
-4
server/handle_repo_put_record.go
···
18
18
19
19
func (s *Server) handlePutRecord(e echo.Context) error {
20
20
ctx := e.Request().Context()
21
+
logger := s.logger.With("name", "handlePutRecord")
21
22
22
23
repo := e.Get("repo").(*models.RepoActor)
23
24
24
25
var req ComAtprotoRepoPutRecordInput
25
26
if err := e.Bind(&req); err != nil {
26
-
s.logger.Error("error binding", "error", err)
27
+
logger.Error("error binding", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
if err := e.Validate(req); err != nil {
31
-
s.logger.Error("error validating", "error", err)
32
+
logger.Error("error validating", "error", err)
32
33
return helpers.InputError(e, nil)
33
34
}
34
35
35
36
if repo.Repo.Did != req.Repo {
36
-
s.logger.Warn("mismatched repo/auth")
37
+
logger.Warn("mismatched repo/auth")
37
38
return helpers.InputError(e, nil)
38
39
}
39
40
···
53
54
},
54
55
}, req.SwapCommit)
55
56
if err != nil {
56
-
s.logger.Error("error applying writes", "error", err)
57
+
logger.Error("error applying writes", "error", err)
57
58
return helpers.ServerError(e, nil)
58
59
}
59
60
+8
-7
server/handle_repo_upload_blob.go
+8
-7
server/handle_repo_upload_blob.go
···
33
33
34
34
func (s *Server) handleRepoUploadBlob(e echo.Context) error {
35
35
ctx := e.Request().Context()
36
+
logger := s.logger.With("name", "handleRepoUploadBlob")
36
37
37
38
urepo := e.Get("repo").(*models.RepoActor)
38
39
···
54
55
}
55
56
56
57
if err := s.db.Create(ctx, &blob, nil).Error; err != nil {
57
-
s.logger.Error("error creating new blob in db", "error", err)
58
+
logger.Error("error creating new blob in db", "error", err)
58
59
return helpers.ServerError(e, nil)
59
60
}
60
61
···
71
72
break
72
73
}
73
74
} else if err != nil && err != io.ErrUnexpectedEOF {
74
-
s.logger.Error("error reading blob", "error", err)
75
+
logger.Error("error reading blob", "error", err)
75
76
return helpers.ServerError(e, nil)
76
77
}
77
78
···
87
88
}
88
89
89
90
if err := s.db.Create(ctx, &blobPart, nil).Error; err != nil {
90
-
s.logger.Error("error adding blob part to db", "error", err)
91
+
logger.Error("error adding blob part to db", "error", err)
91
92
return helpers.ServerError(e, nil)
92
93
}
93
94
}
···
100
101
101
102
c, err := cid.NewPrefixV1(cid.Raw, multihash.SHA2_256).Sum(fulldata.Bytes())
102
103
if err != nil {
103
-
s.logger.Error("error creating cid prefix", "error", err)
104
+
logger.Error("error creating cid prefix", "error", err)
104
105
return helpers.ServerError(e, nil)
105
106
}
106
107
···
117
118
118
119
sess, err := session.NewSession(config)
119
120
if err != nil {
120
-
s.logger.Error("error creating aws session", "error", err)
121
+
logger.Error("error creating aws session", "error", err)
121
122
return helpers.ServerError(e, nil)
122
123
}
123
124
···
128
129
Key: aws.String(fmt.Sprintf("blobs/%s/%s", urepo.Repo.Did, c.String())),
129
130
Body: bytes.NewReader(fulldata.Bytes()),
130
131
}); err != nil {
131
-
s.logger.Error("error uploading blob to s3", "error", err)
132
+
logger.Error("error uploading blob to s3", "error", err)
132
133
return helpers.ServerError(e, nil)
133
134
}
134
135
}
135
136
136
137
if err := s.db.Exec(ctx, "UPDATE blobs SET cid = ? WHERE id = ?", nil, c.Bytes(), blob.ID).Error; err != nil {
137
138
// there should probably be somme handling here if this fails...
138
-
s.logger.Error("error updating blob", "error", err)
139
+
logger.Error("error updating blob", "error", err)
139
140
return helpers.ServerError(e, nil)
140
141
}
141
142
+3
-2
server/handle_server_activate_account.go
+3
-2
server/handle_server_activate_account.go
···
19
19
20
20
func (s *Server) handleServerActivateAccount(e echo.Context) error {
21
21
ctx := e.Request().Context()
22
+
logger := s.logger.With("name", "handleServerActivateAccount")
22
23
23
24
var req ComAtprotoServerDeactivateAccountRequest
24
25
if err := e.Bind(&req); err != nil {
25
-
s.logger.Error("error binding", "error", err)
26
+
logger.Error("error binding", "error", err)
26
27
return helpers.ServerError(e, nil)
27
28
}
28
29
29
30
urepo := e.Get("repo").(*models.RepoActor)
30
31
31
32
if err := s.db.Exec(ctx, "UPDATE repos SET deactivated = ? WHERE did = ?", nil, false, urepo.Repo.Did).Error; err != nil {
32
-
s.logger.Error("error updating account status to deactivated", "error", err)
33
+
logger.Error("error updating account status to deactivated", "error", err)
33
34
return helpers.ServerError(e, nil)
34
35
}
35
36
+5
-4
server/handle_server_check_account_status.go
+5
-4
server/handle_server_check_account_status.go
···
21
21
22
22
func (s *Server) handleServerCheckAccountStatus(e echo.Context) error {
23
23
ctx := e.Request().Context()
24
+
logger := s.logger.With("name", "handleServerCheckAccountStatus")
24
25
25
26
urepo := e.Get("repo").(*models.RepoActor)
26
27
···
33
34
34
35
rootcid, err := cid.Cast(urepo.Root)
35
36
if err != nil {
36
-
s.logger.Error("error casting cid", "error", err)
37
+
logger.Error("error casting cid", "error", err)
37
38
return helpers.ServerError(e, nil)
38
39
}
39
40
resp.RepoCommit = rootcid.String()
···
44
45
45
46
var blockCtResp CountResp
46
47
if err := s.db.Raw(ctx, "SELECT COUNT(*) AS ct FROM blocks WHERE did = ?", nil, urepo.Repo.Did).Scan(&blockCtResp).Error; err != nil {
47
-
s.logger.Error("error getting block count", "error", err)
48
+
logger.Error("error getting block count", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
resp.RepoBlocks = blockCtResp.Ct
51
52
52
53
var recCtResp CountResp
53
54
if err := s.db.Raw(ctx, "SELECT COUNT(*) AS ct FROM records WHERE did = ?", nil, urepo.Repo.Did).Scan(&recCtResp).Error; err != nil {
54
-
s.logger.Error("error getting record count", "error", err)
55
+
logger.Error("error getting record count", "error", err)
55
56
return helpers.ServerError(e, nil)
56
57
}
57
58
resp.IndexedRecords = recCtResp.Ct
58
59
59
60
var blobCtResp CountResp
60
61
if err := s.db.Raw(ctx, "SELECT COUNT(*) AS ct FROM blobs WHERE did = ?", nil, urepo.Repo.Did).Scan(&blobCtResp).Error; err != nil {
61
-
s.logger.Error("error getting record count", "error", err)
62
+
logger.Error("error getting record count", "error", err)
62
63
return helpers.ServerError(e, nil)
63
64
}
64
65
resp.ExpectedBlobs = blobCtResp.Ct
+3
-2
server/handle_server_confirm_email.go
+3
-2
server/handle_server_confirm_email.go
···
16
16
17
17
func (s *Server) handleServerConfirmEmail(e echo.Context) error {
18
18
ctx := e.Request().Context()
19
+
logger := s.logger.With("name", "handleServerConfirmEmail")
19
20
20
21
urepo := e.Get("repo").(*models.RepoActor)
21
22
22
23
var req ComAtprotoServerConfirmEmailRequest
23
24
if err := e.Bind(&req); err != nil {
24
-
s.logger.Error("error binding", "error", err)
25
+
logger.Error("error binding", "error", err)
25
26
return helpers.ServerError(e, nil)
26
27
}
27
28
···
44
45
now := time.Now().UTC()
45
46
46
47
if err := s.db.Exec(ctx, "UPDATE repos SET email_verification_code = NULL, email_verification_code_expires_at = NULL, email_confirmed_at = ? WHERE did = ?", nil, now, urepo.Repo.Did).Error; err != nil {
47
-
s.logger.Error("error updating user", "error", err)
48
+
logger.Error("error updating user", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
+23
-22
server/handle_server_create_account.go
+23
-22
server/handle_server_create_account.go
···
37
37
38
38
func (s *Server) handleCreateAccount(e echo.Context) error {
39
39
ctx := e.Request().Context()
40
+
logger := s.logger.With("name", "handleServerCreateAccount")
40
41
41
42
var request ComAtprotoServerCreateAccountRequest
42
43
43
44
if err := e.Bind(&request); err != nil {
44
-
s.logger.Error("error receiving request", "endpoint", "com.atproto.server.createAccount", "error", err)
45
+
logger.Error("error receiving request", "endpoint", "com.atproto.server.createAccount", "error", err)
45
46
return helpers.ServerError(e, nil)
46
47
}
47
48
48
49
request.Handle = strings.ToLower(request.Handle)
49
50
50
51
if err := e.Validate(request); err != nil {
51
-
s.logger.Error("error validating request", "endpoint", "com.atproto.server.createAccount", "error", err)
52
+
logger.Error("error validating request", "endpoint", "com.atproto.server.createAccount", "error", err)
52
53
53
54
var verr ValidationError
54
55
if errors.As(err, &verr) {
···
82
83
authDid, err := s.validateServiceAuth(e.Request().Context(), token, "com.atproto.server.createAccount")
83
84
84
85
if err != nil {
85
-
s.logger.Warn("error validating authorization token", "endpoint", "com.atproto.server.createAccount", "error", err)
86
+
logger.Warn("error validating authorization token", "endpoint", "com.atproto.server.createAccount", "error", err)
86
87
return helpers.UnauthorizedError(e, to.StringPtr("invalid authorization token"))
87
88
}
88
89
···
94
95
// see if the handle is already taken
95
96
actor, err := s.getActorByHandle(ctx, request.Handle)
96
97
if err != nil && err != gorm.ErrRecordNotFound {
97
-
s.logger.Error("error looking up handle in db", "endpoint", "com.atproto.server.createAccount", "error", err)
98
+
logger.Error("error looking up handle in db", "endpoint", "com.atproto.server.createAccount", "error", err)
98
99
return helpers.ServerError(e, nil)
99
100
}
100
101
if err == nil && actor.Did != signupDid {
···
115
116
if err == gorm.ErrRecordNotFound {
116
117
return helpers.InputError(e, to.StringPtr("InvalidInviteCode"))
117
118
}
118
-
s.logger.Error("error getting invite code from db", "error", err)
119
+
logger.Error("error getting invite code from db", "error", err)
119
120
return helpers.ServerError(e, nil)
120
121
}
121
122
···
127
128
// see if the email is already taken
128
129
existingRepo, err := s.getRepoByEmail(ctx, request.Email)
129
130
if err != nil && err != gorm.ErrRecordNotFound {
130
-
s.logger.Error("error looking up email in db", "endpoint", "com.atproto.server.createAccount", "error", err)
131
+
logger.Error("error looking up email in db", "endpoint", "com.atproto.server.createAccount", "error", err)
131
132
return helpers.ServerError(e, nil)
132
133
}
133
134
if err == nil && existingRepo.Did != signupDid {
···
141
142
if signupDid != "" {
142
143
reservedKey, err := s.getReservedKey(ctx, signupDid)
143
144
if err != nil {
144
-
s.logger.Error("error looking up reserved key", "error", err)
145
+
logger.Error("error looking up reserved key", "error", err)
145
146
}
146
147
if reservedKey != nil {
147
148
k, err = atcrypto.ParsePrivateBytesK256(reservedKey.PrivateKey)
148
149
if err != nil {
149
-
s.logger.Error("error parsing reserved key", "error", err)
150
+
logger.Error("error parsing reserved key", "error", err)
150
151
k = nil
151
152
} else {
152
153
defer func() {
153
154
if delErr := s.deleteReservedKey(ctx, reservedKey.KeyDid, reservedKey.Did); delErr != nil {
154
-
s.logger.Error("error deleting reserved key", "error", delErr)
155
+
logger.Error("error deleting reserved key", "error", delErr)
155
156
}
156
157
}()
157
158
}
···
161
162
if k == nil {
162
163
k, err = atcrypto.GeneratePrivateKeyK256()
163
164
if err != nil {
164
-
s.logger.Error("error creating signing key", "endpoint", "com.atproto.server.createAccount", "error", err)
165
+
logger.Error("error creating signing key", "endpoint", "com.atproto.server.createAccount", "error", err)
165
166
return helpers.ServerError(e, nil)
166
167
}
167
168
}
···
169
170
if signupDid == "" {
170
171
did, op, err := s.plcClient.CreateDID(k, "", request.Handle)
171
172
if err != nil {
172
-
s.logger.Error("error creating operation", "endpoint", "com.atproto.server.createAccount", "error", err)
173
+
logger.Error("error creating operation", "endpoint", "com.atproto.server.createAccount", "error", err)
173
174
return helpers.ServerError(e, nil)
174
175
}
175
176
176
177
if err := s.plcClient.SendOperation(e.Request().Context(), did, op); err != nil {
177
-
s.logger.Error("error sending plc op", "endpoint", "com.atproto.server.createAccount", "error", err)
178
+
logger.Error("error sending plc op", "endpoint", "com.atproto.server.createAccount", "error", err)
178
179
return helpers.ServerError(e, nil)
179
180
}
180
181
signupDid = did
···
182
183
183
184
hashed, err := bcrypt.GenerateFromPassword([]byte(request.Password), 10)
184
185
if err != nil {
185
-
s.logger.Error("error hashing password", "error", err)
186
+
logger.Error("error hashing password", "error", err)
186
187
return helpers.ServerError(e, nil)
187
188
}
188
189
···
202
203
}
203
204
204
205
if err := s.db.Create(ctx, &urepo, nil).Error; err != nil {
205
-
s.logger.Error("error inserting new repo", "error", err)
206
+
logger.Error("error inserting new repo", "error", err)
206
207
return helpers.ServerError(e, nil)
207
208
}
208
209
209
210
if err := s.db.Create(ctx, &actor, nil).Error; err != nil {
210
-
s.logger.Error("error inserting new actor", "error", err)
211
+
logger.Error("error inserting new actor", "error", err)
211
212
return helpers.ServerError(e, nil)
212
213
}
213
214
} else {
214
215
if err := s.db.Save(ctx, &actor, nil).Error; err != nil {
215
-
s.logger.Error("error inserting new actor", "error", err)
216
+
logger.Error("error inserting new actor", "error", err)
216
217
return helpers.ServerError(e, nil)
217
218
}
218
219
}
···
223
224
224
225
root, rev, err := r.Commit(context.TODO(), urepo.SignFor)
225
226
if err != nil {
226
-
s.logger.Error("error committing", "error", err)
227
+
logger.Error("error committing", "error", err)
227
228
return helpers.ServerError(e, nil)
228
229
}
229
230
230
231
if err := s.UpdateRepo(context.TODO(), urepo.Did, root, rev); err != nil {
231
-
s.logger.Error("error updating repo after commit", "error", err)
232
+
logger.Error("error updating repo after commit", "error", err)
232
233
return helpers.ServerError(e, nil)
233
234
}
234
235
···
244
245
245
246
if s.config.RequireInvite {
246
247
if err := s.db.Raw(ctx, "UPDATE invite_codes SET remaining_use_count = remaining_use_count - 1 WHERE code = ?", nil, request.InviteCode).Scan(&ic).Error; err != nil {
247
-
s.logger.Error("error decrementing use count", "error", err)
248
+
logger.Error("error decrementing use count", "error", err)
248
249
return helpers.ServerError(e, nil)
249
250
}
250
251
}
251
252
252
253
sess, err := s.createSession(ctx, &urepo)
253
254
if err != nil {
254
-
s.logger.Error("error creating new session", "error", err)
255
+
logger.Error("error creating new session", "error", err)
255
256
return helpers.ServerError(e, nil)
256
257
}
257
258
258
259
go func() {
259
260
if err := s.sendEmailVerification(urepo.Email, actor.Handle, *urepo.EmailVerificationCode); err != nil {
260
-
s.logger.Error("error sending email verification email", "error", err)
261
+
logger.Error("error sending email verification email", "error", err)
261
262
}
262
263
if err := s.sendWelcomeMail(urepo.Email, actor.Handle); err != nil {
263
-
s.logger.Error("error sending welcome email", "error", err)
264
+
logger.Error("error sending welcome email", "error", err)
264
265
}
265
266
}()
266
267
+4
-3
server/handle_server_create_invite_code.go
+4
-3
server/handle_server_create_invite_code.go
···
18
18
19
19
func (s *Server) handleCreateInviteCode(e echo.Context) error {
20
20
ctx := e.Request().Context()
21
+
logger := s.logger.With("name", "handleServerCreateInviteCode")
21
22
22
23
var req ComAtprotoServerCreateInviteCodeRequest
23
24
if err := e.Bind(&req); err != nil {
24
-
s.logger.Error("error binding", "error", err)
25
+
logger.Error("error binding", "error", err)
25
26
return helpers.ServerError(e, nil)
26
27
}
27
28
28
29
if err := e.Validate(req); err != nil {
29
-
s.logger.Error("error validating", "error", err)
30
+
logger.Error("error validating", "error", err)
30
31
return helpers.InputError(e, nil)
31
32
}
32
33
···
44
45
Did: acc,
45
46
RemainingUseCount: req.UseCount,
46
47
}, nil).Error; err != nil {
47
-
s.logger.Error("error creating invite code", "error", err)
48
+
logger.Error("error creating invite code", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
+4
-3
server/handle_server_create_invite_codes.go
+4
-3
server/handle_server_create_invite_codes.go
···
23
23
24
24
func (s *Server) handleCreateInviteCodes(e echo.Context) error {
25
25
ctx := e.Request().Context()
26
+
logger := s.logger.With("name", "handleServerCreateInviteCodes")
26
27
27
28
var req ComAtprotoServerCreateInviteCodesRequest
28
29
if err := e.Bind(&req); err != nil {
29
-
s.logger.Error("error binding", "error", err)
30
+
logger.Error("error binding", "error", err)
30
31
return helpers.ServerError(e, nil)
31
32
}
32
33
33
34
if err := e.Validate(req); err != nil {
34
-
s.logger.Error("error validating", "error", err)
35
+
logger.Error("error validating", "error", err)
35
36
return helpers.InputError(e, nil)
36
37
}
37
38
···
57
58
Did: did,
58
59
RemainingUseCount: req.UseCount,
59
60
}, nil).Error; err != nil {
60
-
s.logger.Error("error creating invite code", "error", err)
61
+
logger.Error("error creating invite code", "error", err)
61
62
return helpers.ServerError(e, nil)
62
63
}
63
64
}
+59
-5
server/handle_server_create_session.go
+59
-5
server/handle_server_create_session.go
···
1
1
package server
2
2
3
3
import (
4
+
"context"
4
5
"errors"
6
+
"fmt"
5
7
"strings"
8
+
"time"
6
9
7
10
"github.com/Azure/go-autorest/autorest/to"
8
11
"github.com/bluesky-social/indigo/atproto/syntax"
···
33
36
34
37
func (s *Server) handleCreateSession(e echo.Context) error {
35
38
ctx := e.Request().Context()
39
+
logger := s.logger.With("name", "handleServerCreateSession")
36
40
37
41
var req ComAtprotoServerCreateSessionRequest
38
42
if err := e.Bind(&req); err != nil {
39
-
s.logger.Error("error binding request", "endpoint", "com.atproto.server.serverCreateSession", "error", err)
43
+
logger.Error("error binding request", "endpoint", "com.atproto.server.serverCreateSession", "error", err)
40
44
return helpers.ServerError(e, nil)
41
45
}
42
46
···
79
83
return helpers.InputError(e, to.StringPtr("InvalidRequest"))
80
84
}
81
85
82
-
s.logger.Error("erorr looking up repo", "endpoint", "com.atproto.server.createSession", "error", err)
86
+
logger.Error("erorr looking up repo", "endpoint", "com.atproto.server.createSession", "error", err)
83
87
return helpers.ServerError(e, nil)
84
88
}
85
89
86
90
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
87
91
if err != bcrypt.ErrMismatchedHashAndPassword {
88
-
s.logger.Error("erorr comparing hash and password", "error", err)
92
+
logger.Error("erorr comparing hash and password", "error", err)
89
93
}
90
94
return helpers.InputError(e, to.StringPtr("InvalidRequest"))
91
95
}
92
96
97
+
// if repo requires 2FA token and one hasn't been provided, return error prompting for one
98
+
if repo.TwoFactorType != models.TwoFactorTypeNone && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") {
99
+
err = s.createAndSendTwoFactorCode(ctx, repo)
100
+
if err != nil {
101
+
logger.Error("sending 2FA code", "error", err)
102
+
return helpers.ServerError(e, nil)
103
+
}
104
+
105
+
return helpers.InputError(e, to.StringPtr("AuthFactorTokenRequired"))
106
+
}
107
+
108
+
// if 2FA is required, now check that the one provided is valid
109
+
if repo.TwoFactorType != models.TwoFactorTypeNone {
110
+
if repo.TwoFactorCode == nil || repo.TwoFactorCodeExpiresAt == nil {
111
+
err = s.createAndSendTwoFactorCode(ctx, repo)
112
+
if err != nil {
113
+
logger.Error("sending 2FA code", "error", err)
114
+
return helpers.ServerError(e, nil)
115
+
}
116
+
117
+
return helpers.InputError(e, to.StringPtr("AuthFactorTokenRequired"))
118
+
}
119
+
120
+
if *repo.TwoFactorCode != *req.AuthFactorToken {
121
+
return helpers.InvalidTokenError(e)
122
+
}
123
+
124
+
if time.Now().UTC().After(*repo.TwoFactorCodeExpiresAt) {
125
+
return helpers.ExpiredTokenError(e)
126
+
}
127
+
}
128
+
93
129
sess, err := s.createSession(ctx, &repo.Repo)
94
130
if err != nil {
95
-
s.logger.Error("error creating session", "error", err)
131
+
logger.Error("error creating session", "error", err)
96
132
return helpers.ServerError(e, nil)
97
133
}
98
134
···
103
139
Did: repo.Repo.Did,
104
140
Email: repo.Email,
105
141
EmailConfirmed: repo.EmailConfirmedAt != nil,
106
-
EmailAuthFactor: false,
142
+
EmailAuthFactor: repo.TwoFactorType != models.TwoFactorTypeNone,
107
143
Active: repo.Active(),
108
144
Status: repo.Status(),
109
145
})
110
146
}
147
+
148
+
func (s *Server) createAndSendTwoFactorCode(ctx context.Context, repo models.RepoActor) error {
149
+
// TODO: when implementing a new type of 2FA there should be some logic in here to send the
150
+
// right type of code
151
+
152
+
code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5))
153
+
eat := time.Now().Add(10 * time.Minute).UTC()
154
+
155
+
if err := s.db.Exec(ctx, "UPDATE repos SET two_factor_code = ?, two_factor_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil {
156
+
return fmt.Errorf("updating repo: %w", err)
157
+
}
158
+
159
+
if err := s.sendTwoFactorCode(repo.Email, repo.Handle, code); err != nil {
160
+
return fmt.Errorf("sending email: %w", err)
161
+
}
162
+
163
+
return nil
164
+
}
+3
-2
server/handle_server_deactivate_account.go
+3
-2
server/handle_server_deactivate_account.go
···
20
20
21
21
func (s *Server) handleServerDeactivateAccount(e echo.Context) error {
22
22
ctx := e.Request().Context()
23
+
logger := s.logger.With("name", "handleServerDeactivateAccount")
23
24
24
25
var req ComAtprotoServerDeactivateAccountRequest
25
26
if err := e.Bind(&req); err != nil {
26
-
s.logger.Error("error binding", "error", err)
27
+
logger.Error("error binding", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
urepo := e.Get("repo").(*models.RepoActor)
31
32
32
33
if err := s.db.Exec(ctx, "UPDATE repos SET deactivated = ? WHERE did = ?", nil, true, urepo.Repo.Did).Error; err != nil {
33
-
s.logger.Error("error updating account status to deactivated", "error", err)
34
+
logger.Error("error updating account status to deactivated", "error", err)
34
35
return helpers.ServerError(e, nil)
35
36
}
36
37
+31
-28
server/handle_server_delete_account.go
+31
-28
server/handle_server_delete_account.go
···
21
21
22
22
func (s *Server) handleServerDeleteAccount(e echo.Context) error {
23
23
ctx := e.Request().Context()
24
+
logger := s.logger.With("name", "handleServerDeleteAccount")
24
25
25
26
var req ComAtprotoServerDeleteAccountRequest
26
27
if err := e.Bind(&req); err != nil {
27
-
s.logger.Error("error binding", "error", err)
28
+
logger.Error("error binding", "error", err)
28
29
return helpers.ServerError(e, nil)
29
30
}
30
31
31
32
if err := e.Validate(&req); err != nil {
32
-
s.logger.Error("error validating", "error", err)
33
+
logger.Error("error validating", "error", err)
33
34
return helpers.ServerError(e, nil)
34
35
}
35
36
36
37
urepo, err := s.getRepoActorByDid(ctx, req.Did)
37
38
if err != nil {
38
-
s.logger.Error("error getting repo", "error", err)
39
+
logger.Error("error getting repo", "error", err)
39
40
return echo.NewHTTPError(400, "account not found")
40
41
}
41
42
42
43
if err := bcrypt.CompareHashAndPassword([]byte(urepo.Repo.Password), []byte(req.Password)); err != nil {
43
-
s.logger.Error("password mismatch", "error", err)
44
+
logger.Error("password mismatch", "error", err)
44
45
return echo.NewHTTPError(401, "Invalid did or password")
45
46
}
46
47
47
48
if urepo.Repo.AccountDeleteCode == nil || urepo.Repo.AccountDeleteCodeExpiresAt == nil {
48
-
s.logger.Error("no deletion token found for account")
49
+
logger.Error("no deletion token found for account")
49
50
return echo.NewHTTPError(400, map[string]interface{}{
50
51
"error": "InvalidToken",
51
52
"message": "Token is invalid",
···
53
54
}
54
55
55
56
if *urepo.Repo.AccountDeleteCode != req.Token {
56
-
s.logger.Error("deletion token mismatch")
57
+
logger.Error("deletion token mismatch")
57
58
return echo.NewHTTPError(400, map[string]interface{}{
58
59
"error": "InvalidToken",
59
60
"message": "Token is invalid",
···
61
62
}
62
63
63
64
if time.Now().UTC().After(*urepo.Repo.AccountDeleteCodeExpiresAt) {
64
-
s.logger.Error("deletion token expired")
65
+
logger.Error("deletion token expired")
65
66
return echo.NewHTTPError(400, map[string]interface{}{
66
67
"error": "ExpiredToken",
67
68
"message": "Token is expired",
68
69
})
69
70
}
70
71
71
-
tx := s.db.BeginDangerously(ctx)
72
+
tx := s.db.Begin(ctx)
72
73
if tx.Error != nil {
73
-
s.logger.Error("error starting transaction", "error", tx.Error)
74
+
logger.Error("error starting transaction", "error", tx.Error)
74
75
return helpers.ServerError(e, nil)
75
76
}
76
77
78
+
status := "error"
79
+
func() {
80
+
if status == "error" {
81
+
if err := tx.Rollback().Error; err != nil {
82
+
logger.Error("error rolling back after delete failure", "err", err)
83
+
}
84
+
}
85
+
}()
86
+
77
87
if err := tx.Exec("DELETE FROM blocks WHERE did = ?", nil, req.Did).Error; err != nil {
78
-
tx.Rollback()
79
-
s.logger.Error("error deleting blocks", "error", err)
88
+
logger.Error("error deleting blocks", "error", err)
80
89
return helpers.ServerError(e, nil)
81
90
}
82
91
83
92
if err := tx.Exec("DELETE FROM records WHERE did = ?", nil, req.Did).Error; err != nil {
84
-
tx.Rollback()
85
-
s.logger.Error("error deleting records", "error", err)
93
+
logger.Error("error deleting records", "error", err)
86
94
return helpers.ServerError(e, nil)
87
95
}
88
96
89
97
if err := tx.Exec("DELETE FROM blobs WHERE did = ?", nil, req.Did).Error; err != nil {
90
-
tx.Rollback()
91
-
s.logger.Error("error deleting blobs", "error", err)
98
+
logger.Error("error deleting blobs", "error", err)
92
99
return helpers.ServerError(e, nil)
93
100
}
94
101
95
102
if err := tx.Exec("DELETE FROM tokens WHERE did = ?", nil, req.Did).Error; err != nil {
96
-
tx.Rollback()
97
-
s.logger.Error("error deleting tokens", "error", err)
103
+
logger.Error("error deleting tokens", "error", err)
98
104
return helpers.ServerError(e, nil)
99
105
}
100
106
101
107
if err := tx.Exec("DELETE FROM refresh_tokens WHERE did = ?", nil, req.Did).Error; err != nil {
102
-
tx.Rollback()
103
-
s.logger.Error("error deleting refresh tokens", "error", err)
108
+
logger.Error("error deleting refresh tokens", "error", err)
104
109
return helpers.ServerError(e, nil)
105
110
}
106
111
107
112
if err := tx.Exec("DELETE FROM reserved_keys WHERE did = ?", nil, req.Did).Error; err != nil {
108
-
tx.Rollback()
109
-
s.logger.Error("error deleting reserved keys", "error", err)
113
+
logger.Error("error deleting reserved keys", "error", err)
110
114
return helpers.ServerError(e, nil)
111
115
}
112
116
113
117
if err := tx.Exec("DELETE FROM invite_codes WHERE did = ?", nil, req.Did).Error; err != nil {
114
-
tx.Rollback()
115
-
s.logger.Error("error deleting invite codes", "error", err)
118
+
logger.Error("error deleting invite codes", "error", err)
116
119
return helpers.ServerError(e, nil)
117
120
}
118
121
119
122
if err := tx.Exec("DELETE FROM actors WHERE did = ?", nil, req.Did).Error; err != nil {
120
-
tx.Rollback()
121
-
s.logger.Error("error deleting actor", "error", err)
123
+
logger.Error("error deleting actor", "error", err)
122
124
return helpers.ServerError(e, nil)
123
125
}
124
126
125
127
if err := tx.Exec("DELETE FROM repos WHERE did = ?", nil, req.Did).Error; err != nil {
126
-
tx.Rollback()
127
-
s.logger.Error("error deleting repo", "error", err)
128
+
logger.Error("error deleting repo", "error", err)
128
129
return helpers.ServerError(e, nil)
129
130
}
130
131
132
+
status = "ok"
133
+
131
134
if err := tx.Commit().Error; err != nil {
132
-
s.logger.Error("error committing transaction", "error", err)
135
+
logger.Error("error committing transaction", "error", err)
133
136
return helpers.ServerError(e, nil)
134
137
}
135
138
+7
-5
server/handle_server_get_service_auth.go
+7
-5
server/handle_server_get_service_auth.go
···
25
25
}
26
26
27
27
func (s *Server) handleServerGetServiceAuth(e echo.Context) error {
28
+
logger := s.logger.With("name", "handleServerGetServiceAuth")
29
+
28
30
var req ServerGetServiceAuthRequest
29
31
if err := e.Bind(&req); err != nil {
30
-
s.logger.Error("could not bind service auth request", "error", err)
32
+
logger.Error("could not bind service auth request", "error", err)
31
33
return helpers.ServerError(e, nil)
32
34
}
33
35
···
64
66
}
65
67
hj, err := json.Marshal(header)
66
68
if err != nil {
67
-
s.logger.Error("error marshaling header", "error", err)
69
+
logger.Error("error marshaling header", "error", err)
68
70
return helpers.ServerError(e, nil)
69
71
}
70
72
···
82
84
}
83
85
pj, err := json.Marshal(payload)
84
86
if err != nil {
85
-
s.logger.Error("error marashaling payload", "error", err)
87
+
logger.Error("error marashaling payload", "error", err)
86
88
return helpers.ServerError(e, nil)
87
89
}
88
90
···
93
95
94
96
sk, err := secp256k1secec.NewPrivateKey(repo.SigningKey)
95
97
if err != nil {
96
-
s.logger.Error("can't load private key", "error", err)
98
+
logger.Error("can't load private key", "error", err)
97
99
return err
98
100
}
99
101
100
102
R, S, _, err := sk.SignRaw(rand.Reader, hash[:])
101
103
if err != nil {
102
-
s.logger.Error("error signing", "error", err)
104
+
logger.Error("error signing", "error", err)
103
105
return helpers.ServerError(e, nil)
104
106
}
105
107
+1
-1
server/handle_server_get_session.go
+1
-1
server/handle_server_get_session.go
+4
-3
server/handle_server_refresh_session.go
+4
-3
server/handle_server_refresh_session.go
···
17
17
18
18
func (s *Server) handleRefreshSession(e echo.Context) error {
19
19
ctx := e.Request().Context()
20
+
logger := s.logger.With("name", "handleServerRefreshSession")
20
21
21
22
token := e.Get("token").(string)
22
23
repo := e.Get("repo").(*models.RepoActor)
23
24
24
25
if err := s.db.Exec(ctx, "DELETE FROM refresh_tokens WHERE token = ?", nil, token).Error; err != nil {
25
-
s.logger.Error("error getting refresh token from db", "error", err)
26
+
logger.Error("error getting refresh token from db", "error", err)
26
27
return helpers.ServerError(e, nil)
27
28
}
28
29
29
30
if err := s.db.Exec(ctx, "DELETE FROM tokens WHERE refresh_token = ?", nil, token).Error; err != nil {
30
-
s.logger.Error("error deleting access token from db", "error", err)
31
+
logger.Error("error deleting access token from db", "error", err)
31
32
return helpers.ServerError(e, nil)
32
33
}
33
34
34
35
sess, err := s.createSession(ctx, &repo.Repo)
35
36
if err != nil {
36
-
s.logger.Error("error creating new session for refresh", "error", err)
37
+
logger.Error("error creating new session for refresh", "error", err)
37
38
return helpers.ServerError(e, nil)
38
39
}
39
40
+3
-2
server/handle_server_request_account_delete.go
+3
-2
server/handle_server_request_account_delete.go
···
11
11
12
12
func (s *Server) handleServerRequestAccountDelete(e echo.Context) error {
13
13
ctx := e.Request().Context()
14
+
logger := s.logger.With("name", "handleServerRequestAccountDelete")
14
15
15
16
urepo := e.Get("repo").(*models.RepoActor)
16
17
···
18
19
expiresAt := time.Now().UTC().Add(15 * time.Minute)
19
20
20
21
if err := s.db.Exec(ctx, "UPDATE repos SET account_delete_code = ?, account_delete_code_expires_at = ? WHERE did = ?", nil, token, expiresAt, urepo.Repo.Did).Error; err != nil {
21
-
s.logger.Error("error setting deletion token", "error", err)
22
+
logger.Error("error setting deletion token", "error", err)
22
23
return helpers.ServerError(e, nil)
23
24
}
24
25
25
26
if urepo.Email != "" {
26
27
if err := s.sendAccountDeleteEmail(urepo.Email, urepo.Actor.Handle, token); err != nil {
27
-
s.logger.Error("error sending account deletion email", "error", err)
28
+
logger.Error("error sending account deletion email", "error", err)
28
29
}
29
30
}
30
31
+3
-2
server/handle_server_request_email_confirmation.go
+3
-2
server/handle_server_request_email_confirmation.go
···
12
12
13
13
func (s *Server) handleServerRequestEmailConfirmation(e echo.Context) error {
14
14
ctx := e.Request().Context()
15
+
logger := s.logger.With("name", "handleServerRequestEmailConfirm")
15
16
16
17
urepo := e.Get("repo").(*models.RepoActor)
17
18
···
23
24
eat := time.Now().Add(10 * time.Minute).UTC()
24
25
25
26
if err := s.db.Exec(ctx, "UPDATE repos SET email_verification_code = ?, email_verification_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil {
26
-
s.logger.Error("error updating user", "error", err)
27
+
logger.Error("error updating user", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
if err := s.sendEmailVerification(urepo.Email, urepo.Handle, code); err != nil {
31
-
s.logger.Error("error sending mail", "error", err)
32
+
logger.Error("error sending mail", "error", err)
32
33
return helpers.ServerError(e, nil)
33
34
}
34
35
+3
-2
server/handle_server_request_email_update.go
+3
-2
server/handle_server_request_email_update.go
···
15
15
16
16
func (s *Server) handleServerRequestEmailUpdate(e echo.Context) error {
17
17
ctx := e.Request().Context()
18
+
logger := s.logger.With("name", "handleServerRequestEmailUpdate")
18
19
19
20
urepo := e.Get("repo").(*models.RepoActor)
20
21
···
23
24
eat := time.Now().Add(10 * time.Minute).UTC()
24
25
25
26
if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = ?, email_update_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil {
26
-
s.logger.Error("error updating repo", "error", err)
27
+
logger.Error("error updating repo", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
30
31
if err := s.sendEmailUpdate(urepo.Email, urepo.Handle, code); err != nil {
31
-
s.logger.Error("error sending email", "error", err)
32
+
logger.Error("error sending email", "error", err)
32
33
return helpers.ServerError(e, nil)
33
34
}
34
35
}
+3
-2
server/handle_server_request_password_reset.go
+3
-2
server/handle_server_request_password_reset.go
···
15
15
16
16
func (s *Server) handleServerRequestPasswordReset(e echo.Context) error {
17
17
ctx := e.Request().Context()
18
+
logger := s.logger.With("name", "handleServerRequestPasswordReset")
18
19
19
20
urepo, ok := e.Get("repo").(*models.RepoActor)
20
21
if !ok {
···
39
40
eat := time.Now().Add(10 * time.Minute).UTC()
40
41
41
42
if err := s.db.Exec(ctx, "UPDATE repos SET password_reset_code = ?, password_reset_code_expires_at = ? WHERE did = ?", nil, code, eat, urepo.Repo.Did).Error; err != nil {
42
-
s.logger.Error("error updating repo", "error", err)
43
+
logger.Error("error updating repo", "error", err)
43
44
return helpers.ServerError(e, nil)
44
45
}
45
46
46
47
if err := s.sendPasswordReset(urepo.Email, urepo.Handle, code); err != nil {
47
-
s.logger.Error("error sending email", "error", err)
48
+
logger.Error("error sending email", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
+6
-5
server/handle_server_reserve_signing_key.go
+6
-5
server/handle_server_reserve_signing_key.go
···
20
20
21
21
func (s *Server) handleServerReserveSigningKey(e echo.Context) error {
22
22
ctx := e.Request().Context()
23
+
logger := s.logger.With("name", "handleServerReserveSigningKey")
23
24
24
25
var req ServerReserveSigningKeyRequest
25
26
if err := e.Bind(&req); err != nil {
26
-
s.logger.Error("could not bind reserve signing key request", "error", err)
27
+
logger.Error("could not bind reserve signing key request", "error", err)
27
28
return helpers.ServerError(e, nil)
28
29
}
29
30
···
38
39
39
40
k, err := atcrypto.GeneratePrivateKeyK256()
40
41
if err != nil {
41
-
s.logger.Error("error creating signing key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
42
+
logger.Error("error creating signing key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
42
43
return helpers.ServerError(e, nil)
43
44
}
44
45
45
46
pubKey, err := k.PublicKey()
46
47
if err != nil {
47
-
s.logger.Error("error getting public key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
48
+
logger.Error("error getting public key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
···
58
59
}
59
60
60
61
if err := s.db.Create(ctx, &reservedKey, nil).Error; err != nil {
61
-
s.logger.Error("error storing reserved key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
62
+
logger.Error("error storing reserved key", "endpoint", "com.atproto.server.reserveSigningKey", "error", err)
62
63
return helpers.ServerError(e, nil)
63
64
}
64
65
65
-
s.logger.Info("reserved signing key", "keyDid", keyDid, "forDid", req.Did)
66
+
logger.Info("reserved signing key", "keyDid", keyDid, "forDid", req.Did)
66
67
67
68
return e.JSON(200, ServerReserveSigningKeyResponse{
68
69
SigningKey: keyDid,
+4
-3
server/handle_server_reset_password.go
+4
-3
server/handle_server_reset_password.go
···
17
17
18
18
func (s *Server) handleServerResetPassword(e echo.Context) error {
19
19
ctx := e.Request().Context()
20
+
logger := s.logger.With("name", "handleServerResetPassword")
20
21
21
22
urepo := e.Get("repo").(*models.RepoActor)
22
23
23
24
var req ComAtprotoServerResetPasswordRequest
24
25
if err := e.Bind(&req); err != nil {
25
-
s.logger.Error("error binding", "error", err)
26
+
logger.Error("error binding", "error", err)
26
27
return helpers.ServerError(e, nil)
27
28
}
28
29
···
44
45
45
46
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10)
46
47
if err != nil {
47
-
s.logger.Error("error creating hash", "error", err)
48
+
logger.Error("error creating hash", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
51
52
if err := s.db.Exec(ctx, "UPDATE repos SET password_reset_code = NULL, password_reset_code_expires_at = NULL, password = ? WHERE did = ?", nil, hash, urepo.Repo.Did).Error; err != nil {
52
-
s.logger.Error("error updating repo", "error", err)
53
+
logger.Error("error updating repo", "error", err)
53
54
return helpers.ServerError(e, nil)
54
55
}
55
56
+3
-1
server/handle_server_resolve_handle.go
+3
-1
server/handle_server_resolve_handle.go
···
10
10
)
11
11
12
12
func (s *Server) handleResolveHandle(e echo.Context) error {
13
+
logger := s.logger.With("name", "handleServerResolveHandle")
14
+
13
15
type Resp struct {
14
16
Did string `json:"did"`
15
17
}
···
28
30
ctx := context.WithValue(e.Request().Context(), "skip-cache", true)
29
31
did, err := s.passport.ResolveHandle(ctx, parsed.String())
30
32
if err != nil {
31
-
s.logger.Error("error resolving handle", "error", err)
33
+
logger.Error("error resolving handle", "error", err)
32
34
return helpers.ServerError(e, nil)
33
35
}
34
36
+32
-9
server/handle_server_update_email.go
+32
-9
server/handle_server_update_email.go
···
11
11
type ComAtprotoServerUpdateEmailRequest struct {
12
12
Email string `json:"email" validate:"required"`
13
13
EmailAuthFactor bool `json:"emailAuthFactor"`
14
-
Token string `json:"token" validate:"required"`
14
+
Token string `json:"token"`
15
15
}
16
16
17
17
func (s *Server) handleServerUpdateEmail(e echo.Context) error {
18
18
ctx := e.Request().Context()
19
+
logger := s.logger.With("name", "handleServerUpdateEmail")
19
20
20
21
urepo := e.Get("repo").(*models.RepoActor)
21
22
22
23
var req ComAtprotoServerUpdateEmailRequest
23
24
if err := e.Bind(&req); err != nil {
24
-
s.logger.Error("error binding", "error", err)
25
+
logger.Error("error binding", "error", err)
25
26
return helpers.ServerError(e, nil)
26
27
}
27
28
···
29
30
return helpers.InputError(e, nil)
30
31
}
31
32
32
-
if urepo.EmailUpdateCode == nil || urepo.EmailUpdateCodeExpiresAt == nil {
33
+
// To disable email auth factor a token is required.
34
+
// To enable email auth factor a token is not required.
35
+
// If updating an email address, a token will be sent anyway
36
+
if urepo.TwoFactorType != models.TwoFactorTypeNone && req.EmailAuthFactor == false && req.Token == "" {
33
37
return helpers.InvalidTokenError(e)
34
38
}
35
39
36
-
if *urepo.EmailUpdateCode != req.Token {
37
-
return helpers.InvalidTokenError(e)
40
+
if req.Token != "" {
41
+
if urepo.EmailUpdateCode == nil || urepo.EmailUpdateCodeExpiresAt == nil {
42
+
return helpers.InvalidTokenError(e)
43
+
}
44
+
45
+
if *urepo.EmailUpdateCode != req.Token {
46
+
return helpers.InvalidTokenError(e)
47
+
}
48
+
49
+
if time.Now().UTC().After(*urepo.EmailUpdateCodeExpiresAt) {
50
+
return helpers.ExpiredTokenError(e)
51
+
}
38
52
}
39
53
40
-
if time.Now().UTC().After(*urepo.EmailUpdateCodeExpiresAt) {
41
-
return helpers.ExpiredTokenError(e)
54
+
twoFactorType := models.TwoFactorTypeNone
55
+
if req.EmailAuthFactor {
56
+
twoFactorType = models.TwoFactorTypeEmail
42
57
}
43
58
44
-
if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = NULL, email_update_code_expires_at = NULL, email_confirmed_at = NULL, email = ? WHERE did = ?", nil, req.Email, urepo.Repo.Did).Error; err != nil {
45
-
s.logger.Error("error updating repo", "error", err)
59
+
query := "UPDATE repos SET email_update_code = NULL, email_update_code_expires_at = NULL, two_factor_type = ?, email = ?"
60
+
61
+
if urepo.Email != req.Email {
62
+
query += ",email_confirmed_at = NULL"
63
+
}
64
+
65
+
query += " WHERE did = ?"
66
+
67
+
if err := s.db.Exec(ctx, query, nil, twoFactorType, req.Email, urepo.Repo.Did).Error; err != nil {
68
+
logger.Error("error updating repo", "error", err)
46
69
return helpers.ServerError(e, nil)
47
70
}
48
71
+9
-8
server/handle_sync_get_blob.go
+9
-8
server/handle_sync_get_blob.go
···
18
18
19
19
func (s *Server) handleSyncGetBlob(e echo.Context) error {
20
20
ctx := e.Request().Context()
21
+
logger := s.logger.With("name", "handleSyncGetBlob")
21
22
22
23
did := e.QueryParam("did")
23
24
if did == "" {
···
36
37
37
38
urepo, err := s.getRepoActorByDid(ctx, did)
38
39
if err != nil {
39
-
s.logger.Error("could not find user for requested blob", "error", err)
40
+
logger.Error("could not find user for requested blob", "error", err)
40
41
return helpers.InputError(e, nil)
41
42
}
42
43
···
49
50
50
51
var blob models.Blob
51
52
if err := s.db.Raw(ctx, "SELECT * FROM blobs WHERE did = ? AND cid = ?", nil, did, c.Bytes()).Scan(&blob).Error; err != nil {
52
-
s.logger.Error("error looking up blob", "error", err)
53
+
logger.Error("error looking up blob", "error", err)
53
54
return helpers.ServerError(e, nil)
54
55
}
55
56
···
58
59
if blob.Storage == "sqlite" {
59
60
var parts []models.BlobPart
60
61
if err := s.db.Raw(ctx, "SELECT * FROM blob_parts WHERE blob_id = ? ORDER BY idx", nil, blob.ID).Scan(&parts).Error; err != nil {
61
-
s.logger.Error("error getting blob parts", "error", err)
62
+
logger.Error("error getting blob parts", "error", err)
62
63
return helpers.ServerError(e, nil)
63
64
}
64
65
···
68
69
}
69
70
} else if blob.Storage == "s3" {
70
71
if !(s.s3Config != nil && s.s3Config.BlobstoreEnabled) {
71
-
s.logger.Error("s3 storage disabled")
72
+
logger.Error("s3 storage disabled")
72
73
return helpers.ServerError(e, nil)
73
74
}
74
75
···
91
92
92
93
sess, err := session.NewSession(config)
93
94
if err != nil {
94
-
s.logger.Error("error creating aws session", "error", err)
95
+
logger.Error("error creating aws session", "error", err)
95
96
return helpers.ServerError(e, nil)
96
97
}
97
98
···
100
101
Bucket: aws.String(s.s3Config.Bucket),
101
102
Key: aws.String(blobKey),
102
103
}); err != nil {
103
-
s.logger.Error("error getting blob from s3", "error", err)
104
+
logger.Error("error getting blob from s3", "error", err)
104
105
return helpers.ServerError(e, nil)
105
106
} else {
106
107
read := 0
···
114
115
break
115
116
}
116
117
} else if err != nil && err != io.ErrUnexpectedEOF {
117
-
s.logger.Error("error reading blob", "error", err)
118
+
logger.Error("error reading blob", "error", err)
118
119
return helpers.ServerError(e, nil)
119
120
}
120
121
···
125
126
}
126
127
}
127
128
} else {
128
-
s.logger.Error("unknown storage", "storage", blob.Storage)
129
+
logger.Error("unknown storage", "storage", blob.Storage)
129
130
return helpers.ServerError(e, nil)
130
131
}
131
132
+2
-1
server/handle_sync_get_blocks.go
+2
-1
server/handle_sync_get_blocks.go
···
18
18
19
19
func (s *Server) handleGetBlocks(e echo.Context) error {
20
20
ctx := e.Request().Context()
21
+
logger := s.logger.With("name", "handleSyncGetBlocks")
21
22
22
23
var req ComAtprotoSyncGetBlocksRequest
23
24
if err := e.Bind(&req); err != nil {
···
52
53
})
53
54
54
55
if _, err := carstore.LdWrite(buf, hb); err != nil {
55
-
s.logger.Error("error writing to car", "error", err)
56
+
logger.Error("error writing to car", "error", err)
56
57
return helpers.ServerError(e, nil)
57
58
}
58
59
+4
-3
server/handle_sync_get_record.go
+4
-3
server/handle_sync_get_record.go
···
14
14
15
15
func (s *Server) handleSyncGetRecord(e echo.Context) error {
16
16
ctx := e.Request().Context()
17
+
logger := s.logger.With("name", "handleSyncGetRecord")
17
18
18
19
did := e.QueryParam("did")
19
20
collection := e.QueryParam("collection")
···
21
22
22
23
var urepo models.Repo
23
24
if err := s.db.Raw(ctx, "SELECT * FROM repos WHERE did = ?", nil, did).Scan(&urepo).Error; err != nil {
24
-
s.logger.Error("error getting repo", "error", err)
25
+
logger.Error("error getting repo", "error", err)
25
26
return helpers.ServerError(e, nil)
26
27
}
27
28
···
38
39
})
39
40
40
41
if _, err := carstore.LdWrite(buf, hb); err != nil {
41
-
s.logger.Error("error writing to car", "error", err)
42
+
logger.Error("error writing to car", "error", err)
42
43
return helpers.ServerError(e, nil)
43
44
}
44
45
45
46
for _, blk := range blocks {
46
47
if _, err := carstore.LdWrite(buf, blk.Cid().Bytes(), blk.RawData()); err != nil {
47
-
s.logger.Error("error writing to car", "error", err)
48
+
logger.Error("error writing to car", "error", err)
48
49
return helpers.ServerError(e, nil)
49
50
}
50
51
}
+2
-1
server/handle_sync_get_repo.go
+2
-1
server/handle_sync_get_repo.go
···
14
14
15
15
func (s *Server) handleSyncGetRepo(e echo.Context) error {
16
16
ctx := e.Request().Context()
17
+
logger := s.logger.With("name", "handleSyncGetRepo")
17
18
18
19
did := e.QueryParam("did")
19
20
if did == "" {
···
38
39
buf := new(bytes.Buffer)
39
40
40
41
if _, err := carstore.LdWrite(buf, hb); err != nil {
41
-
s.logger.Error("error writing to car", "error", err)
42
+
logger.Error("error writing to car", "error", err)
42
43
return helpers.ServerError(e, nil)
43
44
}
44
45
+4
-3
server/handle_sync_list_blobs.go
+4
-3
server/handle_sync_list_blobs.go
···
15
15
16
16
func (s *Server) handleSyncListBlobs(e echo.Context) error {
17
17
ctx := e.Request().Context()
18
+
logger := s.logger.With("name", "handleSyncListBlobs")
18
19
19
20
did := e.QueryParam("did")
20
21
if did == "" {
···
39
40
40
41
urepo, err := s.getRepoActorByDid(ctx, did)
41
42
if err != nil {
42
-
s.logger.Error("could not find user for requested blobs", "error", err)
43
+
logger.Error("could not find user for requested blobs", "error", err)
43
44
return helpers.InputError(e, nil)
44
45
}
45
46
···
52
53
53
54
var blobs []models.Blob
54
55
if err := s.db.Raw(ctx, "SELECT * FROM blobs WHERE did = ? "+cursorquery+" ORDER BY created_at DESC LIMIT ?", nil, params...).Scan(&blobs).Error; err != nil {
55
-
s.logger.Error("error getting records", "error", err)
56
+
logger.Error("error getting records", "error", err)
56
57
return helpers.ServerError(e, nil)
57
58
}
58
59
···
60
61
for _, b := range blobs {
61
62
c, err := cid.Cast(b.Cid)
62
63
if err != nil {
63
-
s.logger.Error("error casting cid", "error", err)
64
+
logger.Error("error casting cid", "error", err)
64
65
return helpers.ServerError(e, nil)
65
66
}
66
67
cstrs = append(cstrs, c.String())
+82
-50
server/handle_sync_subscribe_repos.go
+82
-50
server/handle_sync_subscribe_repos.go
···
7
7
"github.com/bluesky-social/indigo/events"
8
8
"github.com/bluesky-social/indigo/lex/util"
9
9
"github.com/btcsuite/websocket"
10
+
"github.com/haileyok/cocoon/metrics"
10
11
"github.com/labstack/echo/v4"
11
12
)
12
13
13
14
func (s *Server) handleSyncSubscribeRepos(e echo.Context) error {
14
-
ctx := e.Request().Context()
15
+
ctx, cancel := context.WithCancel(e.Request().Context())
16
+
defer cancel()
17
+
15
18
logger := s.logger.With("component", "subscribe-repos-websocket")
16
19
17
20
conn, err := websocket.Upgrade(e.Response().Writer, e.Request(), e.Response().Header(), 1<<10, 1<<10)
···
24
27
logger = logger.With("ident", ident)
25
28
logger.Info("new connection established")
26
29
27
-
evts, cancel, err := s.evtman.Subscribe(ctx, ident, func(evt *events.XRPCStreamEvent) bool {
30
+
metrics.RelaysConnected.WithLabelValues(ident).Inc()
31
+
defer func() {
32
+
metrics.RelaysConnected.WithLabelValues(ident).Dec()
33
+
}()
34
+
35
+
evts, evtManCancel, err := s.evtman.Subscribe(ctx, ident, func(evt *events.XRPCStreamEvent) bool {
28
36
return true
29
37
}, nil)
30
38
if err != nil {
31
39
return err
32
40
}
33
-
defer cancel()
41
+
defer evtManCancel()
42
+
43
+
// drop the connection whenever a subscriber disconnects from the socket, we should get errors
44
+
go func() {
45
+
for {
46
+
select {
47
+
case <-ctx.Done():
48
+
return
49
+
default:
50
+
if _, _, err := conn.ReadMessage(); err != nil {
51
+
logger.Warn("websocket error", "err", err)
52
+
cancel()
53
+
return
54
+
}
55
+
}
56
+
}
57
+
}()
34
58
35
59
header := events.EventHeader{Op: events.EvtKindMessage}
36
60
for evt := range evts {
37
-
wc, err := conn.NextWriter(websocket.BinaryMessage)
38
-
if err != nil {
39
-
logger.Error("error writing message to relay", "err", err)
40
-
break
41
-
}
61
+
func() {
62
+
defer func() {
63
+
metrics.RelaySends.WithLabelValues(ident, header.MsgType).Inc()
64
+
}()
42
65
43
-
if ctx.Err() != nil {
44
-
logger.Error("context error", "err", err)
45
-
break
46
-
}
66
+
wc, err := conn.NextWriter(websocket.BinaryMessage)
67
+
if err != nil {
68
+
logger.Error("error writing message to relay", "err", err)
69
+
return
70
+
}
47
71
48
-
var obj util.CBOR
49
-
switch {
50
-
case evt.Error != nil:
51
-
header.Op = events.EvtKindErrorFrame
52
-
obj = evt.Error
53
-
case evt.RepoCommit != nil:
54
-
header.MsgType = "#commit"
55
-
obj = evt.RepoCommit
56
-
case evt.RepoIdentity != nil:
57
-
header.MsgType = "#identity"
58
-
obj = evt.RepoIdentity
59
-
case evt.RepoAccount != nil:
60
-
header.MsgType = "#account"
61
-
obj = evt.RepoAccount
62
-
case evt.RepoInfo != nil:
63
-
header.MsgType = "#info"
64
-
obj = evt.RepoInfo
65
-
default:
66
-
logger.Warn("unrecognized event kind")
67
-
return nil
68
-
}
72
+
if ctx.Err() != nil {
73
+
logger.Error("context error", "err", err)
74
+
return
75
+
}
69
76
70
-
if err := header.MarshalCBOR(wc); err != nil {
71
-
logger.Error("failed to write header to relay", "err", err)
72
-
break
73
-
}
77
+
var obj util.CBOR
78
+
switch {
79
+
case evt.Error != nil:
80
+
header.Op = events.EvtKindErrorFrame
81
+
obj = evt.Error
82
+
case evt.RepoCommit != nil:
83
+
header.MsgType = "#commit"
84
+
obj = evt.RepoCommit
85
+
case evt.RepoIdentity != nil:
86
+
header.MsgType = "#identity"
87
+
obj = evt.RepoIdentity
88
+
case evt.RepoAccount != nil:
89
+
header.MsgType = "#account"
90
+
obj = evt.RepoAccount
91
+
case evt.RepoInfo != nil:
92
+
header.MsgType = "#info"
93
+
obj = evt.RepoInfo
94
+
default:
95
+
logger.Warn("unrecognized event kind")
96
+
return
97
+
}
74
98
75
-
if err := obj.MarshalCBOR(wc); err != nil {
76
-
logger.Error("failed to write event to relay", "err", err)
77
-
break
78
-
}
99
+
if err := header.MarshalCBOR(wc); err != nil {
100
+
logger.Error("failed to write header to relay", "err", err)
101
+
return
102
+
}
103
+
104
+
if err := obj.MarshalCBOR(wc); err != nil {
105
+
logger.Error("failed to write event to relay", "err", err)
106
+
return
107
+
}
79
108
80
-
if err := wc.Close(); err != nil {
81
-
logger.Error("failed to flush-close our event write", "err", err)
82
-
break
83
-
}
109
+
if err := wc.Close(); err != nil {
110
+
logger.Error("failed to flush-close our event write", "err", err)
111
+
return
112
+
}
113
+
}()
84
114
}
85
115
86
116
// we should tell the relay to request a new crawl at this point if we got disconnected
87
117
// use a new context since the old one might be cancelled at this point
88
-
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
89
-
defer cancel()
90
-
if err := s.requestCrawl(ctx); err != nil {
91
-
logger.Error("error requesting crawls", "err", err)
92
-
}
118
+
go func() {
119
+
retryCtx, retryCancel := context.WithTimeout(context.Background(), 10*time.Second)
120
+
defer retryCancel()
121
+
if err := s.requestCrawl(retryCtx); err != nil {
122
+
logger.Error("error requesting crawls", "err", err)
123
+
}
124
+
}()
93
125
94
126
return nil
95
127
}
+2
-1
server/handle_well_known.go
+2
-1
server/handle_well_known.go
···
68
68
69
69
func (s *Server) handleAtprotoDid(e echo.Context) error {
70
70
ctx := e.Request().Context()
71
+
logger := s.logger.With("name", "handleAtprotoDid")
71
72
72
73
host := e.Request().Host
73
74
if host == "" {
···
91
92
if err == gorm.ErrRecordNotFound {
92
93
return e.NoContent(404)
93
94
}
94
-
s.logger.Error("error looking up actor by handle", "error", err)
95
+
logger.Error("error looking up actor by handle", "error", err)
95
96
return helpers.ServerError(e, nil)
96
97
}
97
98
+19
server/mail.go
+19
server/mail.go
···
96
96
97
97
return nil
98
98
}
99
+
100
+
func (s *Server) sendTwoFactorCode(email, handle, code string) error {
101
+
if s.mail == nil {
102
+
return nil
103
+
}
104
+
105
+
s.mailLk.Lock()
106
+
defer s.mailLk.Unlock()
107
+
108
+
s.mail.To(email)
109
+
s.mail.Subject("2FA code for " + s.config.Hostname)
110
+
s.mail.Plain().Set(fmt.Sprintf("Hello %s. Your 2FA code is %s. This code will expire in ten minutes.", handle, code))
111
+
112
+
if err := s.mail.Send(); err != nil {
113
+
return err
114
+
}
115
+
116
+
return nil
117
+
}
+18
-16
server/middleware.go
+18
-16
server/middleware.go
···
38
38
func (s *Server) handleLegacySessionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
39
39
return func(e echo.Context) error {
40
40
ctx := e.Request().Context()
41
+
logger := s.logger.With("name", "handleLegacySessionMiddleware")
41
42
42
43
authheader := e.Request().Header.Get("authorization")
43
44
if authheader == "" {
···
69
70
if hasLxm {
70
71
pts := strings.Split(e.Request().URL.String(), "/")
71
72
if lxm != pts[len(pts)-1] {
72
-
s.logger.Error("service auth lxm incorrect", "lxm", lxm, "expected", pts[len(pts)-1], "error", err)
73
+
logger.Error("service auth lxm incorrect", "lxm", lxm, "expected", pts[len(pts)-1], "error", err)
73
74
return helpers.InputError(e, nil)
74
75
}
75
76
76
77
maybeDid, ok := claims["iss"].(string)
77
78
if !ok {
78
-
s.logger.Error("no iss in service auth token", "error", err)
79
+
logger.Error("no iss in service auth token", "error", err)
79
80
return helpers.InputError(e, nil)
80
81
}
81
82
did = maybeDid
82
83
83
84
maybeRepo, err := s.getRepoActorByDid(ctx, did)
84
85
if err != nil {
85
-
s.logger.Error("error fetching repo", "error", err)
86
+
logger.Error("error fetching repo", "error", err)
86
87
return helpers.ServerError(e, nil)
87
88
}
88
89
repo = maybeRepo
···
96
97
return s.privateKey.Public(), nil
97
98
})
98
99
if err != nil {
99
-
s.logger.Error("error parsing jwt", "error", err)
100
+
logger.Error("error parsing jwt", "error", err)
100
101
return helpers.ExpiredTokenError(e)
101
102
}
102
103
···
109
110
hash := sha256.Sum256([]byte(signingInput))
110
111
sigBytes, err := base64.RawURLEncoding.DecodeString(kpts[2])
111
112
if err != nil {
112
-
s.logger.Error("error decoding signature bytes", "error", err)
113
+
logger.Error("error decoding signature bytes", "error", err)
113
114
return helpers.ServerError(e, nil)
114
115
}
115
116
116
117
if len(sigBytes) != 64 {
117
-
s.logger.Error("incorrect sigbytes length", "length", len(sigBytes))
118
+
logger.Error("incorrect sigbytes length", "length", len(sigBytes))
118
119
return helpers.ServerError(e, nil)
119
120
}
120
121
···
140
141
141
142
sk, err := secp256k1secec.NewPrivateKey(repo.SigningKey)
142
143
if err != nil {
143
-
s.logger.Error("can't load private key", "error", err)
144
+
logger.Error("can't load private key", "error", err)
144
145
return err
145
146
}
146
147
147
148
pubKey, ok := sk.Public().(*secp256k1secec.PublicKey)
148
149
if !ok {
149
-
s.logger.Error("error getting public key from sk")
150
+
logger.Error("error getting public key from sk")
150
151
return helpers.ServerError(e, nil)
151
152
}
152
153
153
154
verified := pubKey.VerifyRaw(hash[:], rr, ss)
154
155
if !verified {
155
-
s.logger.Error("error verifying", "error", err)
156
+
logger.Error("error verifying", "error", err)
156
157
return helpers.ServerError(e, nil)
157
158
}
158
159
}
···
181
182
return helpers.InvalidTokenError(e)
182
183
}
183
184
184
-
s.logger.Error("error getting token from db", "error", err)
185
+
logger.Error("error getting token from db", "error", err)
185
186
return helpers.ServerError(e, nil)
186
187
}
187
188
···
192
193
193
194
exp, ok := claims["exp"].(float64)
194
195
if !ok {
195
-
s.logger.Error("error getting iat from token")
196
+
logger.Error("error getting iat from token")
196
197
return helpers.ServerError(e, nil)
197
198
}
198
199
···
203
204
if repo == nil {
204
205
maybeRepo, err := s.getRepoActorByDid(ctx, claims["sub"].(string))
205
206
if err != nil {
206
-
s.logger.Error("error fetching repo", "error", err)
207
+
logger.Error("error fetching repo", "error", err)
207
208
return helpers.ServerError(e, nil)
208
209
}
209
210
repo = maybeRepo
···
225
226
func (s *Server) handleOauthSessionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
226
227
return func(e echo.Context) error {
227
228
ctx := e.Request().Context()
229
+
logger := s.logger.With("name", "handleOauthSessionMiddleware")
228
230
229
231
authheader := e.Request().Header.Get("authorization")
230
232
if authheader == "" {
···
257
259
"error": "use_dpop_nonce",
258
260
})
259
261
}
260
-
s.logger.Error("invalid dpop proof", "error", err)
262
+
logger.Error("invalid dpop proof", "error", err)
261
263
return helpers.InputError(e, nil)
262
264
}
263
265
264
266
var oauthToken provider.OauthToken
265
267
if err := s.db.Raw(ctx, "SELECT * FROM oauth_tokens WHERE token = ?", nil, accessToken).Scan(&oauthToken).Error; err != nil {
266
-
s.logger.Error("error finding access token in db", "error", err)
268
+
logger.Error("error finding access token in db", "error", err)
267
269
return helpers.InputError(e, nil)
268
270
}
269
271
···
272
274
}
273
275
274
276
if *oauthToken.Parameters.DpopJkt != proof.JKT {
275
-
s.logger.Error("jkt mismatch", "token", oauthToken.Parameters.DpopJkt, "proof", proof.JKT)
277
+
logger.Error("jkt mismatch", "token", oauthToken.Parameters.DpopJkt, "proof", proof.JKT)
276
278
return helpers.InputError(e, to.StringPtr("dpop jkt mismatch"))
277
279
}
278
280
···
287
289
288
290
repo, err := s.getRepoActorByDid(ctx, oauthToken.Sub)
289
291
if err != nil {
290
-
s.logger.Error("could not find actor in db", "error", err)
292
+
logger.Error("could not find actor in db", "error", err)
291
293
return helpers.ServerError(e, nil)
292
294
}
293
295
+7
server/repo.go
+7
server/repo.go
···
17
17
lexutil "github.com/bluesky-social/indigo/lex/util"
18
18
"github.com/bluesky-social/indigo/repo"
19
19
"github.com/haileyok/cocoon/internal/db"
20
+
"github.com/haileyok/cocoon/metrics"
20
21
"github.com/haileyok/cocoon/models"
21
22
"github.com/haileyok/cocoon/recording_blockstore"
22
23
blocks "github.com/ipfs/go-block-format"
···
249
250
newroot, rev, err := r.Commit(ctx, urepo.SignFor)
250
251
if err != nil {
251
252
return nil, err
253
+
}
254
+
255
+
for _, result := range results {
256
+
if result.Type != nil {
257
+
metrics.RepoOperations.WithLabelValues(*result.Type).Inc()
258
+
}
252
259
}
253
260
254
261
// create a buffer for dumping our new cbor into
+73
-72
server/server.go
+73
-72
server/server.go
···
39
39
"github.com/haileyok/cocoon/oauth/provider"
40
40
"github.com/haileyok/cocoon/plc"
41
41
"github.com/ipfs/go-cid"
42
+
"github.com/labstack/echo-contrib/echoprometheus"
42
43
echo_session "github.com/labstack/echo-contrib/session"
43
44
"github.com/labstack/echo/v4"
44
45
"github.com/labstack/echo/v4/middleware"
···
89
90
}
90
91
91
92
type Args struct {
93
+
Logger *slog.Logger
94
+
92
95
Addr string
93
96
DbName string
94
97
DbType string
95
98
DatabaseURL string
96
-
Logger *slog.Logger
97
99
Version string
98
100
Did string
99
101
Hostname string
···
209
211
}
210
212
211
213
func New(args *Args) (*Server, error) {
214
+
if args.Logger == nil {
215
+
args.Logger = slog.Default()
216
+
}
217
+
218
+
logger := args.Logger.With("name", "New")
219
+
212
220
if args.Addr == "" {
213
221
return nil, fmt.Errorf("addr must be set")
214
222
}
···
237
245
return nil, fmt.Errorf("admin password must be set")
238
246
}
239
247
240
-
if args.Logger == nil {
241
-
args.Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))
242
-
}
243
-
244
248
if args.SessionSecret == "" {
245
249
panic("SESSION SECRET WAS NOT SET. THIS IS REQUIRED. ")
246
250
}
···
248
252
e := echo.New()
249
253
250
254
e.Pre(middleware.RemoveTrailingSlash())
251
-
e.Pre(slogecho.New(args.Logger))
255
+
e.Pre(slogecho.New(args.Logger.With("component", "slogecho")))
252
256
e.Use(echo_session.Middleware(sessions.NewCookieStore([]byte(args.SessionSecret))))
257
+
e.Use(echoprometheus.NewMiddleware("cocoon"))
253
258
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
254
259
AllowOrigins: []string{"*"},
255
260
AllowHeaders: []string{"*"},
···
311
316
if err != nil {
312
317
return nil, fmt.Errorf("failed to connect to postgres: %w", err)
313
318
}
314
-
args.Logger.Info("connected to PostgreSQL database")
319
+
logger.Info("connected to PostgreSQL database")
315
320
default:
316
321
gdb, err = gorm.Open(sqlite.Open(args.DbName), &gorm.Config{})
317
322
if err != nil {
318
323
return nil, fmt.Errorf("failed to open sqlite database: %w", err)
319
324
}
320
-
args.Logger.Info("connected to SQLite database", "path", args.DbName)
325
+
gdb.Exec("PRAGMA journal_mode=WAL")
326
+
gdb.Exec("PRAGMA synchronous=NORMAL")
327
+
328
+
logger.Info("connected to SQLite database", "path", args.DbName)
321
329
}
322
330
dbw := db.NewDB(gdb)
323
331
···
360
368
var nonceSecret []byte
361
369
maybeSecret, err := os.ReadFile("nonce.secret")
362
370
if err != nil && !os.IsNotExist(err) {
363
-
args.Logger.Error("error attempting to read nonce secret", "error", err)
371
+
logger.Error("error attempting to read nonce secret", "error", err)
364
372
} else {
365
373
nonceSecret = maybeSecret
366
374
}
···
398
406
Hostname: args.Hostname,
399
407
ClientManagerArgs: client.ManagerArgs{
400
408
Cli: oauthCli,
401
-
Logger: args.Logger,
409
+
Logger: args.Logger.With("component", "oauth-client-manager"),
402
410
},
403
411
DpopManagerArgs: dpop.ManagerArgs{
404
412
NonceSecret: nonceSecret,
405
413
NonceRotationInterval: constants.NonceMaxRotationInterval / 3,
406
414
OnNonceSecretCreated: func(newNonce []byte) {
407
415
if err := os.WriteFile("nonce.secret", newNonce, 0644); err != nil {
408
-
args.Logger.Error("error writing new nonce secret", "error", err)
416
+
logger.Error("error writing new nonce secret", "error", err)
409
417
}
410
418
},
411
-
Logger: args.Logger,
419
+
Logger: args.Logger.With("component", "dpop-manager"),
412
420
Hostname: args.Hostname,
413
421
},
414
422
}),
···
535
543
}
536
544
537
545
func (s *Server) Serve(ctx context.Context) error {
546
+
logger := s.logger.With("name", "Serve")
547
+
538
548
s.addRoutes()
539
549
540
-
s.logger.Info("migrating...")
550
+
logger.Info("migrating...")
541
551
542
552
s.db.AutoMigrate(
543
553
&models.Actor{},
···
554
564
&provider.OauthAuthorizationRequest{},
555
565
)
556
566
557
-
s.logger.Info("starting cocoon")
567
+
logger.Info("starting cocoon")
558
568
559
569
go func() {
560
570
if err := s.httpd.ListenAndServe(); err != nil {
···
566
576
567
577
go func() {
568
578
if err := s.requestCrawl(ctx); err != nil {
569
-
s.logger.Error("error requesting crawls", "err", err)
579
+
logger.Error("error requesting crawls", "err", err)
570
580
}
571
581
}()
572
582
···
584
594
585
595
logger.Info("requesting crawl with configured relays")
586
596
587
-
if time.Now().Sub(s.lastRequestCrawl) <= 1*time.Minute {
597
+
if time.Since(s.lastRequestCrawl) <= 1*time.Minute {
588
598
return fmt.Errorf("a crawl request has already been made within the last minute")
589
599
}
590
600
···
607
617
}
608
618
609
619
func (s *Server) doBackup() {
620
+
logger := s.logger.With("name", "doBackup")
621
+
610
622
if s.dbType == "postgres" {
611
-
s.logger.Info("skipping S3 backup - PostgreSQL backups should be handled externally (pg_dump, managed database backups, etc.)")
623
+
logger.Info("skipping S3 backup - PostgreSQL backups should be handled externally (pg_dump, managed database backups, etc.)")
612
624
return
613
625
}
614
626
615
627
start := time.Now()
616
628
617
-
s.logger.Info("beginning backup to s3...")
629
+
logger.Info("beginning backup to s3...")
618
630
619
-
var buf bytes.Buffer
620
-
if err := func() error {
621
-
s.logger.Info("reading database bytes...")
622
-
s.db.Lock()
623
-
defer s.db.Unlock()
624
-
625
-
sf, err := os.Open(s.dbName)
626
-
if err != nil {
627
-
return fmt.Errorf("error opening database for backup: %w", err)
628
-
}
629
-
defer sf.Close()
631
+
tmpFile := fmt.Sprintf("/tmp/cocoon-backup-%s.db", time.Now().Format(time.RFC3339Nano))
632
+
defer os.Remove(tmpFile)
630
633
631
-
if _, err := io.Copy(&buf, sf); err != nil {
632
-
return fmt.Errorf("error reading bytes of backup db: %w", err)
633
-
}
634
+
if err := s.db.Client().Exec(fmt.Sprintf("VACUUM INTO '%s'", tmpFile)).Error; err != nil {
635
+
logger.Error("error creating tmp backup file", "err", err)
636
+
return
637
+
}
634
638
635
-
return nil
636
-
}(); err != nil {
637
-
s.logger.Error("error backing up database", "error", err)
639
+
backupData, err := os.ReadFile(tmpFile)
640
+
if err != nil {
641
+
logger.Error("error reading tmp backup file", "err", err)
638
642
return
639
643
}
640
644
641
-
if err := func() error {
642
-
s.logger.Info("sending to s3...")
643
-
644
-
currTime := time.Now().Format("2006-01-02_15-04-05")
645
-
key := "cocoon-backup-" + currTime + ".db"
646
-
647
-
config := &aws.Config{
648
-
Region: aws.String(s.s3Config.Region),
649
-
Credentials: credentials.NewStaticCredentials(s.s3Config.AccessKey, s.s3Config.SecretKey, ""),
650
-
}
645
+
logger.Info("sending to s3...")
651
646
652
-
if s.s3Config.Endpoint != "" {
653
-
config.Endpoint = aws.String(s.s3Config.Endpoint)
654
-
config.S3ForcePathStyle = aws.Bool(true)
655
-
}
647
+
currTime := time.Now().Format("2006-01-02_15-04-05")
648
+
key := "cocoon-backup-" + currTime + ".db"
656
649
657
-
sess, err := session.NewSession(config)
658
-
if err != nil {
659
-
return err
660
-
}
650
+
config := &aws.Config{
651
+
Region: aws.String(s.s3Config.Region),
652
+
Credentials: credentials.NewStaticCredentials(s.s3Config.AccessKey, s.s3Config.SecretKey, ""),
653
+
}
661
654
662
-
svc := s3.New(sess)
655
+
if s.s3Config.Endpoint != "" {
656
+
config.Endpoint = aws.String(s.s3Config.Endpoint)
657
+
config.S3ForcePathStyle = aws.Bool(true)
658
+
}
663
659
664
-
if _, err := svc.PutObject(&s3.PutObjectInput{
665
-
Bucket: aws.String(s.s3Config.Bucket),
666
-
Key: aws.String(key),
667
-
Body: bytes.NewReader(buf.Bytes()),
668
-
}); err != nil {
669
-
return fmt.Errorf("error uploading file to s3: %w", err)
670
-
}
660
+
sess, err := session.NewSession(config)
661
+
if err != nil {
662
+
logger.Error("error creating s3 session", "err", err)
663
+
return
664
+
}
671
665
672
-
s.logger.Info("finished uploading backup to s3", "key", key, "duration", time.Now().Sub(start).Seconds())
666
+
svc := s3.New(sess)
673
667
674
-
return nil
675
-
}(); err != nil {
676
-
s.logger.Error("error uploading database backup", "error", err)
668
+
if _, err := svc.PutObject(&s3.PutObjectInput{
669
+
Bucket: aws.String(s.s3Config.Bucket),
670
+
Key: aws.String(key),
671
+
Body: bytes.NewReader(backupData),
672
+
}); err != nil {
673
+
logger.Error("error uploading file to s3", "err", err)
677
674
return
678
675
}
679
676
680
-
os.WriteFile("last-backup.txt", []byte(time.Now().String()), 0644)
677
+
logger.Info("finished uploading backup to s3", "key", key, "duration", time.Since(start).Seconds())
678
+
679
+
os.WriteFile("last-backup.txt", []byte(time.Now().Format(time.RFC3339Nano)), 0644)
681
680
}
682
681
683
682
func (s *Server) backupRoutine() {
683
+
logger := s.logger.With("name", "backupRoutine")
684
+
684
685
if s.s3Config == nil || !s.s3Config.BackupsEnabled {
685
686
return
686
687
}
687
688
688
689
if s.s3Config.Region == "" {
689
-
s.logger.Warn("no s3 region configured but backups are enabled. backups will not run.")
690
+
logger.Warn("no s3 region configured but backups are enabled. backups will not run.")
690
691
return
691
692
}
692
693
693
694
if s.s3Config.Bucket == "" {
694
-
s.logger.Warn("no s3 bucket configured but backups are enabled. backups will not run.")
695
+
logger.Warn("no s3 bucket configured but backups are enabled. backups will not run.")
695
696
return
696
697
}
697
698
698
699
if s.s3Config.AccessKey == "" {
699
-
s.logger.Warn("no s3 access key configured but backups are enabled. backups will not run.")
700
+
logger.Warn("no s3 access key configured but backups are enabled. backups will not run.")
700
701
return
701
702
}
702
703
703
704
if s.s3Config.SecretKey == "" {
704
-
s.logger.Warn("no s3 secret key configured but backups are enabled. backups will not run.")
705
+
logger.Warn("no s3 secret key configured but backups are enabled. backups will not run.")
705
706
return
706
707
}
707
708
···
710
711
if err != nil {
711
712
shouldBackupNow = true
712
713
} else {
713
-
lastBackup, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", string(lastBackupStr))
714
+
lastBackup, err := time.Parse(time.RFC3339Nano, string(lastBackupStr))
714
715
if err != nil {
715
716
shouldBackupNow = true
716
-
} else if time.Now().Sub(lastBackup).Seconds() > 3600 {
717
+
} else if time.Since(lastBackup).Seconds() > 3600 {
717
718
shouldBackupNow = true
718
719
}
719
720
}
+4
server/templates/signin.html
+4
server/templates/signin.html
···
26
26
type="password"
27
27
placeholder="Password"
28
28
/>
29
+
{{ if .flashes.tokenrequired }}
30
+
<br />
31
+
<input name="token" id="token" placeholder="Enter your 2FA token" />
32
+
{{ end }}
29
33
<input name="query_params" type="hidden" value="{{ .QueryParams }}" />
30
34
<button class="primary" type="submit" value="Login">Login</button>
31
35
</form>
+1
-1
sqlite_blockstore/sqlite_blockstore.go
+1
-1
sqlite_blockstore/sqlite_blockstore.go
+1
-1
test.go
+1
-1
test.go
···
32
32
33
33
u.Path = "xrpc/com.atproto.sync.subscribeRepos"
34
34
conn, _, err := dialer.Dial(u.String(), http.Header{
35
-
"User-Agent": []string{fmt.Sprintf("hot-topic/0.0.0")},
35
+
"User-Agent": []string{"cocoon-test/0.0.0"},
36
36
})
37
37
if err != nil {
38
38
return fmt.Errorf("subscribing to firehose failed (dialing): %w", err)