this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add tests for handleComAtprotoAccountCreate and handleComAtprotoSessionCreate

authored by

Roman Dmytrenko and committed by
bnewbold
51e25d6d e2885199

+259 -201
+1 -40
cmd/gosky/main.go
··· 4 4 "bufio" 5 5 "bytes" 6 6 "context" 7 - "crypto/ecdsa" 8 7 "encoding/json" 9 8 "fmt" 10 9 "net/http" ··· 29 28 _ "github.com/joho/godotenv/autoload" 30 29 31 30 logging "github.com/ipfs/go-log" 32 - "github.com/lestrrat-go/jwx/v2/jwa" 33 - "github.com/lestrrat-go/jwx/v2/jwk" 34 31 "github.com/polydawn/refmt/cbor" 35 32 rejson "github.com/polydawn/refmt/json" 36 33 "github.com/polydawn/refmt/shared" 37 34 cli "github.com/urfave/cli/v2" 38 - "github.com/whyrusleeping/go-did" 39 35 ) 40 36 41 37 var log = logging.Logger("gosky") ··· 238 234 239 235 recoverydid := cctx.String("recoverydid") 240 236 241 - sigkey, err := loadKey(cctx.String("signingkey")) 237 + sigkey, err := cliutil.LoadKeyFromFile(cctx.String("signingkey")) 242 238 if err != nil { 243 239 return err 244 240 } ··· 253 249 fmt.Println(ndid) 254 250 return nil 255 251 }, 256 - } 257 - 258 - func loadKey(kfile string) (*did.PrivKey, error) { 259 - kb, err := os.ReadFile(kfile) 260 - if err != nil { 261 - return nil, err 262 - } 263 - 264 - sk, err := jwk.ParseKey(kb) 265 - if err != nil { 266 - return nil, err 267 - } 268 - 269 - var spk ecdsa.PrivateKey 270 - if err := sk.Raw(&spk); err != nil { 271 - return nil, err 272 - } 273 - curve, ok := sk.Get("crv") 274 - if !ok { 275 - return nil, fmt.Errorf("need a curve set") 276 - } 277 - 278 - var out string 279 - kts := string(curve.(jwa.EllipticCurveAlgorithm)) 280 - switch kts { 281 - case "P-256": 282 - out = did.KeyTypeP256 283 - default: 284 - return nil, fmt.Errorf("unrecognized key type: %s", kts) 285 - } 286 - 287 - return &did.PrivKey{ 288 - Raw: &spk, 289 - Type: out, 290 - }, nil 291 252 } 292 253 293 254 var syncCmd = &cli.Command{
+80
cmd/gosky/util/key.go
··· 1 + package cliutil 2 + 3 + import ( 4 + "crypto/ecdsa" 5 + "crypto/elliptic" 6 + "crypto/rand" 7 + "encoding/json" 8 + "fmt" 9 + "os" 10 + "path/filepath" 11 + 12 + "github.com/lestrrat-go/jwx/v2/jwa" 13 + "github.com/lestrrat-go/jwx/v2/jwk" 14 + "github.com/whyrusleeping/go-did" 15 + ) 16 + 17 + // LoadKeyFromFile reads the private key from file 18 + func LoadKeyFromFile(kfile string) (*did.PrivKey, error) { 19 + kb, err := os.ReadFile(kfile) 20 + if err != nil { 21 + return nil, err 22 + } 23 + 24 + sk, err := jwk.ParseKey(kb) 25 + if err != nil { 26 + return nil, err 27 + } 28 + 29 + var spk ecdsa.PrivateKey 30 + if err := sk.Raw(&spk); err != nil { 31 + return nil, err 32 + } 33 + curve, ok := sk.Get("crv") 34 + if !ok { 35 + return nil, fmt.Errorf("need a curve set") 36 + } 37 + 38 + var out string 39 + kts := string(curve.(jwa.EllipticCurveAlgorithm)) 40 + switch kts { 41 + case "P-256": 42 + out = did.KeyTypeP256 43 + default: 44 + return nil, fmt.Errorf("unrecognized key type: %s", kts) 45 + } 46 + 47 + return &did.PrivKey{ 48 + Raw: &spk, 49 + Type: out, 50 + }, nil 51 + } 52 + 53 + // GenerateKeyToFile makes the private key and store it into the file 54 + func GenerateKeyToFile(fname string) error { 55 + raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 56 + if err != nil { 57 + return fmt.Errorf("failed to generate new ECDSA private key: %s", err) 58 + } 59 + 60 + key, err := jwk.FromRaw(raw) 61 + if err != nil { 62 + return fmt.Errorf("failed to create ECDSA key: %s", err) 63 + } 64 + 65 + if _, ok := key.(jwk.ECDSAPrivateKey); !ok { 66 + return fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key) 67 + } 68 + 69 + key.Set(jwk.KeyIDKey, "mykey") 70 + 71 + buf, err := json.MarshalIndent(key, "", " ") 72 + if err != nil { 73 + return fmt.Errorf("failed to marshal key into JSON: %w", err) 74 + } 75 + 76 + // ensure data directory exists; won't error if it does 77 + os.MkdirAll(filepath.Dir(fname), os.ModePerm) 78 + 79 + return os.WriteFile(fname, buf, 0664) 80 + }
+30
cmd/gosky/util/key_test.go
··· 1 + package cliutil 2 + 3 + import ( 4 + "os" 5 + "path/filepath" 6 + "testing" 7 + 8 + "github.com/whyrusleeping/go-did" 9 + ) 10 + 11 + func TestKeyGenerationAndLoading(t *testing.T) { 12 + tempdir, err := os.MkdirTemp("", "msttest-") 13 + if err != nil { 14 + t.Fatal(err) 15 + } 16 + defer os.RemoveAll(tempdir) 17 + fkey := filepath.Join(tempdir, "test.key") 18 + err = GenerateKeyToFile(fkey) 19 + if err != nil { 20 + t.Fatal(err) 21 + } 22 + key, err := LoadKeyFromFile(fkey) 23 + if err != nil { 24 + t.Fatal(err) 25 + } 26 + 27 + if key.Type != did.KeyTypeP256 { 28 + t.Fatalf("unexpected type of the key %s", key.KeyType()) 29 + } 30 + }
+1 -1
cmd/labelmaker/main.go
··· 176 176 hiveAIToken := cctx.String("hiveai-api-token") 177 177 sqrlURL := cctx.String("sqrl-url") 178 178 179 - serkey, err := labeling.LoadKeyFromFile(repoKeyPath) 179 + serkey, err := cliutil.LoadKeyFromFile(repoKeyPath) 180 180 if err != nil { 181 181 return err 182 182 }
+8 -32
cmd/laputa/main.go
··· 1 1 package main 2 2 3 3 import ( 4 - "crypto/ecdsa" 5 - "crypto/elliptic" 6 - "crypto/rand" 7 - "encoding/json" 8 - "fmt" 9 4 "os" 10 5 "path/filepath" 11 6 ··· 19 14 _ "github.com/joho/godotenv/autoload" 20 15 21 16 logging "github.com/ipfs/go-log" 22 - "github.com/lestrrat-go/jwx/v2/jwk" 23 17 "github.com/urfave/cli/v2" 24 18 "go.opentelemetry.io/otel" 25 19 "go.opentelemetry.io/otel/attribute" ··· 166 160 } 167 161 168 162 pdshost := cctx.String("name") 169 - srv, err := pds.NewServer(db, cstore, keypath, pdsdomain, pdshost, didr, jwtsecret) 163 + 164 + key, err := cliutil.LoadKeyFromFile(keypath) 165 + if err != nil { 166 + return err 167 + } 168 + 169 + srv, err := pds.NewServer(db, cstore, key, pdsdomain, pdshost, didr, jwtsecret) 170 170 if err != nil { 171 171 return err 172 172 } ··· 187 187 }, 188 188 }, 189 189 Action: func(cctx *cli.Context) error { 190 - raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 191 - if err != nil { 192 - return fmt.Errorf("failed to generate new ECDSA private key: %s", err) 193 - } 194 - 195 - key, err := jwk.FromRaw(raw) 196 - if err != nil { 197 - return fmt.Errorf("failed to create ECDSA key: %s", err) 198 - } 199 - 200 - if _, ok := key.(jwk.ECDSAPrivateKey); !ok { 201 - return fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key) 202 - } 203 - 204 - key.Set(jwk.KeyIDKey, "mykey") 205 - 206 - buf, err := json.MarshalIndent(key, "", " ") 207 - if err != nil { 208 - return fmt.Errorf("failed to marshal key into JSON: %w", err) 209 - } 210 - 211 190 fname := cctx.String("output") 212 - // ensure data directory exists; won't error if it does 213 - os.MkdirAll(filepath.Dir(fname), os.ModePerm) 214 - 215 - return os.WriteFile(fname, buf, 0664) 191 + return cliutil.GenerateKeyToFile(fname) 216 192 }, 217 193 }
-46
labeling/util.go
··· 1 1 package labeling 2 2 3 - import ( 4 - "crypto/ecdsa" 5 - "fmt" 6 - "os" 7 - 8 - "github.com/lestrrat-go/jwx/v2/jwa" 9 - "github.com/lestrrat-go/jwx/v2/jwk" 10 - "github.com/whyrusleeping/go-did" 11 - ) 12 - 13 - // TODO:(bnewbold): duplicates elsewhere; should refactor into cliutil 14 - func LoadKeyFromFile(kfile string) (*did.PrivKey, error) { 15 - kb, err := os.ReadFile(kfile) 16 - if err != nil { 17 - return nil, err 18 - } 19 - 20 - sk, err := jwk.ParseKey(kb) 21 - if err != nil { 22 - return nil, err 23 - } 24 - 25 - var spk ecdsa.PrivateKey 26 - if err := sk.Raw(&spk); err != nil { 27 - return nil, err 28 - } 29 - curve, ok := sk.Get("crv") 30 - if !ok { 31 - return nil, fmt.Errorf("need a curve set") 32 - } 33 - 34 - var out string 35 - kts := string(curve.(jwa.EllipticCurveAlgorithm)) 36 - switch kts { 37 - case "P-256": 38 - out = did.KeyTypeP256 39 - default: 40 - return nil, fmt.Errorf("unrecognized key type: %s", kts) 41 - } 42 - 43 - return &did.PrivKey{ 44 - Raw: &spk, 45 - Type: out, 46 - }, nil 47 - } 48 - 49 3 func dedupeStrings(in []string) []string { 50 4 var out []string 51 5 seen := make(map[string]bool)
+3 -1
pds/handlers.go
··· 470 470 }, nil 471 471 } 472 472 473 + var ErrInvalidUsernameOrPassword = fmt.Errorf("invalid username or password") 474 + 473 475 func (s *Server) handleComAtprotoServerCreateSession(ctx context.Context, body *comatprototypes.ServerCreateSession_Input) (*comatprototypes.ServerCreateSession_Output, error) { 474 476 u, err := s.lookupUserByHandle(ctx, *body.Identifier) 475 477 if err != nil { ··· 477 479 } 478 480 479 481 if body.Password != u.Password { 480 - return nil, fmt.Errorf("invalid username or password") 482 + return nil, ErrInvalidUsernameOrPassword 481 483 } 482 484 483 485 tok, err := s.createAuthTokenForUser(ctx, *body.Identifier, u.Did)
+126
pds/handlers_test.go
··· 1 + package pds 2 + 3 + import ( 4 + "context" 5 + "crypto/ecdsa" 6 + "crypto/elliptic" 7 + "crypto/rand" 8 + "os" 9 + "path/filepath" 10 + "testing" 11 + 12 + "github.com/bluesky-social/indigo/api/atproto" 13 + "github.com/bluesky-social/indigo/carstore" 14 + cliutil "github.com/bluesky-social/indigo/cmd/gosky/util" 15 + "github.com/bluesky-social/indigo/plc" 16 + "github.com/whyrusleeping/go-did" 17 + "gorm.io/gorm" 18 + ) 19 + 20 + func testCarStore(t *testing.T, db *gorm.DB) (*carstore.CarStore, func()) { 21 + t.Helper() 22 + tempdir, err := os.MkdirTemp("", "msttest-") 23 + if err != nil { 24 + t.Fatal(err) 25 + } 26 + 27 + sharddir := filepath.Join(tempdir, "shards") 28 + if err := os.MkdirAll(sharddir, 0775); err != nil { 29 + t.Fatal(err) 30 + } 31 + 32 + cs, err := carstore.NewCarStore(db, sharddir) 33 + if err != nil { 34 + t.Fatal(err) 35 + } 36 + 37 + return cs, func() { _ = os.RemoveAll(tempdir) } 38 + } 39 + 40 + func newTestServer(t *testing.T) (*Server, func()) { 41 + t.Helper() 42 + db, err := cliutil.SetupDatabase("sqlite://:memory:") 43 + if err != nil { 44 + t.Fatal(err) 45 + } 46 + cs, cleanup := testCarStore(t, db) 47 + fakePlc := plc.NewFakeDid(db) 48 + raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 49 + if err != nil { 50 + t.Fatal(err) 51 + } 52 + serkey := &did.PrivKey{ 53 + Raw: raw, 54 + Type: did.KeyTypeP256, 55 + } 56 + 57 + s, err := NewServer(db, cs, serkey, ".test", "", fakePlc, []byte("jwtsecretplaceholder")) 58 + if err != nil { 59 + t.Fatal(err) 60 + } 61 + return s, func() { 62 + cleanup() 63 + sqlDB, err := db.DB() 64 + if err != nil { 65 + t.Fatal(err) 66 + } 67 + err = sqlDB.Close() 68 + if err != nil { 69 + t.Fatal(err) 70 + } 71 + } 72 + } 73 + 74 + func TestHandleComAtprotoAccountCreate(t *testing.T) { 75 + s, cleanup := newTestServer(t) 76 + defer cleanup() 77 + 78 + o, err := s.handleComAtprotoServerCreateAccount(context.Background(), &atproto.ServerCreateAccount_Input{ 79 + Email: "test@foo.com", 80 + Password: "password", 81 + Handle: "testman.test", 82 + }) 83 + if err != nil { 84 + t.Fatal(err) 85 + } 86 + u, err := s.lookupUserByDid(context.Background(), o.Did) 87 + if err != nil { 88 + t.Fatal(err) 89 + } 90 + if u.Email != "test@foo.com" { 91 + t.Fatal("user has different email") 92 + } 93 + 94 + } 95 + 96 + func TestHandleComAtprotoSessionCreate(t *testing.T) { 97 + s, cleanup := newTestServer(t) 98 + defer cleanup() 99 + 100 + o, err := s.handleComAtprotoServerCreateAccount(context.Background(), &atproto.ServerCreateAccount_Input{ 101 + Email: "test@foo.com", 102 + Password: "password", 103 + Handle: "testman.test", 104 + }) 105 + if err != nil { 106 + t.Fatal(err) 107 + } 108 + so, err := s.handleComAtprotoServerCreateSession(context.Background(), &atproto.ServerCreateSession_Input{ 109 + Identifier: &o.Handle, 110 + Password: "password", 111 + }) 112 + if err != nil { 113 + t.Fatal(err) 114 + } 115 + if so.Handle != o.Handle { 116 + t.Fatal("user has different handle") 117 + } 118 + 119 + _, err = s.handleComAtprotoServerCreateSession(context.Background(), &atproto.ServerCreateSession_Input{ 120 + Identifier: &o.Handle, 121 + Password: "invalid", 122 + }) 123 + if err != ErrInvalidUsernameOrPassword { 124 + t.Fatalf("expected error %s, got %s\n", ErrInvalidUsernameOrPassword, err) 125 + } 126 + }
+1 -46
pds/server.go
··· 2 2 3 3 import ( 4 4 "context" 5 - "crypto/ecdsa" 6 5 "encoding/json" 7 6 "errors" 8 7 "fmt" 9 8 "net/mail" 10 9 "net/url" 11 - "os" 12 10 "strings" 13 11 "time" 14 12 ··· 30 28 logging "github.com/ipfs/go-log" 31 29 "github.com/labstack/echo/v4" 32 30 "github.com/labstack/echo/v4/middleware" 33 - "github.com/lestrrat-go/jwx/v2/jwa" 34 - "github.com/lestrrat-go/jwx/v2/jwk" 35 31 "github.com/lestrrat-go/jwx/v2/jwt" 36 32 "github.com/whyrusleeping/go-did" 37 33 "gorm.io/gorm" ··· 61 57 const UserActorDeclCid = "bafyreid27zk7lbis4zw5fz4podbvbs4fc5ivwji3dmrwa6zggnj4bnd57u" 62 58 const UserActorDeclType = "app.bsky.system.actorUser" 63 59 64 - func NewServer(db *gorm.DB, cs *carstore.CarStore, kfile string, handleSuffix, serviceUrl string, didr plc.PLCClient, jwtkey []byte) (*Server, error) { 60 + func NewServer(db *gorm.DB, cs *carstore.CarStore, serkey *did.PrivKey, handleSuffix, serviceUrl string, didr plc.PLCClient, jwtkey []byte) (*Server, error) { 65 61 db.AutoMigrate(&User{}) 66 62 db.AutoMigrate(&Peering{}) 67 - 68 - serkey, err := loadKey(kfile) 69 - if err != nil { 70 - return nil, err 71 - } 72 63 73 64 evtman := events.NewEventManager(events.NewMemPersister()) 74 65 ··· 274 265 return lexutil.CborDecodeValue(blk.RawData()) 275 266 } 276 267 277 - func loadKey(kfile string) (*did.PrivKey, error) { 278 - kb, err := os.ReadFile(kfile) 279 - if err != nil { 280 - return nil, err 281 - } 282 - 283 - sk, err := jwk.ParseKey(kb) 284 - if err != nil { 285 - return nil, err 286 - } 287 - 288 - var spk ecdsa.PrivateKey 289 - if err := sk.Raw(&spk); err != nil { 290 - return nil, err 291 - } 292 - curve, ok := sk.Get("crv") 293 - if !ok { 294 - return nil, fmt.Errorf("need a curve set") 295 - } 296 - 297 - var out string 298 - kts := string(curve.(jwa.EllipticCurveAlgorithm)) 299 - switch kts { 300 - case "P-256": 301 - out = did.KeyTypeP256 302 - default: 303 - return nil, fmt.Errorf("unrecognized key type: %s", kts) 304 - } 305 - 306 - return &did.PrivKey{ 307 - Raw: &spk, 308 - Type: out, 309 - }, nil 310 - } 311 - 312 268 func (s *Server) RunAPI(listen string) error { 313 269 e := echo.New() 314 270 s.echo = e ··· 490 446 if err := s.db.Find(&u, "handle = ?", handle).Error; err != nil { 491 447 return nil, err 492 448 } 493 - fmt.Println("USER: ", handle) 494 449 if u.ID == 0 { 495 450 return nil, ErrNoSuchUser 496 451 }
+9 -35
testing/utils.go
··· 6 6 "crypto/elliptic" 7 7 "crypto/rand" 8 8 "encoding/base32" 9 - "encoding/json" 10 9 "fmt" 11 10 mathrand "math/rand" 12 11 "net/http" ··· 33 32 bsutil "github.com/bluesky-social/indigo/util" 34 33 "github.com/bluesky-social/indigo/xrpc" 35 34 "github.com/ipfs/go-cid" 36 - "github.com/lestrrat-go/jwx/v2/jwk" 37 35 "github.com/multiformats/go-multihash" 36 + "github.com/whyrusleeping/go-did" 38 37 39 38 "github.com/gorilla/websocket" 40 39 "gorm.io/driver/sqlite" 41 40 "gorm.io/gorm" 42 41 ) 43 42 44 - func makeKey(fname string) error { 45 - raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 46 - if err != nil { 47 - return fmt.Errorf("failed to generate new ECDSA private key: %s", err) 48 - } 49 - 50 - key, err := jwk.FromRaw(raw) 51 - if err != nil { 52 - return fmt.Errorf("failed to create ECDSA key: %s", err) 53 - } 54 - 55 - if _, ok := key.(jwk.ECDSAPrivateKey); !ok { 56 - return fmt.Errorf("expected jwk.ECDSAPrivateKey, got %T", key) 57 - } 58 - 59 - key.Set(jwk.KeyIDKey, "mykey") 60 - 61 - buf, err := json.MarshalIndent(key, "", " ") 62 - if err != nil { 63 - return fmt.Errorf("failed to marshal key into JSON: %w", err) 64 - } 65 - 66 - if err := os.WriteFile(fname, buf, 0664); err != nil { 67 - return err 68 - } 69 - 70 - return nil 71 - } 72 - 73 43 type testPDS struct { 74 44 dir string 75 45 server *pds.Server ··· 127 97 return nil, err 128 98 } 129 99 130 - kfile := filepath.Join(dir, "server.key") 131 - if err := makeKey(kfile); err != nil { 132 - return nil, err 100 + raw, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 101 + if err != nil { 102 + return nil, fmt.Errorf("failed to generate new ECDSA private key: %s", err) 103 + } 104 + serkey := &did.PrivKey{ 105 + Raw: raw, 106 + Type: did.KeyTypeP256, 133 107 } 134 108 135 - srv, err := pds.NewServer(maindb, cs, kfile, suffix, host, plc, []byte(host+suffix)) 109 + srv, err := pds.NewServer(maindb, cs, serkey, suffix, host, plc, []byte(host+suffix)) 136 110 if err != nil { 137 111 return nil, err 138 112 }