+2
.gitignore
+2
.gitignore
+24
appview/oauth/client/oauth_client.go
+24
appview/oauth/client/oauth_client.go
···
1
+
package client
2
+
3
+
import (
4
+
oauth "github.com/haileyok/atproto-oauth-golang"
5
+
"github.com/haileyok/atproto-oauth-golang/helpers"
6
+
)
7
+
8
+
type OAuthClient struct {
9
+
*oauth.Client
10
+
}
11
+
12
+
func NewClient(clientId, clientJwk, redirectUri string) (*OAuthClient, error) {
13
+
k, err := helpers.ParseJWKFromBytes([]byte(clientJwk))
14
+
if err != nil {
15
+
return nil, err
16
+
}
17
+
18
+
cli, err := oauth.NewClient(oauth.ClientArgs{
19
+
ClientId: clientId,
20
+
ClientJwk: k,
21
+
RedirectUri: redirectUri,
22
+
})
23
+
return &OAuthClient{cli}, err
24
+
}
+18
-12
go.mod
+18
-12
go.mod
···
1
1
module tangled.sh/tangled.sh/core
2
2
3
-
go 1.23.0
3
+
go 1.24.0
4
4
5
-
toolchain go1.23.6
5
+
toolchain go1.24.3
6
6
7
7
require (
8
8
github.com/Blank-Xu/sql-adapter v1.1.1
9
9
github.com/alecthomas/chroma/v2 v2.15.0
10
10
github.com/bluekeyes/go-gitdiff v0.8.1
11
-
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20
11
+
github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188
12
12
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1
13
13
github.com/casbin/casbin/v2 v2.103.0
14
14
github.com/cyphar/filepath-securejoin v0.4.1
···
19
19
github.com/go-git/go-git/v5 v5.14.0
20
20
github.com/google/uuid v1.6.0
21
21
github.com/gorilla/sessions v1.4.0
22
+
github.com/haileyok/atproto-oauth-golang v0.0.2
22
23
github.com/ipfs/go-cid v0.5.0
24
+
github.com/lestrrat-go/jwx/v2 v2.0.12
23
25
github.com/mattn/go-sqlite3 v1.14.24
24
26
github.com/microcosm-cc/bluemonday v1.0.27
25
27
github.com/resend/resend-go/v2 v2.15.0
···
41
43
github.com/casbin/govaluate v1.3.0 // indirect
42
44
github.com/cespare/xxhash/v2 v2.3.0 // indirect
43
45
github.com/cloudflare/circl v1.6.0 // indirect
44
-
github.com/davecgh/go-spew v1.1.1 // indirect
46
+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
45
47
github.com/dlclark/regexp2 v1.11.5 // indirect
46
48
github.com/emirpasic/gods v1.18.1 // indirect
47
49
github.com/felixge/httpsnoop v1.0.4 // indirect
48
50
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
49
51
github.com/go-git/go-billy/v5 v5.6.2 // indirect
50
-
github.com/go-logr/logr v1.4.1 // indirect
52
+
github.com/go-logr/logr v1.4.2 // indirect
51
53
github.com/go-logr/stdr v1.2.2 // indirect
52
54
github.com/goccy/go-json v0.10.2 // indirect
53
55
github.com/gogo/protobuf v1.3.2 // indirect
56
+
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
54
57
github.com/gorilla/css v1.0.1 // indirect
55
58
github.com/gorilla/securecookie v1.1.2 // indirect
56
59
github.com/gorilla/websocket v1.5.1 // indirect
···
75
78
github.com/kevinburke/ssh_config v1.2.0 // indirect
76
79
github.com/klauspost/compress v1.17.9 // indirect
77
80
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
81
+
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
82
+
github.com/lestrrat-go/httpcc v1.0.1 // indirect
83
+
github.com/lestrrat-go/httprc v1.0.4 // indirect
84
+
github.com/lestrrat-go/iter v1.0.2 // indirect
85
+
github.com/lestrrat-go/option v1.0.1 // indirect
78
86
github.com/mattn/go-isatty v0.0.20 // indirect
79
87
github.com/minio/sha256-simd v1.0.1 // indirect
80
88
github.com/mr-tron/base58 v1.2.0 // indirect
···
86
94
github.com/opentracing/opentracing-go v1.2.0 // indirect
87
95
github.com/pjbgf/sha1cd v0.3.2 // indirect
88
96
github.com/pkg/errors v0.9.1 // indirect
89
-
github.com/pmezard/go-difflib v1.0.0 // indirect
90
97
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
91
98
github.com/prometheus/client_golang v1.19.1 // indirect
92
99
github.com/prometheus/client_model v0.6.1 // indirect
93
100
github.com/prometheus/common v0.54.0 // indirect
94
101
github.com/prometheus/procfs v0.15.1 // indirect
102
+
github.com/segmentio/asm v1.2.0 // indirect
95
103
github.com/sergi/go-diff v1.3.1 // indirect
96
104
github.com/skeema/knownhosts v1.3.1 // indirect
97
105
github.com/spaolacci/murmur3 v1.1.0 // indirect
98
-
github.com/stretchr/testify v1.10.0 // indirect
99
106
github.com/xanzy/ssh-agent v0.3.3 // indirect
100
107
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
101
108
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
102
109
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
103
-
go.opentelemetry.io/otel v1.21.0 // indirect
104
-
go.opentelemetry.io/otel/metric v1.21.0 // indirect
105
-
go.opentelemetry.io/otel/trace v1.21.0 // indirect
110
+
go.opentelemetry.io/otel v1.29.0 // indirect
111
+
go.opentelemetry.io/otel/metric v1.29.0 // indirect
112
+
go.opentelemetry.io/otel/trace v1.29.0 // indirect
106
113
go.uber.org/atomic v1.11.0 // indirect
107
114
go.uber.org/multierr v1.11.0 // indirect
108
115
go.uber.org/zap v1.26.0 // indirect
109
116
golang.org/x/crypto v0.37.0 // indirect
110
117
golang.org/x/net v0.39.0 // indirect
111
118
golang.org/x/sys v0.32.0 // indirect
112
-
golang.org/x/time v0.5.0 // indirect
119
+
golang.org/x/time v0.8.0 // indirect
113
120
google.golang.org/protobuf v1.34.2 // indirect
114
121
gopkg.in/warnings.v0 v0.1.2 // indirect
115
-
gopkg.in/yaml.v3 v3.0.1 // indirect
116
122
lukechampine.com/blake3 v1.2.1 // indirect
117
123
)
118
124
+61
-16
go.sum
+61
-16
go.sum
···
26
26
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
27
27
github.com/bluekeyes/go-gitdiff v0.8.1 h1:lL1GofKMywO17c0lgQmJYcKek5+s8X6tXVNOLxy4smI=
28
28
github.com/bluekeyes/go-gitdiff v0.8.1/go.mod h1:WWAk1Mc6EgWarCrPFO+xeYlujPu98VuLW3Tu+B/85AE=
29
-
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20 h1:yHusfYYi8odoCcsI6AurU+dRWb7itHAQNwt3/Rl9Vfs=
30
-
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20/go.mod h1:Qp4YqWf+AQ3TwQCxV5Ls8O2tXE55zVTGVs3zTmn7BOg=
29
+
github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188 h1:1sQaG37xk08/rpmdhrmMkfQWF9kZbnfHm9Zav3bbSMk=
30
+
github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188/go.mod h1:NVBwZvbBSa93kfyweAmKwOLYawdVHdwZ9s+GZtBBVLA=
31
31
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1 h1:CFvRtYNSnWRAi/98M3O466t9dYuwtesNbu6FVPymRrA=
32
32
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1/go.mod h1:WiYEeyJSdUwqoaZ71KJSpTblemUCpwJfh5oVXplK6T4=
33
33
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
···
52
52
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
53
53
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
54
54
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
56
55
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
56
+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
57
+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
58
+
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
59
+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
60
+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
57
61
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
58
62
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
59
63
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
···
82
86
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
83
87
github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
84
88
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
85
-
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
86
-
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
89
+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
90
+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
87
91
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
88
92
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
89
93
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
···
91
95
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
92
96
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
93
97
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
98
+
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
99
+
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
94
100
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
95
101
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
96
102
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
···
111
117
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
112
118
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
113
119
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
120
+
github.com/haileyok/atproto-oauth-golang v0.0.2 h1:61KPkLB615LQXR2f5x1v3sf6vPe6dOXqNpTYCgZ0Fz8=
121
+
github.com/haileyok/atproto-oauth-golang v0.0.2/go.mod h1:jcZ4GCjo5I5RuE/RsAXg1/b6udw7R4W+2rb/cGyTDK8=
114
122
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
115
123
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
116
124
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
···
159
167
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
160
168
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
161
169
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
170
+
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
171
+
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
162
172
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
163
173
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
164
174
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
···
177
187
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
178
188
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
179
189
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
190
+
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
191
+
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
192
+
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
193
+
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
194
+
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
195
+
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
196
+
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
197
+
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
198
+
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
199
+
github.com/lestrrat-go/jwx/v2 v2.0.12 h1:3d589+5w/b9b7S3DneICPW16AqTyYXB7VRjgluSDWeA=
200
+
github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G/0y2qUjAQuQ=
201
+
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
202
+
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
203
+
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
180
204
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
181
205
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
182
206
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
···
212
236
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
213
237
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
214
238
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
215
-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
216
239
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
240
+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
241
+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
217
242
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
218
243
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
219
244
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
···
227
252
github.com/resend/resend-go/v2 v2.15.0 h1:B6oMEPf8IEQwn2Ovx/9yymkESLDSeNfLFaNMw+mzHhE=
228
253
github.com/resend/resend-go/v2 v2.15.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ=
229
254
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
230
-
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
231
-
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
255
+
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
256
+
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
232
257
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
258
+
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
259
+
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
233
260
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
234
261
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
235
262
github.com/sethvargo/go-envconfig v1.1.0 h1:cWZiJxeTm7AlCvzGXrEXaSTCNgip5oJepekh/BOQuog=
···
246
273
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
247
274
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
248
275
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
276
+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
277
+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
249
278
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
250
279
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
251
280
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
281
+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
252
282
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
283
+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
284
+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
285
+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
253
286
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
254
287
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
255
288
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
···
270
303
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
271
304
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
272
305
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
273
-
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
274
-
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
275
-
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
276
-
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
277
-
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
278
-
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
306
+
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
307
+
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
308
+
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
309
+
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
310
+
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
311
+
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
279
312
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
280
313
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
281
314
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
···
303
336
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
304
337
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
305
338
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
339
+
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
306
340
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
307
341
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
308
342
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
···
314
348
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
315
349
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
316
350
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
351
+
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
317
352
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
318
353
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
319
354
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
···
327
362
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
328
363
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
329
364
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
365
+
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
330
366
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
331
367
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
332
368
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
···
334
370
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
335
371
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
336
372
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
373
+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
337
374
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
338
375
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
339
376
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
···
348
385
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
349
386
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
350
387
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
388
+
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
351
389
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
352
390
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
353
391
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
···
357
395
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
358
396
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
359
397
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
398
+
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
399
+
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
360
400
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
361
401
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
362
402
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
···
364
404
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
365
405
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
366
406
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
407
+
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
408
+
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
367
409
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
368
410
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
369
411
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
···
372
414
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
373
415
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
374
416
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
417
+
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
418
+
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
375
419
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
376
420
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
377
-
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
378
-
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
421
+
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
422
+
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
379
423
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
380
424
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
381
425
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
···
389
433
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
390
434
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
391
435
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
436
+
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
392
437
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
393
438
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
394
439
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+80
appview/xrpcclient/xrpc.go
+80
appview/xrpcclient/xrpc.go
···
1
+
package xrpcclient
2
+
3
+
import (
4
+
"bytes"
5
+
"context"
6
+
"io"
7
+
8
+
"github.com/bluesky-social/indigo/api/atproto"
9
+
"github.com/bluesky-social/indigo/xrpc"
10
+
oauth "github.com/haileyok/atproto-oauth-golang"
11
+
)
12
+
13
+
type Client struct {
14
+
*oauth.XrpcClient
15
+
authArgs *oauth.XrpcAuthedRequestArgs
16
+
}
17
+
18
+
func NewClient(client *oauth.XrpcClient, authArgs *oauth.XrpcAuthedRequestArgs) *Client {
19
+
return &Client{
20
+
XrpcClient: client,
21
+
authArgs: authArgs,
22
+
}
23
+
}
24
+
25
+
func (c *Client) RepoPutRecord(ctx context.Context, input *atproto.RepoPutRecord_Input) (*atproto.RepoPutRecord_Output, error) {
26
+
var out atproto.RepoPutRecord_Output
27
+
if err := c.Do(ctx, c.authArgs, xrpc.Procedure, "application/json", "com.atproto.repo.putRecord", nil, input, &out); err != nil {
28
+
return nil, err
29
+
}
30
+
31
+
return &out, nil
32
+
}
33
+
34
+
func (c *Client) RepoGetRecord(ctx context.Context, cid string, collection string, repo string, rkey string) (*atproto.RepoGetRecord_Output, error) {
35
+
var out atproto.RepoGetRecord_Output
36
+
37
+
params := map[string]interface{}{
38
+
"cid": cid,
39
+
"collection": collection,
40
+
"repo": repo,
41
+
"rkey": rkey,
42
+
}
43
+
if err := c.Do(ctx, c.authArgs, xrpc.Query, "", "com.atproto.repo.getRecord", params, nil, &out); err != nil {
44
+
return nil, err
45
+
}
46
+
47
+
return &out, nil
48
+
}
49
+
50
+
func (c *Client) RepoUploadBlob(ctx context.Context, input io.Reader) (*atproto.RepoUploadBlob_Output, error) {
51
+
var out atproto.RepoUploadBlob_Output
52
+
if err := c.Do(ctx, c.authArgs, xrpc.Procedure, "*/*", "com.atproto.repo.uploadBlob", nil, input, &out); err != nil {
53
+
return nil, err
54
+
}
55
+
56
+
return &out, nil
57
+
}
58
+
59
+
func (c *Client) SyncGetBlob(ctx context.Context, cid string, did string) ([]byte, error) {
60
+
buf := new(bytes.Buffer)
61
+
62
+
params := map[string]interface{}{
63
+
"cid": cid,
64
+
"did": did,
65
+
}
66
+
if err := c.Do(ctx, c.authArgs, xrpc.Query, "", "com.atproto.sync.getBlob", params, nil, buf); err != nil {
67
+
return nil, err
68
+
}
69
+
70
+
return buf.Bytes(), nil
71
+
}
72
+
73
+
func (c *Client) RepoDeleteRecord(ctx context.Context, input *atproto.RepoDeleteRecord_Input) (*atproto.RepoDeleteRecord_Output, error) {
74
+
var out atproto.RepoDeleteRecord_Output
75
+
if err := c.Do(ctx, c.authArgs, xrpc.Procedure, "application/json", "com.atproto.repo.deleteRecord", nil, input, &out); err != nil {
76
+
return nil, err
77
+
}
78
+
79
+
return &out, nil
80
+
}
+1
-1
.air/appview.toml
+1
-1
.air/appview.toml
+37
-10
appview/config.go
+37
-10
appview/config.go
···
6
6
"github.com/sethvargo/go-envconfig"
7
7
)
8
8
9
+
type CoreConfig struct {
10
+
CookieSecret string `env:"COOKIE_SECRET, default=00000000000000000000000000000000"`
11
+
DbPath string `env:"DB_PATH, default=appview.db"`
12
+
ListenAddr string `env:"LISTEN_ADDR, default=0.0.0.0:3000"`
13
+
AppviewHost string `env:"APPVIEW_HOST, default=https://tangled.sh"`
14
+
Dev bool `env:"DEV, default=false"`
15
+
}
16
+
17
+
type OAuthConfig struct {
18
+
Jwks string `env:"JWKS"`
19
+
ServerMetadataUrl string `env:"SERVER_METADATA_URL"`
20
+
}
21
+
22
+
type JetstreamConfig struct {
23
+
Endpoint string `env:"ENDPOINT, default=wss://jetstream1.us-east.bsky.network/subscribe"`
24
+
}
25
+
26
+
type ResendConfig struct {
27
+
ApiKey string `env:"API_KEY"`
28
+
}
29
+
30
+
type CamoConfig struct {
31
+
Host string `env:"HOST, default=https://camo.tangled.sh"`
32
+
SharedSecret string `env:"SHARED_SECRET"`
33
+
}
34
+
35
+
type AvatarConfig struct {
36
+
Host string `env:"HOST, default=https://avatar.tangled.sh"`
37
+
SharedSecret string `env:"SHARED_SECRET"`
38
+
}
39
+
9
40
type Config struct {
10
-
CookieSecret string `env:"TANGLED_COOKIE_SECRET, default=00000000000000000000000000000000"`
11
-
DbPath string `env:"TANGLED_DB_PATH, default=appview.db"`
12
-
ListenAddr string `env:"TANGLED_LISTEN_ADDR, default=0.0.0.0:3000"`
13
-
Dev bool `env:"TANGLED_DEV, default=false"`
14
-
JetstreamEndpoint string `env:"TANGLED_JETSTREAM_ENDPOINT, default=wss://jetstream1.us-east.bsky.network/subscribe"`
15
-
ResendApiKey string `env:"TANGLED_RESEND_API_KEY"`
16
-
CamoHost string `env:"TANGLED_CAMO_HOST, default=https://camo.tangled.sh"`
17
-
CamoSharedSecret string `env:"TANGLED_CAMO_SHARED_SECRET"`
18
-
AvatarSharedSecret string `env:"TANGLED_AVATAR_SHARED_SECRET"`
19
-
AvatarHost string `env:"TANGLED_AVATAR_HOST, default=https://avatar.tangled.sh"`
41
+
Core CoreConfig `env:",prefix=TANGLED_"`
42
+
Jetstream JetstreamConfig `env:",prefix=TANGLED_JETSTREAM_"`
43
+
Resend ResendConfig `env:",prefix=TANGLED_RESEND_"`
44
+
Camo CamoConfig `env:",prefix=TANGLED_CAMO_"`
45
+
Avatar AvatarConfig `env:",prefix=TANGLED_AVATAR_"`
46
+
OAuth OAuthConfig `env:",prefix=TANGLED_OAUTH_"`
20
47
}
21
48
22
49
func LoadConfig(ctx context.Context) (*Config, error) {
+3
appview/consts.go
+3
appview/consts.go
+26
appview/db/db.go
+26
appview/db/db.go
···
288
288
foreign key (at_uri) references repos(at_uri) on delete cascade
289
289
);
290
290
291
+
create table if not exists oauth_requests (
292
+
id integer primary key autoincrement,
293
+
auth_server_iss text not null,
294
+
state text not null,
295
+
did text not null,
296
+
handle text not null,
297
+
pds_url text not null,
298
+
pkce_verifier text not null,
299
+
dpop_auth_server_nonce text not null,
300
+
dpop_private_jwk text not null
301
+
);
302
+
303
+
create table if not exists oauth_sessions (
304
+
id integer primary key autoincrement,
305
+
did text not null,
306
+
handle text not null,
307
+
pds_url text not null,
308
+
auth_server_iss text not null,
309
+
access_jwt text not null,
310
+
refresh_jwt text not null,
311
+
dpop_pds_nonce text,
312
+
dpop_auth_server_nonce text not null,
313
+
dpop_private_jwk text not null,
314
+
expiry text not null
315
+
);
316
+
291
317
create table if not exists migrations (
292
318
id integer primary key autoincrement,
293
319
name text unique
+173
appview/db/oauth.go
+173
appview/db/oauth.go
···
1
+
package db
2
+
3
+
type OAuthRequest struct {
4
+
ID uint
5
+
AuthserverIss string
6
+
Handle string
7
+
State string
8
+
Did string
9
+
PdsUrl string
10
+
PkceVerifier string
11
+
DpopAuthserverNonce string
12
+
DpopPrivateJwk string
13
+
}
14
+
15
+
func SaveOAuthRequest(e Execer, oauthRequest OAuthRequest) error {
16
+
_, err := e.Exec(`
17
+
insert into oauth_requests (
18
+
auth_server_iss,
19
+
state,
20
+
handle,
21
+
did,
22
+
pds_url,
23
+
pkce_verifier,
24
+
dpop_auth_server_nonce,
25
+
dpop_private_jwk
26
+
) values (?, ?, ?, ?, ?, ?, ?, ?)`,
27
+
oauthRequest.AuthserverIss,
28
+
oauthRequest.State,
29
+
oauthRequest.Handle,
30
+
oauthRequest.Did,
31
+
oauthRequest.PdsUrl,
32
+
oauthRequest.PkceVerifier,
33
+
oauthRequest.DpopAuthserverNonce,
34
+
oauthRequest.DpopPrivateJwk,
35
+
)
36
+
return err
37
+
}
38
+
39
+
func GetOAuthRequestByState(e Execer, state string) (OAuthRequest, error) {
40
+
var req OAuthRequest
41
+
err := e.QueryRow(`
42
+
select
43
+
id,
44
+
auth_server_iss,
45
+
handle,
46
+
state,
47
+
did,
48
+
pds_url,
49
+
pkce_verifier,
50
+
dpop_auth_server_nonce,
51
+
dpop_private_jwk
52
+
from oauth_requests
53
+
where state = ?`, state).Scan(
54
+
&req.ID,
55
+
&req.AuthserverIss,
56
+
&req.Handle,
57
+
&req.State,
58
+
&req.Did,
59
+
&req.PdsUrl,
60
+
&req.PkceVerifier,
61
+
&req.DpopAuthserverNonce,
62
+
&req.DpopPrivateJwk,
63
+
)
64
+
return req, err
65
+
}
66
+
67
+
func DeleteOAuthRequestByState(e Execer, state string) error {
68
+
_, err := e.Exec(`
69
+
delete from oauth_requests
70
+
where state = ?`, state)
71
+
return err
72
+
}
73
+
74
+
type OAuthSession struct {
75
+
ID uint
76
+
Handle string
77
+
Did string
78
+
PdsUrl string
79
+
AccessJwt string
80
+
RefreshJwt string
81
+
AuthServerIss string
82
+
DpopPdsNonce string
83
+
DpopAuthserverNonce string
84
+
DpopPrivateJwk string
85
+
Expiry string
86
+
}
87
+
88
+
func SaveOAuthSession(e Execer, session OAuthSession) error {
89
+
_, err := e.Exec(`
90
+
insert into oauth_sessions (
91
+
did,
92
+
handle,
93
+
pds_url,
94
+
access_jwt,
95
+
refresh_jwt,
96
+
auth_server_iss,
97
+
dpop_auth_server_nonce,
98
+
dpop_private_jwk,
99
+
expiry
100
+
) values (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
101
+
session.Did,
102
+
session.Handle,
103
+
session.PdsUrl,
104
+
session.AccessJwt,
105
+
session.RefreshJwt,
106
+
session.AuthServerIss,
107
+
session.DpopAuthserverNonce,
108
+
session.DpopPrivateJwk,
109
+
session.Expiry,
110
+
)
111
+
return err
112
+
}
113
+
114
+
func RefreshOAuthSession(e Execer, did string, accessJwt, refreshJwt, expiry string) error {
115
+
_, err := e.Exec(`
116
+
update oauth_sessions
117
+
set access_jwt = ?, refresh_jwt = ?, expiry = ?
118
+
where did = ?`,
119
+
accessJwt,
120
+
refreshJwt,
121
+
expiry,
122
+
did,
123
+
)
124
+
return err
125
+
}
126
+
127
+
func GetOAuthSessionByDid(e Execer, did string) (*OAuthSession, error) {
128
+
var session OAuthSession
129
+
err := e.QueryRow(`
130
+
select
131
+
id,
132
+
did,
133
+
handle,
134
+
pds_url,
135
+
access_jwt,
136
+
refresh_jwt,
137
+
auth_server_iss,
138
+
dpop_auth_server_nonce,
139
+
dpop_private_jwk,
140
+
expiry
141
+
from oauth_sessions
142
+
where did = ?`, did).Scan(
143
+
&session.ID,
144
+
&session.Did,
145
+
&session.Handle,
146
+
&session.PdsUrl,
147
+
&session.AccessJwt,
148
+
&session.RefreshJwt,
149
+
&session.AuthServerIss,
150
+
&session.DpopAuthserverNonce,
151
+
&session.DpopPrivateJwk,
152
+
&session.Expiry,
153
+
)
154
+
return &session, err
155
+
}
156
+
157
+
func DeleteOAuthSessionByDid(e Execer, did string) error {
158
+
_, err := e.Exec(`
159
+
delete from oauth_sessions
160
+
where did = ?`, did)
161
+
return err
162
+
}
163
+
164
+
func UpdateDpopPdsNonce(e Execer, did string, dpopPdsNonce string) error {
165
+
_, err := e.Exec(`
166
+
update oauth_sessions
167
+
set dpop_pds_nonce = ?
168
+
where did = ?`,
169
+
dpopPdsNonce,
170
+
did,
171
+
)
172
+
return err
173
+
}
+5
-58
appview/middleware/middleware.go
+5
-58
appview/middleware/middleware.go
···
5
5
"log"
6
6
"net/http"
7
7
"strconv"
8
-
"time"
9
8
10
-
comatproto "github.com/bluesky-social/indigo/api/atproto"
11
-
"github.com/bluesky-social/indigo/xrpc"
12
-
"tangled.sh/tangled.sh/core/appview"
13
-
"tangled.sh/tangled.sh/core/appview/auth"
9
+
"tangled.sh/tangled.sh/core/appview/oauth"
14
10
"tangled.sh/tangled.sh/core/appview/pagination"
15
11
)
16
12
17
13
type Middleware func(http.Handler) http.Handler
18
14
19
-
func AuthMiddleware(a *auth.Auth) Middleware {
15
+
func AuthMiddleware(a *oauth.OAuth) Middleware {
20
16
return func(next http.Handler) http.Handler {
21
17
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22
18
redirectFunc := func(w http.ResponseWriter, r *http.Request) {
···
29
25
}
30
26
}
31
27
32
-
session, err := a.GetSession(r)
33
-
if session.IsNew || err != nil {
28
+
_, auth, err := a.GetSession(r)
29
+
if err != nil {
34
30
log.Printf("not logged in, redirecting")
35
31
redirectFunc(w, r)
36
32
return
37
33
}
38
34
39
-
authorized, ok := session.Values[appview.SessionAuthenticated].(bool)
40
-
if !ok || !authorized {
35
+
if !auth {
41
36
log.Printf("not logged in, redirecting")
42
37
redirectFunc(w, r)
43
38
return
44
39
}
45
40
46
-
// refresh if nearing expiry
47
-
// TODO: dedup with /login
48
-
expiryStr := session.Values[appview.SessionExpiry].(string)
49
-
expiry, err := time.Parse(time.RFC3339, expiryStr)
50
-
if err != nil {
51
-
log.Println("invalid expiry time", err)
52
-
redirectFunc(w, r)
53
-
return
54
-
}
55
-
pdsUrl, ok1 := session.Values[appview.SessionPds].(string)
56
-
did, ok2 := session.Values[appview.SessionDid].(string)
57
-
refreshJwt, ok3 := session.Values[appview.SessionRefreshJwt].(string)
58
-
59
-
if !ok1 || !ok2 || !ok3 {
60
-
log.Println("invalid expiry time", err)
61
-
redirectFunc(w, r)
62
-
return
63
-
}
64
-
65
-
if time.Now().After(expiry) {
66
-
log.Println("token expired, refreshing ...")
67
-
68
-
client := xrpc.Client{
69
-
Host: pdsUrl,
70
-
Auth: &xrpc.AuthInfo{
71
-
Did: did,
72
-
AccessJwt: refreshJwt,
73
-
RefreshJwt: refreshJwt,
74
-
},
75
-
}
76
-
atSession, err := comatproto.ServerRefreshSession(r.Context(), &client)
77
-
if err != nil {
78
-
log.Println("failed to refresh session", err)
79
-
redirectFunc(w, r)
80
-
return
81
-
}
82
-
83
-
sessionish := auth.RefreshSessionWrapper{atSession}
84
-
85
-
err = a.StoreSession(r, w, &sessionish, pdsUrl)
86
-
if err != nil {
87
-
log.Printf("failed to store session for did: %s\n: %s", atSession.Did, err)
88
-
return
89
-
}
90
-
91
-
log.Println("successfully refreshed token")
92
-
}
93
-
94
41
next.ServeHTTP(w, r)
95
42
})
96
43
}
+27
-18
appview/settings/settings.go
+27
-18
appview/settings/settings.go
···
13
13
"github.com/go-chi/chi/v5"
14
14
"tangled.sh/tangled.sh/core/api/tangled"
15
15
"tangled.sh/tangled.sh/core/appview"
16
-
"tangled.sh/tangled.sh/core/appview/auth"
17
16
"tangled.sh/tangled.sh/core/appview/db"
18
17
"tangled.sh/tangled.sh/core/appview/email"
19
18
"tangled.sh/tangled.sh/core/appview/middleware"
19
+
"tangled.sh/tangled.sh/core/appview/oauth"
20
20
"tangled.sh/tangled.sh/core/appview/pages"
21
21
22
22
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
27
27
28
28
type Settings struct {
29
29
Db *db.DB
30
-
Auth *auth.Auth
30
+
OAuth *oauth.OAuth
31
31
Pages *pages.Pages
32
32
Config *appview.Config
33
33
}
···
35
35
func (s *Settings) Router() http.Handler {
36
36
r := chi.NewRouter()
37
37
38
-
r.Use(middleware.AuthMiddleware(s.Auth))
38
+
r.Use(middleware.AuthMiddleware(s.OAuth))
39
39
40
40
r.Get("/", s.settings)
41
41
···
56
56
}
57
57
58
58
func (s *Settings) settings(w http.ResponseWriter, r *http.Request) {
59
-
user := s.Auth.GetUser(r)
59
+
user := s.OAuth.GetUser(r)
60
60
pubKeys, err := db.GetPublicKeys(s.Db, user.Did)
61
61
if err != nil {
62
62
log.Println(err)
···
79
79
verifyURL := s.verifyUrl(did, emailAddr, code)
80
80
81
81
return email.Email{
82
-
APIKey: s.Config.ResendApiKey,
82
+
APIKey: s.Config.Resend.ApiKey,
83
83
From: "noreply@notifs.tangled.sh",
84
84
To: emailAddr,
85
85
Subject: "Verify your Tangled email",
···
111
111
log.Println("unimplemented")
112
112
return
113
113
case http.MethodPut:
114
-
did := s.Auth.GetDid(r)
114
+
did := s.OAuth.GetDid(r)
115
115
emAddr := r.FormValue("email")
116
116
emAddr = strings.TrimSpace(emAddr)
117
117
···
174
174
s.Pages.Notice(w, "settings-emails-success", "Click the link in the email we sent you to verify your email address.")
175
175
return
176
176
case http.MethodDelete:
177
-
did := s.Auth.GetDid(r)
177
+
did := s.OAuth.GetDid(r)
178
178
emailAddr := r.FormValue("email")
179
179
emailAddr = strings.TrimSpace(emailAddr)
180
180
···
207
207
208
208
func (s *Settings) verifyUrl(did string, email string, code string) string {
209
209
var appUrl string
210
-
if s.Config.Dev {
211
-
appUrl = "http://" + s.Config.ListenAddr
210
+
if s.Config.Core.Dev {
211
+
appUrl = "http://" + s.Config.Core.ListenAddr
212
212
} else {
213
213
appUrl = "https://tangled.sh"
214
214
}
···
252
252
return
253
253
}
254
254
255
-
did := s.Auth.GetDid(r)
255
+
did := s.OAuth.GetDid(r)
256
256
emAddr := r.FormValue("email")
257
257
emAddr = strings.TrimSpace(emAddr)
258
258
···
323
323
}
324
324
325
325
func (s *Settings) emailsPrimary(w http.ResponseWriter, r *http.Request) {
326
-
did := s.Auth.GetDid(r)
326
+
did := s.OAuth.GetDid(r)
327
327
emailAddr := r.FormValue("email")
328
328
emailAddr = strings.TrimSpace(emailAddr)
329
329
···
348
348
log.Println("unimplemented")
349
349
return
350
350
case http.MethodPut:
351
-
did := s.Auth.GetDid(r)
351
+
did := s.OAuth.GetDid(r)
352
352
key := r.FormValue("key")
353
353
key = strings.TrimSpace(key)
354
354
name := r.FormValue("name")
355
-
client, _ := s.Auth.AuthorizedClient(r)
355
+
client, err := s.OAuth.AuthorizedClient(r)
356
+
if err != nil {
357
+
s.Pages.Notice(w, "settings-keys", "Failed to authorize. Try again later.")
358
+
return
359
+
}
356
360
357
-
_, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
361
+
_, _, _, _, err = ssh.ParseAuthorizedKey([]byte(key))
358
362
if err != nil {
359
363
log.Printf("parsing public key: %s", err)
360
364
s.Pages.Notice(w, "settings-keys", "That doesn't look like a valid public key. Make sure it's a <strong>public</strong> key.")
···
378
382
}
379
383
380
384
// store in pds too
381
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
385
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
382
386
Collection: tangled.PublicKeyNSID,
383
387
Repo: did,
384
388
Rkey: rkey,
···
409
413
return
410
414
411
415
case http.MethodDelete:
412
-
did := s.Auth.GetDid(r)
416
+
did := s.OAuth.GetDid(r)
413
417
q := r.URL.Query()
414
418
415
419
name := q.Get("name")
···
420
424
log.Println(rkey)
421
425
log.Println(key)
422
426
423
-
client, _ := s.Auth.AuthorizedClient(r)
427
+
client, err := s.OAuth.AuthorizedClient(r)
428
+
if err != nil {
429
+
log.Printf("failed to authorize client: %s", err)
430
+
s.Pages.Notice(w, "settings-keys", "Failed to authorize client.")
431
+
return
432
+
}
424
433
425
434
if err := db.DeletePublicKey(s.Db, did, name, key); err != nil {
426
435
log.Printf("removing public key: %s", err)
···
430
439
431
440
if rkey != "" {
432
441
// remove from pds too
433
-
_, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
442
+
_, err := client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
434
443
Collection: tangled.PublicKeyNSID,
435
444
Repo: did,
436
445
Rkey: rkey,
+19
-10
appview/state/artifact.go
+19
-10
appview/state/artifact.go
···
22
22
23
23
// TODO: proper statuses here on early exit
24
24
func (s *State) AttachArtifact(w http.ResponseWriter, r *http.Request) {
25
-
user := s.auth.GetUser(r)
25
+
user := s.oauth.GetUser(r)
26
26
tagParam := chi.URLParam(r, "tag")
27
27
f, err := s.fullyResolvedRepo(r)
28
28
if err != nil {
···
46
46
}
47
47
defer file.Close()
48
48
49
-
client, _ := s.auth.AuthorizedClient(r)
49
+
client, err := s.oauth.AuthorizedClient(r)
50
+
if err != nil {
51
+
log.Println("failed to get authorized client", err)
52
+
s.pages.Notice(w, "upload", "failed to get authorized client")
53
+
return
54
+
}
50
55
51
-
uploadBlobResp, err := comatproto.RepoUploadBlob(r.Context(), client, file)
56
+
uploadBlobResp, err := client.RepoUploadBlob(r.Context(), file)
52
57
if err != nil {
53
58
log.Println("failed to upload blob", err)
54
59
s.pages.Notice(w, "upload", "Failed to upload blob to your PDS. Try again later.")
···
60
65
rkey := appview.TID()
61
66
createdAt := time.Now()
62
67
63
-
putRecordResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
68
+
putRecordResp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
64
69
Collection: tangled.RepoArtifactNSID,
65
70
Repo: user.Did,
66
71
Rkey: rkey,
···
140
145
return
141
146
}
142
147
143
-
client, _ := s.auth.AuthorizedClient(r)
148
+
client, err := s.oauth.AuthorizedClient(r)
149
+
if err != nil {
150
+
log.Println("failed to get authorized client", err)
151
+
return
152
+
}
144
153
145
154
artifacts, err := db.GetArtifact(
146
155
s.db,
···
159
168
160
169
artifact := artifacts[0]
161
170
162
-
getBlobResp, err := comatproto.SyncGetBlob(r.Context(), client, artifact.BlobCid.String(), artifact.Did)
171
+
getBlobResp, err := client.SyncGetBlob(r.Context(), artifact.BlobCid.String(), artifact.Did)
163
172
if err != nil {
164
173
log.Println("failed to get blob from pds", err)
165
174
return
···
171
180
172
181
// TODO: proper statuses here on early exit
173
182
func (s *State) DeleteArtifact(w http.ResponseWriter, r *http.Request) {
174
-
user := s.auth.GetUser(r)
183
+
user := s.oauth.GetUser(r)
175
184
tagParam := chi.URLParam(r, "tag")
176
185
filename := chi.URLParam(r, "file")
177
186
f, err := s.fullyResolvedRepo(r)
···
180
189
return
181
190
}
182
191
183
-
client, _ := s.auth.AuthorizedClient(r)
192
+
client, _ := s.oauth.AuthorizedClient(r)
184
193
185
194
tag := plumbing.NewHash(tagParam)
186
195
···
208
217
return
209
218
}
210
219
211
-
_, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
220
+
_, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
212
221
Collection: tangled.RepoArtifactNSID,
213
222
Repo: user.Did,
214
223
Rkey: artifact.Rkey,
···
254
263
return nil, err
255
264
}
256
265
257
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
266
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
258
267
if err != nil {
259
268
return nil, err
260
269
}
+8
-4
appview/state/follow.go
+8
-4
appview/state/follow.go
···
14
14
)
15
15
16
16
func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
17
-
currentUser := s.auth.GetUser(r)
17
+
currentUser := s.oauth.GetUser(r)
18
18
19
19
subject := r.URL.Query().Get("subject")
20
20
if subject == "" {
···
32
32
return
33
33
}
34
34
35
-
client, _ := s.auth.AuthorizedClient(r)
35
+
client, err := s.oauth.AuthorizedClient(r)
36
+
if err != nil {
37
+
log.Println("failed to authorize client")
38
+
return
39
+
}
36
40
37
41
switch r.Method {
38
42
case http.MethodPost:
39
43
createdAt := time.Now().Format(time.RFC3339)
40
44
rkey := appview.TID()
41
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
45
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
42
46
Collection: tangled.GraphFollowNSID,
43
47
Repo: currentUser.Did,
44
48
Rkey: rkey,
···
75
79
return
76
80
}
77
81
78
-
_, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
82
+
_, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
79
83
Collection: tangled.GraphFollowNSID,
80
84
Repo: currentUser.Did,
81
85
Rkey: follow.Rkey,
+2
-2
appview/state/git_http.go
+2
-2
appview/state/git_http.go
···
15
15
repo := chi.URLParam(r, "repo")
16
16
17
17
scheme := "https"
18
-
if s.config.Dev {
18
+
if s.config.Core.Dev {
19
19
scheme = "http"
20
20
}
21
21
targetURL := fmt.Sprintf("%s://%s/%s/%s/info/refs?%s", scheme, knot, user.DID, repo, r.URL.RawQuery)
···
52
52
repo := chi.URLParam(r, "repo")
53
53
54
54
scheme := "https"
55
-
if s.config.Dev {
55
+
if s.config.Core.Dev {
56
56
scheme = "http"
57
57
}
58
58
targetURL := fmt.Sprintf("%s://%s/%s/%s/git-upload-pack?%s", scheme, knot, user.DID, repo, r.URL.RawQuery)
+2
-2
appview/state/middleware.go
+2
-2
appview/state/middleware.go
···
20
20
return func(next http.Handler) http.Handler {
21
21
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22
22
// requires auth also
23
-
actor := s.auth.GetUser(r)
23
+
actor := s.oauth.GetUser(r)
24
24
if actor == nil {
25
25
// we need a logged in user
26
26
log.Printf("not logged in, redirecting")
···
54
54
return func(next http.Handler) http.Handler {
55
55
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56
56
// requires auth also
57
-
actor := s.auth.GetUser(r)
57
+
actor := s.oauth.GetUser(r)
58
58
if actor == nil {
59
59
// we need a logged in user
60
60
log.Printf("not logged in, redirecting")
+17
-12
appview/state/profile.go
+17
-12
appview/state/profile.go
···
119
119
log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err)
120
120
}
121
121
122
-
loggedInUser := s.auth.GetUser(r)
122
+
loggedInUser := s.oauth.GetUser(r)
123
123
followStatus := db.IsNotFollowing
124
124
if loggedInUser != nil {
125
125
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···
161
161
log.Printf("getting repos for %s: %s", ident.DID.String(), err)
162
162
}
163
163
164
-
loggedInUser := s.auth.GetUser(r)
164
+
loggedInUser := s.oauth.GetUser(r)
165
165
followStatus := db.IsNotFollowing
166
166
if loggedInUser != nil {
167
167
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···
190
190
}
191
191
192
192
func (s *State) GetAvatarUri(handle string) string {
193
-
secret := s.config.AvatarSharedSecret
193
+
secret := s.config.Avatar.SharedSecret
194
194
h := hmac.New(sha256.New, []byte(secret))
195
195
h.Write([]byte(handle))
196
196
signature := hex.EncodeToString(h.Sum(nil))
197
-
return fmt.Sprintf("%s/%s/%s", s.config.AvatarHost, signature, handle)
197
+
return fmt.Sprintf("%s/%s/%s", s.config.Avatar.Host, signature, handle)
198
198
}
199
199
200
200
func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) {
201
-
user := s.auth.GetUser(r)
201
+
user := s.oauth.GetUser(r)
202
202
203
203
err := r.ParseForm()
204
204
if err != nil {
···
246
246
}
247
247
248
248
func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) {
249
-
user := s.auth.GetUser(r)
249
+
user := s.oauth.GetUser(r)
250
250
251
251
err := r.ParseForm()
252
252
if err != nil {
···
286
286
}
287
287
288
288
func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *http.Request) {
289
-
user := s.auth.GetUser(r)
289
+
user := s.oauth.GetUser(r)
290
290
tx, err := s.db.BeginTx(r.Context(), nil)
291
291
if err != nil {
292
292
log.Println("failed to start transaction", err)
···
294
294
return
295
295
}
296
296
297
-
client, _ := s.auth.AuthorizedClient(r)
297
+
client, err := s.oauth.AuthorizedClient(r)
298
+
if err != nil {
299
+
log.Println("failed to get authorized client", err)
300
+
s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.")
301
+
return
302
+
}
298
303
299
304
// yeah... lexgen dose not support syntax.ATURI in the record for some reason,
300
305
// nor does it support exact size arrays
···
308
313
vanityStats = append(vanityStats, string(v.Kind))
309
314
}
310
315
311
-
ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.ActorProfileNSID, user.Did, "self")
316
+
ex, _ := client.RepoGetRecord(r.Context(), "", tangled.ActorProfileNSID, user.Did, "self")
312
317
var cid *string
313
318
if ex != nil {
314
319
cid = ex.Cid
315
320
}
316
321
317
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
322
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
318
323
Collection: tangled.ActorProfileNSID,
319
324
Repo: user.Did,
320
325
Rkey: "self",
···
347
352
}
348
353
349
354
func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) {
350
-
user := s.auth.GetUser(r)
355
+
user := s.oauth.GetUser(r)
351
356
352
357
profile, err := db.GetProfile(s.db, user.Did)
353
358
if err != nil {
···
361
366
}
362
367
363
368
func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) {
364
-
user := s.auth.GetUser(r)
369
+
user := s.oauth.GetUser(r)
365
370
366
371
profile, err := db.GetProfile(s.db, user.Did)
367
372
if err != nil {
+76
-51
appview/state/pull.go
+76
-51
appview/state/pull.go
···
13
13
14
14
"tangled.sh/tangled.sh/core/api/tangled"
15
15
"tangled.sh/tangled.sh/core/appview"
16
-
"tangled.sh/tangled.sh/core/appview/auth"
17
16
"tangled.sh/tangled.sh/core/appview/db"
17
+
"tangled.sh/tangled.sh/core/appview/oauth"
18
18
"tangled.sh/tangled.sh/core/appview/pages"
19
19
"tangled.sh/tangled.sh/core/patchutil"
20
20
"tangled.sh/tangled.sh/core/types"
···
29
29
func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
30
30
switch r.Method {
31
31
case http.MethodGet:
32
-
user := s.auth.GetUser(r)
32
+
user := s.oauth.GetUser(r)
33
33
f, err := s.fullyResolvedRepo(r)
34
34
if err != nil {
35
35
log.Println("failed to get repo and knot", err)
···
73
73
}
74
74
75
75
func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
76
-
user := s.auth.GetUser(r)
76
+
user := s.oauth.GetUser(r)
77
77
f, err := s.fullyResolvedRepo(r)
78
78
if err != nil {
79
79
log.Println("failed to get repo and knot", err)
···
143
143
}
144
144
}
145
145
146
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
146
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
147
147
if err != nil {
148
148
log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
149
149
return types.MergeCheckResponse{
···
215
215
repoName = f.RepoName
216
216
}
217
217
218
-
us, err := NewUnsignedClient(knot, s.config.Dev)
218
+
us, err := NewUnsignedClient(knot, s.config.Core.Dev)
219
219
if err != nil {
220
220
log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
221
221
return pages.Unknown
···
250
250
}
251
251
252
252
func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
253
-
user := s.auth.GetUser(r)
253
+
user := s.oauth.GetUser(r)
254
254
f, err := s.fullyResolvedRepo(r)
255
255
if err != nil {
256
256
log.Println("failed to get repo and knot", err)
···
298
298
}
299
299
300
300
func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
301
-
user := s.auth.GetUser(r)
301
+
user := s.oauth.GetUser(r)
302
302
303
303
f, err := s.fullyResolvedRepo(r)
304
304
if err != nil {
···
355
355
interdiff := patchutil.Interdiff(previousPatch, currentPatch)
356
356
357
357
s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
358
-
LoggedInUser: s.auth.GetUser(r),
358
+
LoggedInUser: s.oauth.GetUser(r),
359
359
RepoInfo: f.RepoInfo(s, user),
360
360
Pull: pull,
361
361
Round: roundIdInt,
···
397
397
}
398
398
399
399
func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
400
-
user := s.auth.GetUser(r)
400
+
user := s.oauth.GetUser(r)
401
401
params := r.URL.Query()
402
402
403
403
state := db.PullOpen
···
451
451
}
452
452
453
453
s.pages.RepoPulls(w, pages.RepoPullsParams{
454
-
LoggedInUser: s.auth.GetUser(r),
454
+
LoggedInUser: s.oauth.GetUser(r),
455
455
RepoInfo: f.RepoInfo(s, user),
456
456
Pulls: pulls,
457
457
DidHandleMap: didHandleMap,
···
461
461
}
462
462
463
463
func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
464
-
user := s.auth.GetUser(r)
464
+
user := s.oauth.GetUser(r)
465
465
f, err := s.fullyResolvedRepo(r)
466
466
if err != nil {
467
467
log.Println("failed to get repo and knot", err)
···
519
519
}
520
520
521
521
atUri := f.RepoAt.String()
522
-
client, _ := s.auth.AuthorizedClient(r)
523
-
atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
522
+
client, err := s.oauth.AuthorizedClient(r)
523
+
if err != nil {
524
+
log.Println("failed to get authorized client", err)
525
+
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
526
+
return
527
+
}
528
+
atResp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
524
529
Collection: tangled.RepoPullCommentNSID,
525
530
Repo: user.Did,
526
531
Rkey: appview.TID(),
···
568
573
}
569
574
570
575
func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
571
-
user := s.auth.GetUser(r)
576
+
user := s.oauth.GetUser(r)
572
577
f, err := s.fullyResolvedRepo(r)
573
578
if err != nil {
574
579
log.Println("failed to get repo and knot", err)
···
577
582
578
583
switch r.Method {
579
584
case http.MethodGet:
580
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
585
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
581
586
if err != nil {
582
587
log.Printf("failed to create unsigned client for %s", f.Knot)
583
588
s.pages.Error503(w)
···
646
651
return
647
652
}
648
653
649
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
654
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
650
655
if err != nil {
651
656
log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
652
657
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
···
689
694
}
690
695
}
691
696
692
-
func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, sourceBranch string) {
697
+
func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, sourceBranch string) {
693
698
pullSource := &db.PullSource{
694
699
Branch: sourceBranch,
695
700
}
···
698
703
}
699
704
700
705
// Generate a patch using /compare
701
-
ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
706
+
ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
702
707
if err != nil {
703
708
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
704
709
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
723
728
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
724
729
}
725
730
726
-
func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, patch string) {
731
+
func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, patch string) {
727
732
if !patchutil.IsPatchValid(patch) {
728
733
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
729
734
return
···
732
737
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil)
733
738
}
734
739
735
-
func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
740
+
func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
736
741
fork, err := db.GetForkByDid(s.db, user.Did, forkRepo)
737
742
if errors.Is(err, sql.ErrNoRows) {
738
743
s.pages.Notice(w, "pull", "No such fork.")
···
750
755
return
751
756
}
752
757
753
-
sc, err := NewSignedClient(fork.Knot, secret, s.config.Dev)
758
+
sc, err := NewSignedClient(fork.Knot, secret, s.config.Core.Dev)
754
759
if err != nil {
755
760
log.Println("failed to create signed client:", err)
756
761
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
757
762
return
758
763
}
759
764
760
-
us, err := NewUnsignedClient(fork.Knot, s.config.Dev)
765
+
us, err := NewUnsignedClient(fork.Knot, s.config.Core.Dev)
761
766
if err != nil {
762
767
log.Println("failed to create unsigned client:", err)
763
768
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
816
821
w http.ResponseWriter,
817
822
r *http.Request,
818
823
f *FullyResolvedRepo,
819
-
user *auth.User,
824
+
user *oauth.User,
820
825
title, body, targetBranch string,
821
826
patch string,
822
827
sourceRev string,
···
870
875
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
871
876
return
872
877
}
873
-
client, _ := s.auth.AuthorizedClient(r)
878
+
client, err := s.oauth.AuthorizedClient(r)
879
+
if err != nil {
880
+
log.Println("failed to get authorized client", err)
881
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
882
+
return
883
+
}
874
884
pullId, err := db.NextPullId(s.db, f.RepoAt)
875
885
if err != nil {
876
886
log.Println("failed to get pull id", err)
···
878
888
return
879
889
}
880
890
881
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
891
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
882
892
Collection: tangled.RepoPullNSID,
883
893
Repo: user.Did,
884
894
Rkey: rkey,
···
929
939
}
930
940
931
941
func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
932
-
user := s.auth.GetUser(r)
942
+
user := s.oauth.GetUser(r)
933
943
f, err := s.fullyResolvedRepo(r)
934
944
if err != nil {
935
945
log.Println("failed to get repo and knot", err)
···
942
952
}
943
953
944
954
func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
945
-
user := s.auth.GetUser(r)
955
+
user := s.oauth.GetUser(r)
946
956
f, err := s.fullyResolvedRepo(r)
947
957
if err != nil {
948
958
log.Println("failed to get repo and knot", err)
949
959
return
950
960
}
951
961
952
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
962
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
953
963
if err != nil {
954
964
log.Printf("failed to create unsigned client for %s", f.Knot)
955
965
s.pages.Error503(w)
···
982
992
}
983
993
984
994
func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
985
-
user := s.auth.GetUser(r)
995
+
user := s.oauth.GetUser(r)
986
996
f, err := s.fullyResolvedRepo(r)
987
997
if err != nil {
988
998
log.Println("failed to get repo and knot", err)
···
1002
1012
}
1003
1013
1004
1014
func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1005
-
user := s.auth.GetUser(r)
1015
+
user := s.oauth.GetUser(r)
1006
1016
1007
1017
f, err := s.fullyResolvedRepo(r)
1008
1018
if err != nil {
···
1019
1029
return
1020
1030
}
1021
1031
1022
-
sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev)
1032
+
sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Core.Dev)
1023
1033
if err != nil {
1024
1034
log.Printf("failed to create unsigned client for %s", repo.Knot)
1025
1035
s.pages.Error503(w)
···
1046
1056
return
1047
1057
}
1048
1058
1049
-
targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
1059
+
targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
1050
1060
if err != nil {
1051
1061
log.Printf("failed to create unsigned client for target knot %s", f.Knot)
1052
1062
s.pages.Error503(w)
···
1081
1091
}
1082
1092
1083
1093
func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1084
-
user := s.auth.GetUser(r)
1094
+
user := s.oauth.GetUser(r)
1085
1095
f, err := s.fullyResolvedRepo(r)
1086
1096
if err != nil {
1087
1097
log.Println("failed to get repo and knot", err)
···
1117
1127
}
1118
1128
1119
1129
func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1120
-
user := s.auth.GetUser(r)
1130
+
user := s.oauth.GetUser(r)
1121
1131
1122
1132
pull, ok := r.Context().Value("pull").(*db.Pull)
1123
1133
if !ok {
···
1159
1169
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
1160
1170
return
1161
1171
}
1162
-
client, _ := s.auth.AuthorizedClient(r)
1172
+
client, err := s.oauth.AuthorizedClient(r)
1173
+
if err != nil {
1174
+
log.Println("failed to get authorized client", err)
1175
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1176
+
return
1177
+
}
1163
1178
1164
-
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1179
+
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1165
1180
if err != nil {
1166
1181
// failed to get record
1167
1182
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1168
1183
return
1169
1184
}
1170
1185
1171
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1186
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1172
1187
Collection: tangled.RepoPullNSID,
1173
1188
Repo: user.Did,
1174
1189
Rkey: pull.Rkey,
···
1200
1215
}
1201
1216
1202
1217
func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1203
-
user := s.auth.GetUser(r)
1218
+
user := s.oauth.GetUser(r)
1204
1219
1205
1220
pull, ok := r.Context().Value("pull").(*db.Pull)
1206
1221
if !ok {
···
1227
1242
return
1228
1243
}
1229
1244
1230
-
ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
1245
+
ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
1231
1246
if err != nil {
1232
1247
log.Printf("failed to create client for %s: %s", f.Knot, err)
1233
1248
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
1268
1283
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1269
1284
return
1270
1285
}
1271
-
client, _ := s.auth.AuthorizedClient(r)
1286
+
client, err := s.oauth.AuthorizedClient(r)
1287
+
if err != nil {
1288
+
log.Println("failed to authorize client")
1289
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1290
+
return
1291
+
}
1272
1292
1273
-
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1293
+
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1274
1294
if err != nil {
1275
1295
// failed to get record
1276
1296
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···
1280
1300
recordPullSource := &tangled.RepoPull_Source{
1281
1301
Branch: pull.PullSource.Branch,
1282
1302
}
1283
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1303
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1284
1304
Collection: tangled.RepoPullNSID,
1285
1305
Repo: user.Did,
1286
1306
Rkey: pull.Rkey,
···
1313
1333
}
1314
1334
1315
1335
func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
1316
-
user := s.auth.GetUser(r)
1336
+
user := s.oauth.GetUser(r)
1317
1337
1318
1338
pull, ok := r.Context().Value("pull").(*db.Pull)
1319
1339
if !ok {
···
1342
1362
}
1343
1363
1344
1364
// extract patch by performing compare
1345
-
ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev)
1365
+
ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Core.Dev)
1346
1366
if err != nil {
1347
1367
log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
1348
1368
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
1357
1377
}
1358
1378
1359
1379
// update the hidden tracking branch to latest
1360
-
signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev)
1380
+
signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev)
1361
1381
if err != nil {
1362
1382
log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
1363
1383
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
1406
1426
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1407
1427
return
1408
1428
}
1409
-
client, _ := s.auth.AuthorizedClient(r)
1429
+
client, err := s.oauth.AuthorizedClient(r)
1430
+
if err != nil {
1431
+
log.Println("failed to get client")
1432
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1433
+
return
1434
+
}
1410
1435
1411
-
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1436
+
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1412
1437
if err != nil {
1413
1438
// failed to get record
1414
1439
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···
1420
1445
Branch: pull.PullSource.Branch,
1421
1446
Repo: &repoAt,
1422
1447
}
1423
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1448
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1424
1449
Collection: tangled.RepoPullNSID,
1425
1450
Repo: user.Did,
1426
1451
Rkey: pull.Rkey,
···
1503
1528
log.Printf("failed to get primary email: %s", err)
1504
1529
}
1505
1530
1506
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
1531
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
1507
1532
if err != nil {
1508
1533
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
1509
1534
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···
1533
1558
}
1534
1559
1535
1560
func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
1536
-
user := s.auth.GetUser(r)
1561
+
user := s.oauth.GetUser(r)
1537
1562
1538
1563
f, err := s.fullyResolvedRepo(r)
1539
1564
if err != nil {
···
1587
1612
}
1588
1613
1589
1614
func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
1590
-
user := s.auth.GetUser(r)
1615
+
user := s.oauth.GetUser(r)
1591
1616
1592
1617
f, err := s.fullyResolvedRepo(r)
1593
1618
if err != nil {
+98
-60
appview/state/repo.go
+98
-60
appview/state/repo.go
···
18
18
19
19
"tangled.sh/tangled.sh/core/api/tangled"
20
20
"tangled.sh/tangled.sh/core/appview"
21
-
"tangled.sh/tangled.sh/core/appview/auth"
22
21
"tangled.sh/tangled.sh/core/appview/db"
22
+
"tangled.sh/tangled.sh/core/appview/oauth"
23
23
"tangled.sh/tangled.sh/core/appview/pages"
24
24
"tangled.sh/tangled.sh/core/appview/pages/markup"
25
25
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
···
45
45
return
46
46
}
47
47
48
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
48
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
49
49
if err != nil {
50
50
log.Printf("failed to create unsigned client for %s", f.Knot)
51
51
s.pages.Error503(w)
···
119
119
120
120
emails := uniqueEmails(commitsTrunc)
121
121
122
-
user := s.auth.GetUser(r)
122
+
user := s.oauth.GetUser(r)
123
123
s.pages.RepoIndexPage(w, pages.RepoIndexParams{
124
124
LoggedInUser: user,
125
125
RepoInfo: f.RepoInfo(s, user),
···
150
150
151
151
ref := chi.URLParam(r, "ref")
152
152
153
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
153
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
154
154
if err != nil {
155
155
log.Println("failed to create unsigned client", err)
156
156
return
···
190
190
tagMap[hash] = append(tagMap[hash], tag.Name)
191
191
}
192
192
193
-
user := s.auth.GetUser(r)
193
+
user := s.oauth.GetUser(r)
194
194
s.pages.RepoLog(w, pages.RepoLogParams{
195
195
LoggedInUser: user,
196
196
TagMap: tagMap,
···
209
209
return
210
210
}
211
211
212
-
user := s.auth.GetUser(r)
212
+
user := s.oauth.GetUser(r)
213
213
s.pages.EditRepoDescriptionFragment(w, pages.RepoDescriptionParams{
214
214
RepoInfo: f.RepoInfo(s, user),
215
215
})
···
232
232
return
233
233
}
234
234
235
-
user := s.auth.GetUser(r)
235
+
user := s.oauth.GetUser(r)
236
236
237
237
switch r.Method {
238
238
case http.MethodGet:
···
241
241
})
242
242
return
243
243
case http.MethodPut:
244
-
user := s.auth.GetUser(r)
244
+
user := s.oauth.GetUser(r)
245
245
newDescription := r.FormValue("description")
246
-
client, _ := s.auth.AuthorizedClient(r)
246
+
client, err := s.oauth.AuthorizedClient(r)
247
+
if err != nil {
248
+
log.Println("failed to get client")
249
+
s.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
250
+
return
251
+
}
247
252
248
253
// optimistic update
249
254
err = db.UpdateDescription(s.db, string(repoAt), newDescription)
···
256
261
// this is a bit of a pain because the golang atproto impl does not allow nil SwapRecord field
257
262
//
258
263
// SwapRecord is optional and should happen automagically, but given that it does not, we have to perform two requests
259
-
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoNSID, user.Did, rkey)
264
+
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoNSID, user.Did, rkey)
260
265
if err != nil {
261
266
// failed to get record
262
267
s.pages.Notice(w, "repo-notice", "Failed to update description, no record found on PDS.")
263
268
return
264
269
}
265
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
270
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
266
271
Collection: tangled.RepoNSID,
267
272
Repo: user.Did,
268
273
Rkey: rkey,
···
303
308
}
304
309
ref := chi.URLParam(r, "ref")
305
310
protocol := "http"
306
-
if !s.config.Dev {
311
+
if !s.config.Core.Dev {
307
312
protocol = "https"
308
313
}
309
314
···
331
336
return
332
337
}
333
338
334
-
user := s.auth.GetUser(r)
339
+
user := s.oauth.GetUser(r)
335
340
s.pages.RepoCommit(w, pages.RepoCommitParams{
336
341
LoggedInUser: user,
337
342
RepoInfo: f.RepoInfo(s, user),
···
351
356
ref := chi.URLParam(r, "ref")
352
357
treePath := chi.URLParam(r, "*")
353
358
protocol := "http"
354
-
if !s.config.Dev {
359
+
if !s.config.Core.Dev {
355
360
protocol = "https"
356
361
}
357
362
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath))
···
380
385
return
381
386
}
382
387
383
-
user := s.auth.GetUser(r)
388
+
user := s.oauth.GetUser(r)
384
389
385
390
var breadcrumbs [][]string
386
391
breadcrumbs = append(breadcrumbs, []string{f.RepoName, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), ref)})
···
411
416
return
412
417
}
413
418
414
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
419
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
415
420
if err != nil {
416
421
log.Println("failed to create unsigned client", err)
417
422
return
···
451
456
}
452
457
}
453
458
454
-
user := s.auth.GetUser(r)
459
+
user := s.oauth.GetUser(r)
455
460
s.pages.RepoTags(w, pages.RepoTagsParams{
456
461
LoggedInUser: user,
457
462
RepoInfo: f.RepoInfo(s, user),
···
469
474
return
470
475
}
471
476
472
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
477
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
473
478
if err != nil {
474
479
log.Println("failed to create unsigned client", err)
475
480
return
···
511
516
return strings.Compare(a.Name, b.Name) * -1
512
517
})
513
518
514
-
user := s.auth.GetUser(r)
519
+
user := s.oauth.GetUser(r)
515
520
s.pages.RepoBranches(w, pages.RepoBranchesParams{
516
521
LoggedInUser: user,
517
522
RepoInfo: f.RepoInfo(s, user),
···
530
535
ref := chi.URLParam(r, "ref")
531
536
filePath := chi.URLParam(r, "*")
532
537
protocol := "http"
533
-
if !s.config.Dev {
538
+
if !s.config.Core.Dev {
534
539
protocol = "https"
535
540
}
536
541
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···
568
573
showRendered = r.URL.Query().Get("code") != "true"
569
574
}
570
575
571
-
user := s.auth.GetUser(r)
576
+
user := s.oauth.GetUser(r)
572
577
s.pages.RepoBlob(w, pages.RepoBlobParams{
573
578
LoggedInUser: user,
574
579
RepoInfo: f.RepoInfo(s, user),
···
591
596
filePath := chi.URLParam(r, "*")
592
597
593
598
protocol := "http"
594
-
if !s.config.Dev {
599
+
if !s.config.Core.Dev {
595
600
protocol = "https"
596
601
}
597
602
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···
652
657
return
653
658
}
654
659
655
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
660
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
656
661
if err != nil {
657
662
log.Println("failed to create client to ", f.Knot)
658
663
return
···
714
719
}
715
720
716
721
func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
717
-
user := s.auth.GetUser(r)
722
+
user := s.oauth.GetUser(r)
718
723
719
724
f, err := s.fullyResolvedRepo(r)
720
725
if err != nil {
···
723
728
}
724
729
725
730
// remove record from pds
726
-
xrpcClient, _ := s.auth.AuthorizedClient(r)
731
+
xrpcClient, err := s.oauth.AuthorizedClient(r)
732
+
if err != nil {
733
+
log.Println("failed to get authorized client", err)
734
+
return
735
+
}
727
736
repoRkey := f.RepoAt.RecordKey().String()
728
-
_, err = comatproto.RepoDeleteRecord(r.Context(), xrpcClient, &comatproto.RepoDeleteRecord_Input{
737
+
_, err = xrpcClient.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
729
738
Collection: tangled.RepoNSID,
730
739
Repo: user.Did,
731
740
Rkey: repoRkey,
···
743
752
return
744
753
}
745
754
746
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
755
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
747
756
if err != nil {
748
757
log.Println("failed to create client to ", f.Knot)
749
758
return
···
838
847
return
839
848
}
840
849
841
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
850
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
842
851
if err != nil {
843
852
log.Println("failed to create client to ", f.Knot)
844
853
return
···
868
877
switch r.Method {
869
878
case http.MethodGet:
870
879
// for now, this is just pubkeys
871
-
user := s.auth.GetUser(r)
880
+
user := s.oauth.GetUser(r)
872
881
repoCollaborators, err := f.Collaborators(r.Context(), s)
873
882
if err != nil {
874
883
log.Println("failed to get collaborators", err)
···
884
893
885
894
var branchNames []string
886
895
var defaultBranch string
887
-
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
896
+
us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
888
897
if err != nil {
889
898
log.Println("failed to create unsigned client", err)
890
899
} else {
···
1008
1017
return collaborators, nil
1009
1018
}
1010
1019
1011
-
func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo {
1020
+
func (f *FullyResolvedRepo) RepoInfo(s *State, u *oauth.User) repoinfo.RepoInfo {
1012
1021
isStarred := false
1013
1022
if u != nil {
1014
1023
isStarred = db.GetStarStatus(s.db, u.Did, syntax.ATURI(f.RepoAt))
···
1051
1060
1052
1061
knot := f.Knot
1053
1062
var disableFork bool
1054
-
us, err := NewUnsignedClient(knot, s.config.Dev)
1063
+
us, err := NewUnsignedClient(knot, s.config.Core.Dev)
1055
1064
if err != nil {
1056
1065
log.Printf("failed to create unsigned client for %s: %v", knot, err)
1057
1066
} else {
···
1105
1114
}
1106
1115
1107
1116
func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
1108
-
user := s.auth.GetUser(r)
1117
+
user := s.oauth.GetUser(r)
1109
1118
f, err := s.fullyResolvedRepo(r)
1110
1119
if err != nil {
1111
1120
log.Println("failed to get repo and knot", err)
···
1159
1168
}
1160
1169
1161
1170
func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
1162
-
user := s.auth.GetUser(r)
1171
+
user := s.oauth.GetUser(r)
1163
1172
f, err := s.fullyResolvedRepo(r)
1164
1173
if err != nil {
1165
1174
log.Println("failed to get repo and knot", err)
···
1195
1204
1196
1205
closed := tangled.RepoIssueStateClosed
1197
1206
1198
-
client, _ := s.auth.AuthorizedClient(r)
1199
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1207
+
client, err := s.oauth.AuthorizedClient(r)
1208
+
if err != nil {
1209
+
log.Println("failed to get authorized client", err)
1210
+
return
1211
+
}
1212
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1200
1213
Collection: tangled.RepoIssueStateNSID,
1201
1214
Repo: user.Did,
1202
1215
Rkey: appview.TID(),
···
1214
1227
return
1215
1228
}
1216
1229
1217
-
err := db.CloseIssue(s.db, f.RepoAt, issueIdInt)
1230
+
err = db.CloseIssue(s.db, f.RepoAt, issueIdInt)
1218
1231
if err != nil {
1219
1232
log.Println("failed to close issue", err)
1220
1233
s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
···
1231
1244
}
1232
1245
1233
1246
func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) {
1234
-
user := s.auth.GetUser(r)
1247
+
user := s.oauth.GetUser(r)
1235
1248
f, err := s.fullyResolvedRepo(r)
1236
1249
if err != nil {
1237
1250
log.Println("failed to get repo and knot", err)
···
1279
1292
}
1280
1293
1281
1294
func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
1282
-
user := s.auth.GetUser(r)
1295
+
user := s.oauth.GetUser(r)
1283
1296
f, err := s.fullyResolvedRepo(r)
1284
1297
if err != nil {
1285
1298
log.Println("failed to get repo and knot", err)
···
1330
1343
}
1331
1344
1332
1345
atUri := f.RepoAt.String()
1333
-
client, _ := s.auth.AuthorizedClient(r)
1334
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1346
+
client, err := s.oauth.AuthorizedClient(r)
1347
+
if err != nil {
1348
+
log.Println("failed to get authorized client", err)
1349
+
s.pages.Notice(w, "issue-comment", "Failed to create comment.")
1350
+
return
1351
+
}
1352
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1335
1353
Collection: tangled.RepoIssueCommentNSID,
1336
1354
Repo: user.Did,
1337
1355
Rkey: rkey,
···
1358
1376
}
1359
1377
1360
1378
func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) {
1361
-
user := s.auth.GetUser(r)
1379
+
user := s.oauth.GetUser(r)
1362
1380
f, err := s.fullyResolvedRepo(r)
1363
1381
if err != nil {
1364
1382
log.Println("failed to get repo and knot", err)
···
1417
1435
}
1418
1436
1419
1437
func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
1420
-
user := s.auth.GetUser(r)
1438
+
user := s.oauth.GetUser(r)
1421
1439
f, err := s.fullyResolvedRepo(r)
1422
1440
if err != nil {
1423
1441
log.Println("failed to get repo and knot", err)
···
1469
1487
case http.MethodPost:
1470
1488
// extract form value
1471
1489
newBody := r.FormValue("body")
1472
-
client, _ := s.auth.AuthorizedClient(r)
1490
+
client, err := s.oauth.AuthorizedClient(r)
1491
+
if err != nil {
1492
+
log.Println("failed to get authorized client", err)
1493
+
s.pages.Notice(w, "issue-comment", "Failed to create comment.")
1494
+
return
1495
+
}
1473
1496
rkey := comment.Rkey
1474
1497
1475
1498
// optimistic update
···
1484
1507
// rkey is optional, it was introduced later
1485
1508
if comment.Rkey != "" {
1486
1509
// update the record on pds
1487
-
ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, rkey)
1510
+
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoIssueCommentNSID, user.Did, rkey)
1488
1511
if err != nil {
1489
1512
// failed to get record
1490
1513
log.Println(err, rkey)
···
1499
1522
createdAt := record["createdAt"].(string)
1500
1523
commentIdInt64 := int64(commentIdInt)
1501
1524
1502
-
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1525
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1503
1526
Collection: tangled.RepoIssueCommentNSID,
1504
1527
Repo: user.Did,
1505
1528
Rkey: rkey,
···
1542
1565
}
1543
1566
1544
1567
func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
1545
-
user := s.auth.GetUser(r)
1568
+
user := s.oauth.GetUser(r)
1546
1569
f, err := s.fullyResolvedRepo(r)
1547
1570
if err != nil {
1548
1571
log.Println("failed to get repo and knot", err)
···
1599
1622
1600
1623
// delete from pds
1601
1624
if comment.Rkey != "" {
1602
-
client, _ := s.auth.AuthorizedClient(r)
1603
-
_, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
1625
+
client, err := s.oauth.AuthorizedClient(r)
1626
+
if err != nil {
1627
+
log.Println("failed to get authorized client", err)
1628
+
s.pages.Notice(w, "issue-comment", "Failed to delete comment.")
1629
+
return
1630
+
}
1631
+
_, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
1604
1632
Collection: tangled.GraphFollowNSID,
1605
1633
Repo: user.Did,
1606
1634
Rkey: comment.Rkey,
···
1647
1675
page = pagination.FirstPage()
1648
1676
}
1649
1677
1650
-
user := s.auth.GetUser(r)
1678
+
user := s.oauth.GetUser(r)
1651
1679
f, err := s.fullyResolvedRepo(r)
1652
1680
if err != nil {
1653
1681
log.Println("failed to get repo and knot", err)
···
1676
1704
}
1677
1705
1678
1706
s.pages.RepoIssues(w, pages.RepoIssuesParams{
1679
-
LoggedInUser: s.auth.GetUser(r),
1707
+
LoggedInUser: s.oauth.GetUser(r),
1680
1708
RepoInfo: f.RepoInfo(s, user),
1681
1709
Issues: issues,
1682
1710
DidHandleMap: didHandleMap,
···
1687
1715
}
1688
1716
1689
1717
func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
1690
-
user := s.auth.GetUser(r)
1718
+
user := s.oauth.GetUser(r)
1691
1719
1692
1720
f, err := s.fullyResolvedRepo(r)
1693
1721
if err != nil {
···
1735
1763
return
1736
1764
}
1737
1765
1738
-
client, _ := s.auth.AuthorizedClient(r)
1766
+
client, err := s.oauth.AuthorizedClient(r)
1767
+
if err != nil {
1768
+
log.Println("failed to get authorized client", err)
1769
+
s.pages.Notice(w, "issues", "Failed to create issue.")
1770
+
return
1771
+
}
1739
1772
atUri := f.RepoAt.String()
1740
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1773
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1741
1774
Collection: tangled.RepoIssueNSID,
1742
1775
Repo: user.Did,
1743
1776
Rkey: appview.TID(),
···
1770
1803
}
1771
1804
1772
1805
func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
1773
-
user := s.auth.GetUser(r)
1806
+
user := s.oauth.GetUser(r)
1774
1807
f, err := s.fullyResolvedRepo(r)
1775
1808
if err != nil {
1776
1809
log.Printf("failed to resolve source repo: %v", err)
···
1779
1812
1780
1813
switch r.Method {
1781
1814
case http.MethodGet:
1782
-
user := s.auth.GetUser(r)
1815
+
user := s.oauth.GetUser(r)
1783
1816
knots, err := s.enforcer.GetDomainsForUser(user.Did)
1784
1817
if err != nil {
1785
1818
s.pages.Notice(w, "repo", "Invalid user account.")
···
1829
1862
return
1830
1863
}
1831
1864
1832
-
client, err := NewSignedClient(knot, secret, s.config.Dev)
1865
+
client, err := NewSignedClient(knot, secret, s.config.Core.Dev)
1833
1866
if err != nil {
1834
1867
s.pages.Notice(w, "repo", "Failed to reach knot server.")
1835
1868
return
1836
1869
}
1837
1870
1838
1871
var uri string
1839
-
if s.config.Dev {
1872
+
if s.config.Core.Dev {
1840
1873
uri = "http"
1841
1874
} else {
1842
1875
uri = "https"
···
1883
1916
// continue
1884
1917
}
1885
1918
1886
-
xrpcClient, _ := s.auth.AuthorizedClient(r)
1919
+
xrpcClient, err := s.oauth.AuthorizedClient(r)
1920
+
if err != nil {
1921
+
log.Println("failed to get authorized client", err)
1922
+
s.pages.Notice(w, "repo", "Failed to create repository.")
1923
+
return
1924
+
}
1887
1925
1888
1926
createdAt := time.Now().Format(time.RFC3339)
1889
-
atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{
1927
+
atresp, err := xrpcClient.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1890
1928
Collection: tangled.RepoNSID,
1891
1929
Repo: user.Did,
1892
1930
Rkey: rkey,
+3
-3
appview/state/repo_util.go
+3
-3
appview/state/repo_util.go
···
12
12
"github.com/bluesky-social/indigo/atproto/syntax"
13
13
"github.com/go-chi/chi/v5"
14
14
"github.com/go-git/go-git/v5/plumbing/object"
15
-
"tangled.sh/tangled.sh/core/appview/auth"
16
15
"tangled.sh/tangled.sh/core/appview/db"
16
+
"tangled.sh/tangled.sh/core/appview/oauth"
17
17
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
18
18
)
19
19
···
45
45
ref := chi.URLParam(r, "ref")
46
46
47
47
if ref == "" {
48
-
us, err := NewUnsignedClient(knot, s.config.Dev)
48
+
us, err := NewUnsignedClient(knot, s.config.Core.Dev)
49
49
if err != nil {
50
50
return nil, err
51
51
}
···
73
73
}, nil
74
74
}
75
75
76
-
func RolesInRepo(s *State, u *auth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
76
+
func RolesInRepo(s *State, u *oauth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
77
77
if u != nil {
78
78
r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.DidSlashRepo())
79
79
return repoinfo.RolesInRepo{r}
+8
-4
appview/state/star.go
+8
-4
appview/state/star.go
···
15
15
)
16
16
17
17
func (s *State) Star(w http.ResponseWriter, r *http.Request) {
18
-
currentUser := s.auth.GetUser(r)
18
+
currentUser := s.oauth.GetUser(r)
19
19
20
20
subject := r.URL.Query().Get("subject")
21
21
if subject == "" {
···
29
29
return
30
30
}
31
31
32
-
client, _ := s.auth.AuthorizedClient(r)
32
+
client, err := s.oauth.AuthorizedClient(r)
33
+
if err != nil {
34
+
log.Println("failed to authorize client", err)
35
+
return
36
+
}
33
37
34
38
switch r.Method {
35
39
case http.MethodPost:
36
40
createdAt := time.Now().Format(time.RFC3339)
37
41
rkey := appview.TID()
38
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
42
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
39
43
Collection: tangled.FeedStarNSID,
40
44
Repo: currentUser.Did,
41
45
Rkey: rkey,
···
80
84
return
81
85
}
82
86
83
-
_, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
87
+
_, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
84
88
Collection: tangled.FeedStarNSID,
85
89
Repo: currentUser.Did,
86
90
Rkey: star.Rkey,
+109
-96
appview/state/state.go
+109
-96
appview/state/state.go
···
21
21
"tangled.sh/tangled.sh/core/appview"
22
22
"tangled.sh/tangled.sh/core/appview/auth"
23
23
"tangled.sh/tangled.sh/core/appview/db"
24
+
"tangled.sh/tangled.sh/core/appview/oauth"
24
25
"tangled.sh/tangled.sh/core/appview/pages"
25
26
"tangled.sh/tangled.sh/core/jetstream"
26
27
"tangled.sh/tangled.sh/core/rbac"
···
29
30
type State struct {
30
31
db *db.DB
31
32
auth *auth.Auth
33
+
oauth *oauth.OAuth
32
34
enforcer *rbac.Enforcer
33
-
tidClock *syntax.TIDClock
35
+
tidClock syntax.TIDClock
34
36
pages *pages.Pages
35
37
resolver *appview.Resolver
36
38
jc *jetstream.JetstreamClient
···
38
40
}
39
41
40
42
func Make(config *appview.Config) (*State, error) {
41
-
d, err := db.Make(config.DbPath)
43
+
d, err := db.Make(config.Core.DbPath)
42
44
if err != nil {
43
45
return nil, err
44
46
}
45
47
46
-
auth, err := auth.Make(config.CookieSecret)
48
+
auth, err := auth.Make(config.Core.CookieSecret)
47
49
if err != nil {
48
50
return nil, err
49
51
}
50
52
51
-
enforcer, err := rbac.NewEnforcer(config.DbPath)
53
+
enforcer, err := rbac.NewEnforcer(config.Core.DbPath)
52
54
if err != nil {
53
55
return nil, err
54
56
}
···
59
61
60
62
resolver := appview.NewResolver()
61
63
64
+
oauth := oauth.NewOAuth(d, config)
65
+
62
66
wrapper := db.DbWrapper{d}
63
67
jc, err := jetstream.NewJetstreamClient(
64
-
config.JetstreamEndpoint,
68
+
config.Jetstream.Endpoint,
65
69
"appview",
66
70
[]string{
67
71
tangled.GraphFollowNSID,
···
86
90
state := &State{
87
91
d,
88
92
auth,
93
+
oauth,
89
94
enforcer,
90
95
clock,
91
96
pgs,
···
101
106
return c.Next().String()
102
107
}
103
108
104
-
func (s *State) Login(w http.ResponseWriter, r *http.Request) {
105
-
ctx := r.Context()
106
-
107
-
switch r.Method {
108
-
case http.MethodGet:
109
-
err := s.pages.Login(w, pages.LoginParams{})
110
-
if err != nil {
111
-
log.Printf("rendering login page: %s", err)
112
-
}
113
-
114
-
return
115
-
case http.MethodPost:
116
-
handle := strings.TrimPrefix(r.FormValue("handle"), "@")
117
-
appPassword := r.FormValue("app_password")
118
-
119
-
resolved, err := s.resolver.ResolveIdent(ctx, handle)
120
-
if err != nil {
121
-
log.Println("failed to resolve handle:", err)
122
-
s.pages.Notice(w, "login-msg", fmt.Sprintf("\"%s\" is an invalid handle.", handle))
123
-
return
124
-
}
125
-
126
-
atSession, err := s.auth.CreateInitialSession(ctx, resolved, appPassword)
127
-
if err != nil {
128
-
s.pages.Notice(w, "login-msg", "Invalid handle or password.")
129
-
return
130
-
}
131
-
sessionish := auth.CreateSessionWrapper{ServerCreateSession_Output: atSession}
132
-
133
-
err = s.auth.StoreSession(r, w, &sessionish, resolved.PDSEndpoint())
134
-
if err != nil {
135
-
s.pages.Notice(w, "login-msg", "Failed to login, try again later.")
136
-
return
137
-
}
138
-
139
-
log.Printf("successfully saved session for %s (%s)", atSession.Handle, atSession.Did)
140
-
141
-
did := resolved.DID.String()
142
-
defaultKnot := "knot1.tangled.sh"
143
-
144
-
go func() {
145
-
log.Printf("adding %s to default knot", did)
146
-
err = s.enforcer.AddMember(defaultKnot, did)
147
-
if err != nil {
148
-
log.Println("failed to add user to knot1.tangled.sh: ", err)
149
-
return
150
-
}
151
-
err = s.enforcer.E.SavePolicy()
152
-
if err != nil {
153
-
log.Println("failed to add user to knot1.tangled.sh: ", err)
154
-
return
155
-
}
156
-
157
-
secret, err := db.GetRegistrationKey(s.db, defaultKnot)
158
-
if err != nil {
159
-
log.Println("failed to get registration key for knot1.tangled.sh")
160
-
return
161
-
}
162
-
signedClient, err := NewSignedClient(defaultKnot, secret, s.config.Dev)
163
-
resp, err := signedClient.AddMember(did)
164
-
if err != nil {
165
-
log.Println("failed to add user to knot1.tangled.sh: ", err)
166
-
return
167
-
}
168
-
169
-
if resp.StatusCode != http.StatusNoContent {
170
-
log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode)
171
-
return
172
-
}
173
-
}()
174
-
175
-
s.pages.HxRedirect(w, "/")
176
-
return
177
-
}
178
-
}
109
+
// func (s *State) Login(w http.ResponseWriter, r *http.Request) {
110
+
// ctx := r.Context()
111
+
112
+
// switch r.Method {
113
+
// case http.MethodGet:
114
+
// err := s.pages.Login(w, pages.LoginParams{})
115
+
// if err != nil {
116
+
// log.Printf("rendering login page: %s", err)
117
+
// }
118
+
119
+
// return
120
+
// case http.MethodPost:
121
+
// handle := strings.TrimPrefix(r.FormValue("handle"), "@")
122
+
// appPassword := r.FormValue("app_password")
123
+
124
+
// resolved, err := s.resolver.ResolveIdent(ctx, handle)
125
+
// if err != nil {
126
+
// log.Println("failed to resolve handle:", err)
127
+
// s.pages.Notice(w, "login-msg", fmt.Sprintf("\"%s\" is an invalid handle.", handle))
128
+
// return
129
+
// }
130
+
131
+
// atSession, err := s.oauth.CreateInitialSession(ctx, resolved, appPassword)
132
+
// if err != nil {
133
+
// s.pages.Notice(w, "login-msg", "Invalid handle or password.")
134
+
// return
135
+
// }
136
+
// sessionish := auth.CreateSessionWrapper{ServerCreateSession_Output: atSession}
137
+
138
+
// err = s.oauth.StoreSession(r, w, &sessionish, resolved.PDSEndpoint())
139
+
// if err != nil {
140
+
// s.pages.Notice(w, "login-msg", "Failed to login, try again later.")
141
+
// return
142
+
// }
143
+
144
+
// log.Printf("successfully saved session for %s (%s)", atSession.Handle, atSession.Did)
145
+
146
+
// did := resolved.DID.String()
147
+
// defaultKnot := "knot1.tangled.sh"
148
+
149
+
// go func() {
150
+
// log.Printf("adding %s to default knot", did)
151
+
// err = s.enforcer.AddMember(defaultKnot, did)
152
+
// if err != nil {
153
+
// log.Println("failed to add user to knot1.tangled.sh: ", err)
154
+
// return
155
+
// }
156
+
// err = s.enforcer.E.SavePolicy()
157
+
// if err != nil {
158
+
// log.Println("failed to add user to knot1.tangled.sh: ", err)
159
+
// return
160
+
// }
161
+
162
+
// secret, err := db.GetRegistrationKey(s.db, defaultKnot)
163
+
// if err != nil {
164
+
// log.Println("failed to get registration key for knot1.tangled.sh")
165
+
// return
166
+
// }
167
+
// signedClient, err := NewSignedClient(defaultKnot, secret, s.config.Core.Dev)
168
+
// resp, err := signedClient.AddMember(did)
169
+
// if err != nil {
170
+
// log.Println("failed to add user to knot1.tangled.sh: ", err)
171
+
// return
172
+
// }
173
+
174
+
// if resp.StatusCode != http.StatusNoContent {
175
+
// log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode)
176
+
// return
177
+
// }
178
+
// }()
179
+
180
+
// s.pages.HxRedirect(w, "/")
181
+
// return
182
+
// }
183
+
// }
179
184
180
185
func (s *State) Logout(w http.ResponseWriter, r *http.Request) {
181
-
s.auth.ClearSession(r, w)
186
+
s.oauth.ClearSession(r, w)
182
187
w.Header().Set("HX-Redirect", "/login")
183
188
w.WriteHeader(http.StatusSeeOther)
184
189
}
185
190
186
191
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
187
-
user := s.auth.GetUser(r)
192
+
user := s.oauth.GetUser(r)
188
193
189
194
timeline, err := db.MakeTimeline(s.db)
190
195
if err != nil {
···
235
240
236
241
return
237
242
case http.MethodPost:
238
-
session, err := s.auth.Store.Get(r, appview.SessionName)
243
+
session, err := s.oauth.Store.Get(r, appview.SessionName)
239
244
if err != nil || session.IsNew {
240
245
log.Println("unauthorized attempt to generate registration key")
241
246
http.Error(w, "Forbidden", http.StatusUnauthorized)
···
297
302
298
303
// create a signed request and check if a node responds to that
299
304
func (s *State) InitKnotServer(w http.ResponseWriter, r *http.Request) {
300
-
user := s.auth.GetUser(r)
305
+
user := s.oauth.GetUser(r)
301
306
302
307
domain := chi.URLParam(r, "domain")
303
308
if domain == "" {
···
312
317
return
313
318
}
314
319
315
-
client, err := NewSignedClient(domain, secret, s.config.Dev)
320
+
client, err := NewSignedClient(domain, secret, s.config.Core.Dev)
316
321
if err != nil {
317
322
log.Println("failed to create client to ", domain)
318
323
}
···
421
426
return
422
427
}
423
428
424
-
user := s.auth.GetUser(r)
429
+
user := s.oauth.GetUser(r)
425
430
reg, err := db.RegistrationByDomain(s.db, domain)
426
431
if err != nil {
427
432
w.Write([]byte("failed to pull up registration info"))
···
469
474
// get knots registered by this user
470
475
func (s *State) Knots(w http.ResponseWriter, r *http.Request) {
471
476
// for now, this is just pubkeys
472
-
user := s.auth.GetUser(r)
477
+
user := s.oauth.GetUser(r)
473
478
registrations, err := db.RegistrationsByDid(s.db, user.Did)
474
479
if err != nil {
475
480
log.Println(err)
···
522
527
log.Printf("adding %s to %s\n", subjectIdentity.Handle.String(), domain)
523
528
524
529
// announce this relation into the firehose, store into owners' pds
525
-
client, _ := s.auth.AuthorizedClient(r)
526
-
currentUser := s.auth.GetUser(r)
530
+
client, err := s.oauth.AuthorizedClient(r)
531
+
if err != nil {
532
+
http.Error(w, "failed to authorize client", http.StatusInternalServerError)
533
+
return
534
+
}
535
+
currentUser := s.oauth.GetUser(r)
527
536
createdAt := time.Now().Format(time.RFC3339)
528
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
537
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
529
538
Collection: tangled.KnotMemberNSID,
530
539
Repo: currentUser.Did,
531
540
Rkey: appview.TID(),
···
550
559
return
551
560
}
552
561
553
-
ksClient, err := NewSignedClient(domain, secret, s.config.Dev)
562
+
ksClient, err := NewSignedClient(domain, secret, s.config.Core.Dev)
554
563
if err != nil {
555
564
log.Println("failed to create client to ", domain)
556
565
return
···
614
623
func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) {
615
624
switch r.Method {
616
625
case http.MethodGet:
617
-
user := s.auth.GetUser(r)
626
+
user := s.oauth.GetUser(r)
618
627
knots, err := s.enforcer.GetDomainsForUser(user.Did)
619
628
if err != nil {
620
629
s.pages.Notice(w, "repo", "Invalid user account.")
···
627
636
})
628
637
629
638
case http.MethodPost:
630
-
user := s.auth.GetUser(r)
639
+
user := s.oauth.GetUser(r)
631
640
632
641
domain := r.FormValue("domain")
633
642
if domain == "" {
···
671
680
return
672
681
}
673
682
674
-
client, err := NewSignedClient(domain, secret, s.config.Dev)
683
+
client, err := NewSignedClient(domain, secret, s.config.Core.Dev)
675
684
if err != nil {
676
685
s.pages.Notice(w, "repo", "Failed to connect to knot server.")
677
686
return
···
686
695
Description: description,
687
696
}
688
697
689
-
xrpcClient, _ := s.auth.AuthorizedClient(r)
698
+
xrpcClient, err := s.oauth.AuthorizedClient(r)
699
+
if err != nil {
700
+
s.pages.Notice(w, "repo", "Failed to write record to PDS.")
701
+
return
702
+
}
690
703
691
704
createdAt := time.Now().Format(time.RFC3339)
692
-
atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{
705
+
atresp, err := xrpcClient.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
693
706
Collection: tangled.RepoNSID,
694
707
Repo: user.Did,
695
708
Rkey: rkey,
+1
-1
appview/tid.go
+1
-1
appview/tid.go
+2
-2
cmd/appview/main.go
+2
-2
cmd/appview/main.go
+12
-2
appview/oauth/handler/handler.go
+12
-2
appview/oauth/handler/handler.go
···
61
61
"token_endpoint_auth_signing_alg": "ES256",
62
62
}
63
63
64
-
fmt.Println("clientMetadata", metadata)
65
-
66
64
w.Header().Set("Content-Type", "application/json")
67
65
w.WriteHeader(http.StatusOK)
68
66
json.NewEncoder(w).Encode(metadata)
···
246
244
http.Redirect(w, r, "/", http.StatusFound)
247
245
}
248
246
247
+
func (o *OAuthHandler) logout(w http.ResponseWriter, r *http.Request) {
248
+
err := o.OAuth.ClearSession(r, w)
249
+
if err != nil {
250
+
log.Println("failed to clear session:", err)
251
+
http.Redirect(w, r, "/", http.StatusFound)
252
+
return
253
+
}
254
+
255
+
log.Println("session cleared successfully")
256
+
http.Redirect(w, r, "/", http.StatusFound)
257
+
}
258
+
249
259
func pubKeyFromJwk(jwks string) (jwk.Key, error) {
250
260
k, err := helpers.ParseJWKFromBytes([]byte(jwks))
251
261
if err != nil {