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