Signed-off-by: brookjeynes me@brookjeynes.dev
assets/yoten_logo.png
assets/yoten_logo.png
This is a binary file and will not be displayed.
+10
assets/yoten_logo_transparent.svg
+10
assets/yoten_logo_transparent.svg
···
1
+
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+
<path d="M160 107.39C160 141.824 145.837 161.277 122.403 161.277C98.9686 161.277 71.9149 140.006 71.9149 105.573C71.9149 71.1399 77.4844 46.3196 100.919 46.3196C124.214 38.116 160 72.9573 160 107.39Z" fill="#F9FBF9"/>
3
+
<circle cx="98.3957" cy="110.264" r="49.3079" fill="#A8DE9C"/>
4
+
<rect x="81.3088" y="58.0269" width="17.5751" height="104.474" fill="#F9FBF9"/>
5
+
<path d="M96.3814 99.0276L147.255 149.39L110.606 172.558L90.3659 167.161L60.7262 135.045L96.3814 99.0276Z" fill="#F9FBF9"/>
6
+
<path d="M97.4468 113.215C97.4468 149.759 100.729 172.128 85.3191 172.128C69.9089 172.128 40 149.759 40 113.215C40 76.6708 54.6809 56.3327 70.0912 56.3327C90.8815 41.2416 97.4468 76.6708 97.4468 113.215Z" fill="#F9FBF9"/>
7
+
<circle cx="98.8839" cy="109.776" r="62.6073" stroke="black" stroke-width="10"/>
8
+
<rect x="73.1915" y="13.1915" width="51.0638" height="12.766" rx="2" fill="black"/>
9
+
<rect x="98.6467" y="104.894" width="32.4789" height="6.60207" rx="3.30104" transform="rotate(44.7106 98.6467 104.894)" fill="black"/>
10
+
</svg>
+54
cmd/cborgen.go
+54
cmd/cborgen.go
···
1
+
package main
2
+
3
+
import (
4
+
"maps"
5
+
"reflect"
6
+
"strings"
7
+
8
+
"github.com/bluesky-social/indigo/mst"
9
+
cbg "github.com/whyrusleeping/cbor-gen"
10
+
11
+
"yoten.app/api/yoten"
12
+
)
13
+
14
+
func main() {
15
+
var typVals []any
16
+
for _, typ := range mst.CBORTypes() {
17
+
typVals = append(typVals, reflect.New(typ).Elem().Interface())
18
+
}
19
+
20
+
genCfg := cbg.Gen{
21
+
MaxStringLength: 1_000_000,
22
+
}
23
+
24
+
yotenTypes := []any{
25
+
yoten.ActorProfile{},
26
+
yoten.FeedSession{},
27
+
yoten.FeedResource{},
28
+
yoten.ActivityDef{},
29
+
yoten.GraphFollow{},
30
+
yoten.FeedReaction{},
31
+
yoten.FeedComment{},
32
+
yoten.FeedComment_Reply{},
33
+
}
34
+
35
+
for name, rt := range AllLexTypes() {
36
+
if strings.HasPrefix(name, "app.yoten.") {
37
+
yotenTypes = append(yotenTypes, reflect.New(rt).Interface())
38
+
}
39
+
}
40
+
yotenGenCfg := genCfg
41
+
yotenGenCfg.SortTypeNames = true
42
+
43
+
if err := yotenGenCfg.WriteMapEncodersToFile("api/yoten/cbor_gen.go", "yoten", yotenTypes...); err != nil {
44
+
panic(err)
45
+
}
46
+
}
47
+
48
+
var lexTypesMap map[string]reflect.Type
49
+
50
+
func AllLexTypes() map[string]reflect.Type {
51
+
out := make(map[string]reflect.Type, len(lexTypesMap))
52
+
maps.Copy(out, lexTypesMap)
53
+
return out
54
+
}
-54
cmd/gen.go
-54
cmd/gen.go
···
1
-
package main
2
-
3
-
import (
4
-
"maps"
5
-
"reflect"
6
-
"strings"
7
-
8
-
"github.com/bluesky-social/indigo/mst"
9
-
cbg "github.com/whyrusleeping/cbor-gen"
10
-
11
-
"yoten.app/api/yoten"
12
-
)
13
-
14
-
func main() {
15
-
var typVals []any
16
-
for _, typ := range mst.CBORTypes() {
17
-
typVals = append(typVals, reflect.New(typ).Elem().Interface())
18
-
}
19
-
20
-
genCfg := cbg.Gen{
21
-
MaxStringLength: 1_000_000,
22
-
}
23
-
24
-
yotenTypes := []any{
25
-
yoten.ActorProfile{},
26
-
yoten.FeedSession{},
27
-
yoten.FeedResource{},
28
-
yoten.ActivityDef{},
29
-
yoten.GraphFollow{},
30
-
yoten.FeedReaction{},
31
-
yoten.FeedComment{},
32
-
yoten.FeedComment_Reply{},
33
-
}
34
-
35
-
for name, rt := range AllLexTypes() {
36
-
if strings.HasPrefix(name, "app.yoten.") {
37
-
yotenTypes = append(yotenTypes, reflect.New(rt).Interface())
38
-
}
39
-
}
40
-
yotenGenCfg := genCfg
41
-
yotenGenCfg.SortTypeNames = true
42
-
43
-
if err := yotenGenCfg.WriteMapEncodersToFile("api/yoten/cbor_gen.go", "yoten", yotenTypes...); err != nil {
44
-
panic(err)
45
-
}
46
-
}
47
-
48
-
var lexTypesMap map[string]reflect.Type
49
-
50
-
func AllLexTypes() map[string]reflect.Type {
51
-
out := make(map[string]reflect.Type, len(lexTypesMap))
52
-
maps.Copy(out, lexTypesMap)
53
-
return out
54
-
}
-64
cmd/genjwks/main.go
-64
cmd/genjwks/main.go
···
1
-
// MIT License
2
-
//
3
-
// Copyright (c) 2025 Anirudh Oppiliappan, Akshay Oppiliappan and
4
-
// contributors.
5
-
//
6
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
7
-
// of this software and associated documentation files (the "Software"), to deal
8
-
// in the Software without restriction, including without limitation the rights
9
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
-
// copies of the Software, and to permit persons to whom the Software is
11
-
// furnished to do so, subject to the following conditions:
12
-
//
13
-
// The above copyright notice and this permission notice shall be included in all
14
-
// copies or substantial portions of the Software.
15
-
//
16
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
-
// SOFTWARE.
23
-
24
-
package main
25
-
26
-
import (
27
-
"crypto/ecdsa"
28
-
"crypto/elliptic"
29
-
"crypto/rand"
30
-
"encoding/json"
31
-
"fmt"
32
-
"time"
33
-
34
-
"github.com/lestrrat-go/jwx/v2/jwk"
35
-
)
36
-
37
-
func main() {
38
-
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
39
-
if err != nil {
40
-
panic(err)
41
-
}
42
-
43
-
key, err := jwk.FromRaw(privKey)
44
-
if err != nil {
45
-
panic(err)
46
-
}
47
-
48
-
kid := fmt.Sprintf("%d", time.Now().Unix())
49
-
50
-
if err := key.Set(jwk.KeyIDKey, kid); err != nil {
51
-
panic(err)
52
-
}
53
-
54
-
if err := key.Set("use", "sig"); err != nil {
55
-
panic(err)
56
-
}
57
-
58
-
b, err := json.Marshal(key)
59
-
if err != nil {
60
-
panic(err)
61
-
}
62
-
63
-
fmt.Println(string(b))
64
-
}
+15
-16
cmd/server/main.go
+15
-16
cmd/server/main.go
···
3
3
import (
4
4
"context"
5
5
"encoding/gob"
6
-
"errors"
7
6
"fmt"
8
7
"log"
9
8
"net/http"
9
+
"os"
10
10
11
11
"yoten.app/internal/server"
12
12
"yoten.app/internal/server/config"
···
16
16
func main() {
17
17
ctx := context.Background()
18
18
19
-
c, err := config.LoadConfig(ctx)
19
+
config, err := config.LoadConfig(ctx)
20
20
if err != nil {
21
21
log.Fatalf("failed to load config: %v", err)
22
+
os.Exit(-1)
22
23
}
23
24
24
-
serverState, err := server.Make(ctx, c)
25
+
state, err := server.Make(ctx, config)
26
+
defer func() {
27
+
if err := state.Close(); err != nil {
28
+
log.Fatalf("failed to create state: %v", err)
29
+
}
30
+
}()
25
31
if err != nil {
26
-
log.Fatalf("failed to create state: %v", err)
32
+
log.Fatalf("failed to start server: %v", err)
33
+
os.Exit(-1)
27
34
}
28
35
29
-
handler := handlers.NewHandler(serverState)
36
+
handler := handlers.NewHandler(state)
30
37
31
38
gob.Register(map[string][]uint8{})
32
39
33
-
server := &http.Server{
34
-
Addr: fmt.Sprintf(":%s", c.Core.Port),
35
-
Handler: handler.Router(),
36
-
}
37
-
38
-
log.Printf("Starting server on :%s\n", c.Core.Port)
39
-
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
40
+
log.Printf("Starting server on :%s\n", config.Core.Port)
41
+
err = http.ListenAndServe(fmt.Sprintf(":%s", config.Core.Port), handler.Router())
42
+
if err != nil {
40
43
log.Fatalf("failed to start server: %v", err)
41
-
}
42
-
43
-
if err := serverState.Close(); err != nil {
44
-
log.Printf("Application state cleanup error: %v", err)
45
44
}
46
45
47
46
log.Println("Shutdown complete.")
+2
-2
docs/hacking.md
+2
-2
docs/hacking.md
···
10
10
11
11
To authenticate, you will need OAUTH JWKs to be setup:
12
12
```bash
13
-
go build -o genjwks.out ./cmd/genjwks
14
-
export YOTEN_OAUTH_JWKS="$(./genjwks.out)"
13
+
export SHELF_OAUTH_CLIENT_KID="$(date +%s)"
14
+
export SHELF_OAUTH_CLIENT_SECRET="$(goat key generate -t P-256 | grep -A1 "Secret Key" | tail -n1 | awk '{print $1}')"
15
15
```
16
16
17
17
You will need to fetch a series of static assets yΕten depends on:
+3
-3
generate-lexicons.sh
+3
-3
generate-lexicons.sh
···
6
6
--build-file lexicon-build-config.json \
7
7
lexicons/
8
8
9
-
find ./api/yoten -type f -exec sed -i.bak 's/\tutil/\/\/\tutil/' {} +
10
-
find ./api/yoten -type f -exec sed -i.bak -E 's/^(.+)github(.+)//' {} +
11
-
go run ./cmd/gen.go
9
+
find ./api/shelf -type f -exec sed -i.bak 's/\lexutil/\/\/\lexutil/' {} +
10
+
find ./api/shelf -type f -exec sed -i.bak -E 's/^(.+)github(.+)//' {} +
11
+
go run ./cmd/cborgen.go
12
12
13
13
go run github.com/bluesky-social/indigo/cmd/lexgen \
14
14
--package yoten \
+2
-5
go.mod
+2
-5
go.mod
···
1
1
module yoten.app
2
2
3
-
go 1.24.0
4
-
5
-
toolchain go1.24.4
3
+
go 1.25
6
4
7
5
require (
8
6
github.com/a-h/templ v0.3.898
9
7
github.com/bluesky-social/indigo v0.0.0-20251003000214-3259b215110e
10
-
github.com/bluesky-social/jetstream v0.0.0-20250414024304-d17bd81a945e
8
+
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1
11
9
github.com/carlmjohnson/versioninfo v0.22.5
12
10
github.com/charmbracelet/log v0.4.2
13
11
github.com/go-chi/chi/v5 v5.2.1
···
23
21
golang.org/x/sync v0.16.0
24
22
golang.org/x/text v0.28.0
25
23
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
26
-
tangled.sh/icyphox.sh/atproto-oauth v0.0.0-20250724194903-28e660378cb1
27
24
)
28
25
29
26
require (
+6
-12
go.sum
+6
-12
go.sum
···
12
12
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
13
13
github.com/bluesky-social/indigo v0.0.0-20251003000214-3259b215110e h1:IutKPwmbU0LrYqw03EuwJtMdAe67rDTrL1U8S8dicRU=
14
14
github.com/bluesky-social/indigo v0.0.0-20251003000214-3259b215110e/go.mod h1:n6QE1NDPFoi7PRbMUZmc2y7FibCqiVU4ePpsvhHUBR8=
15
-
github.com/bluesky-social/jetstream v0.0.0-20250414024304-d17bd81a945e h1:P/O6TDHs53gwgV845uDHI+Nri889ixksRrh4bCkCdxo=
16
-
github.com/bluesky-social/jetstream v0.0.0-20250414024304-d17bd81a945e/go.mod h1:WiYEeyJSdUwqoaZ71KJSpTblemUCpwJfh5oVXplK6T4=
15
+
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1 h1:CFvRtYNSnWRAi/98M3O466t9dYuwtesNbu6FVPymRrA=
16
+
github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1/go.mod h1:WiYEeyJSdUwqoaZ71KJSpTblemUCpwJfh5oVXplK6T4=
17
17
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
18
18
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
19
19
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
···
40
40
github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=
41
41
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
42
42
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
43
+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
43
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
44
-
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
45
-
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
46
45
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
47
46
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
48
47
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
···
133
132
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
134
133
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
135
134
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
136
-
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
137
-
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
138
135
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
139
136
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
140
137
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
···
201
198
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk=
202
199
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw=
203
200
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
201
+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
204
202
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
205
-
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
206
-
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
207
203
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
208
204
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
209
205
github.com/posthog/posthog-go v1.5.12 h1:nxK/z5QLCFxwzxV8GNvVd4Y1wJ++zJSWMGEtzU+/HLM=
···
222
218
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
223
219
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
224
220
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
225
-
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
226
-
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
221
+
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
222
+
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
227
223
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
228
224
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
229
225
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
···
398
394
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
399
395
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
400
396
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
401
-
tangled.sh/icyphox.sh/atproto-oauth v0.0.0-20250724194903-28e660378cb1 h1:z1os1aRIqeo5e8d0Tx7hk+LH8OdZZeIOY0zw9VB/ZoU=
402
-
tangled.sh/icyphox.sh/atproto-oauth v0.0.0-20250724194903-28e660378cb1/go.mod h1:+oQi9S6IIDll0nxLZVhuzOPX8WKLCYEnE6M5kUKupDg=
+2
-1
input.css
+2
-1
input.css
···
172
172
@utility btn-muted {
173
173
border-radius: theme(borderRadius.md);
174
174
border-color: theme(--color-bg-dark);
175
-
background-color: theme(colors.white);
175
+
background-color: theme(--color-bg);
176
176
border-width: 1px;
177
+
color: theme(--color-text-muted);
177
178
178
179
@variant hover {
179
180
opacity: 75%;
+3
-2
internal/server/config/config.go
+3
-2
internal/server/config/config.go
···
17
17
}
18
18
19
19
type OAuthConfig struct {
20
-
Jwks string `env:"JWKS"`
20
+
ClientSecret string `env:"CLIENT_SECRET"`
21
+
ClientKid string `env:"CLIENT_KID"`
21
22
}
22
23
23
24
type JetstreamConfig struct {
···
55
56
56
57
type Config struct {
57
58
Core CoreConfig `env:",prefix=YOTEN_"`
58
-
Jetstream JetstreamConfig `env:",prefix=TANGLED_JETSTREAM_"`
59
+
Jetstream JetstreamConfig `env:",prefix=YOTEN_JETSTREAM_"`
59
60
OAuth OAuthConfig `env:",prefix=YOTEN_OAUTH_"`
60
61
Posthog PosthogConfig `env:",prefix=YOTEN_POSTHOG_"`
61
62
Google GoogleConfig `env:",prefix=YOTEN_GOOGLE_"`
-24
internal/server/oauth/client/client.go
-24
internal/server/oauth/client/client.go
···
1
-
package client
2
-
3
-
import (
4
-
oauth "tangled.sh/icyphox.sh/atproto-oauth"
5
-
"tangled.sh/icyphox.sh/atproto-oauth/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
-
}
+3
-25
internal/server/oauth/handler.go
+3
-25
internal/server/oauth/handler.go
···
12
12
"github.com/bluesky-social/indigo/atproto/auth/oauth"
13
13
lexutil "github.com/bluesky-social/indigo/lex/util"
14
14
"github.com/go-chi/chi/v5"
15
-
"github.com/lestrrat-go/jwx/v2/jwk"
16
15
"github.com/posthog/posthog-go"
17
16
18
17
"yoten.app/api/yoten"
···
46
45
}
47
46
}
48
47
49
-
func pubKeyFromJwk(jwks string) (jwk.Key, error) {
50
-
k, err := jwk.ParseKey([]byte(jwks))
51
-
if err != nil {
52
-
return nil, err
53
-
}
54
-
pubKey, err := k.PublicKey()
55
-
if err != nil {
56
-
return nil, err
57
-
}
58
-
return pubKey, nil
59
-
}
60
-
61
48
func (o *OAuth) jwks(w http.ResponseWriter, r *http.Request) {
62
-
jwks := o.Config.OAuth.Jwks
63
-
pubKey, err := pubKeyFromJwk(jwks)
64
-
if err != nil {
65
-
o.Logger.Error("failed to parse public key", "err", err)
49
+
w.Header().Set("Content-Type", "application/json")
50
+
body := o.ClientApp.Config.PublicJWKS()
51
+
if err := json.NewEncoder(w).Encode(body); err != nil {
66
52
http.Error(w, err.Error(), http.StatusInternalServerError)
67
53
return
68
54
}
69
-
70
-
response := map[string]any{
71
-
"keys": []jwk.Key{pubKey},
72
-
}
73
-
74
-
w.Header().Set("Content-Type", "application/json")
75
-
w.WriteHeader(http.StatusOK)
76
-
json.NewEncoder(w).Encode(response)
77
55
}
78
56
79
57
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
+9
internal/server/oauth/oauth.go
+9
internal/server/oauth/oauth.go
···
10
10
comatproto "github.com/bluesky-social/indigo/api/atproto"
11
11
"github.com/bluesky-social/indigo/atproto/auth/oauth"
12
12
atpclient "github.com/bluesky-social/indigo/atproto/client"
13
+
atcrypto "github.com/bluesky-social/indigo/atproto/crypto"
13
14
"github.com/bluesky-social/indigo/atproto/syntax"
14
15
xrpc "github.com/bluesky-social/indigo/xrpc"
15
16
"github.com/gorilla/sessions"
···
43
44
clientId := fmt.Sprintf("%s/oauth/client-metadata.json", clientUri)
44
45
callbackUri := clientUri + "/oauth/callback"
45
46
oauthConfig = oauth.NewPublicConfig(clientId, callbackUri, []string{"atproto", "transition:generic"})
47
+
}
48
+
49
+
priv, err := atcrypto.ParsePrivateMultibase(config.OAuth.ClientSecret)
50
+
if err != nil {
51
+
return nil, err
52
+
}
53
+
if err := oauthConfig.SetClientSecret(priv, config.OAuth.ClientKid); err != nil {
54
+
return nil, err
46
55
}
47
56
48
57
jwksUri := clientUri + "/oauth/jwks.json"
History
1 round
0 comments
brookjeynes.dev
submitted
#0
expand 0 comments
pull request successfully merged