···2626 - `api/bsky`: generated types for `app.bsky` lexicon
2727 - `api/chat`: generated types for `chat.bsky` lexicon
2828 - `api/ozone`: generated types for `tools.ozone` lexicon
2929-- `atproto/crypto`: cryptographic helpers (signing, key generation and serialization)
2929+- `atproto/atcrypto`: cryptographic helpers (signing, key generation and serialization)
3030- `atproto/syntax`: string types and parsers for identifiers, datetimes, etc
3131- `atproto/identity`: DID and handle resolution
3232-- `atproto/data`: helpers for atproto data as JSON or CBOR with unknown schema
3232+- `atproto/atdata`: helpers for atproto data as JSON or CBOR with unknown schema
3333- `atproto/lexicon`: lexicon validation of generic data
3434- `atproto/repo`: repo and MST implementation
3535- `automod`: moderation and anti-spam rules engine
+1-1
README.md
···2525| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2626| `api/atproto`: generated types for `com.atproto.*` Lexicons | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/api/atproto) |
2727| `api/bsky`: generated types for `app.bsky.*` Lexicons | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/api/bsky) |
2828-| `atproto/crypto`: crytographic signing and key serialization | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/atproto/crypto) |
2828+| `atproto/atcrypto`: crytographic signing and key serialization | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/atproto/atcrypto) |
2929| `atproto/identity`: DID and handle resolution | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/atproto/identity) |
3030| `atproto/syntax`: string types and parsers for identifiers | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/atproto/syntax) |
3131| `atproto/lexicon`: schema validation of data | [](https://pkg.go.dev/mod/github.com/bluesky-social/indigo/atproto/lexicon) |
···12121313 _ "github.com/joho/godotenv/autoload"
14141515+ "github.com/bluesky-social/indigo/atproto/atcrypto"
1516 "github.com/bluesky-social/indigo/atproto/auth/oauth"
1616- "github.com/bluesky-social/indigo/atproto/crypto"
1717 "github.com/bluesky-social/indigo/atproto/identity"
1818 "github.com/bluesky-social/indigo/atproto/syntax"
1919···101101102102 // If a client secret key is provided (as a multibase string), turn this in to a confidential client
103103 if cctx.String("client-secret-key") != "" && hostname != "" {
104104- priv, err := crypto.ParsePrivateMultibase(cctx.String("client-secret-key"))
104104+ priv, err := atcrypto.ParsePrivateMultibase(cctx.String("client-secret-key"))
105105 if err != nil {
106106 return err
107107 }
+2-2
atproto/auth/oauth/jwt_signing.go
···44 "crypto"
55 "fmt"
6677- atcrypto "github.com/bluesky-social/indigo/atproto/crypto"
77+ "github.com/bluesky-social/indigo/atproto/atcrypto"
88 "github.com/golang-jwt/jwt/v5"
99)
1010···1515 supportedAlgs []string
1616)
17171818-// Implementation of jwt.SigningMethod for the `atproto/crypto` types.
1818+// Implementation of jwt.SigningMethod for the `atproto/atcrypto` types.
1919type signingMethodAtproto struct {
2020 alg string
2121 hash crypto.Hash
+11-11
atproto/auth/oauth/oauth.go
···1111 "strings"
1212 "time"
13131414- "github.com/bluesky-social/indigo/atproto/crypto"
1414+ "github.com/bluesky-social/indigo/atproto/atcrypto"
1515 "github.com/bluesky-social/indigo/atproto/identity"
1616 "github.com/bluesky-social/indigo/atproto/syntax"
1717···4343 UserAgent string
44444545 // For confidential clients, the private client assertion key. Note that while an interface is used here, only P-256 is allowed by the current specification.
4646- PrivateKey crypto.PrivateKey
4646+ PrivateKey atcrypto.PrivateKey
47474848 // ID for current client assertion key (should be provided if PrivateKey is)
4949 KeyID *string
···112112 return config.PrivateKey != nil && config.KeyID != nil
113113}
114114115115-func (config *ClientConfig) SetClientSecret(priv crypto.PrivateKey, keyID string) error {
115115+func (config *ClientConfig) SetClientSecret(priv atcrypto.PrivateKey, keyID string) error {
116116 switch priv.(type) {
117117- case *crypto.PrivateKeyP256:
117117+ case *atcrypto.PrivateKeyP256:
118118 // pass
119119- case *crypto.PrivateKeyK256:
119119+ case *atcrypto.PrivateKeyK256:
120120 return fmt.Errorf("only P-256 (ES256) private keys supported for atproto OAuth")
121121 default:
122122 return fmt.Errorf("unknown private key type: %T", priv)
···131131// If the client does not have any keys (eg, public client), returns an empty set.
132132func (config *ClientConfig) PublicJWKS() JWKS {
133133134134- jwks := JWKS{Keys: []crypto.JWK{}}
134134+ jwks := JWKS{Keys: []atcrypto.JWK{}}
135135136136 // public client with no keys
137137 if config.PrivateKey == nil || config.KeyID == nil {
···148148 }
149149 jwk.KeyID = config.KeyID
150150151151- jwks.Keys = []crypto.JWK{*jwk}
151151+ jwks.Keys = []atcrypto.JWK{*jwk}
152152 return jwks
153153}
154154···209209 }
210210211211 // TODO: refactor this in to ClientAuthStore layer?
212212- priv, err := crypto.ParsePrivateMultibase(sd.DPoPPrivateKeyMultibase)
212212+ priv, err := atcrypto.ParsePrivateMultibase(sd.DPoPPrivateKeyMultibase)
213213 if err != nil {
214214 return nil, err
215215 }
···264264// Creates a DPoP token (JWT) for use with an OAuth Auth Server (not to be used with Resource Server). The returned JWT is not bound to an Access Token (no 'ath'), and does not indicate an issuer ('iss').
265265//
266266// This is used during initial auth request (PAR), initial token request, and subsequent refresh token requests. Note that a full [ClientSession] is not available in several of these circumstances, so this is a stand-alone function.
267267-func NewAuthDPoP(httpMethod, url, dpopNonce string, privKey crypto.PrivateKey) (string, error) {
267267+func NewAuthDPoP(httpMethod, url, dpopNonce string, privKey atcrypto.PrivateKey) (string, error) {
268268269269 claims := dpopClaims{
270270 HTTPMethod: httpMethod,
···356356 dpopServerNonce := ""
357357358358 // create new key for the session
359359- dpopPrivKey, err := crypto.GeneratePrivateKeyP256()
359359+ dpopPrivKey, err := atcrypto.GeneratePrivateKeyP256()
360360 if err != nil {
361361 return nil, err
362362 }
···447447 body.ClientAssertion = &clientAssertion
448448 }
449449450450- dpopPrivKey, err := crypto.ParsePrivateMultibase(info.DPoPPrivateKeyMultibase)
450450+ dpopPrivKey, err := atcrypto.ParsePrivateMultibase(info.DPoPPrivateKeyMultibase)
451451 if err != nil {
452452 return nil, err
453453 }
+7-7
atproto/auth/oauth/session.go
···1313 "sync"
1414 "time"
15151616- "github.com/bluesky-social/indigo/atproto/client"
1717- "github.com/bluesky-social/indigo/atproto/crypto"
1616+ "github.com/bluesky-social/indigo/atproto/atclient"
1717+ "github.com/bluesky-social/indigo/atproto/atcrypto"
1818 "github.com/bluesky-social/indigo/atproto/syntax"
19192020 "github.com/golang-jwt/jwt/v5"
···6464 // TODO: also persist access token creation time / expiration time? In context that token might not be an easily parsed JWT
6565}
66666767-// Implementation of [client.AuthMethod] for an OAuth session. Handles DPoP request token signing and nonce rotation, and token refresh requests. Optionally uses a callback to persist updated session data.
6767+// Implementation of [atclient.AuthMethod] for an OAuth session. Handles DPoP request token signing and nonce rotation, and token refresh requests. Optionally uses a callback to persist updated session data.
6868//
6969// A single ClientSession instance can be called concurrently: updates to session data (the 'Data' field) are protected with a RW mutex lock. Note that concurrent calls to distinct ClientSession instances for the same session could result in clobbered session data.
7070type ClientSession struct {
···73737474 Config *ClientConfig
7575 Data *ClientSessionData
7676- DPoPPrivateKey crypto.PrivateKey
7676+ DPoPPrivateKey atcrypto.PrivateKey
77777878 PersistSessionCallback PersistSessionCallback
7979···397397 return nil, fmt.Errorf("OAuth client ran out of request retries")
398398}
399399400400-// Creates a new [client.APIClient] which wraps this session for auth.
401401-func (sess *ClientSession) APIClient() *client.APIClient {
402402- c := client.APIClient{
400400+// Creates a new [atclient.APIClient] which wraps this session for auth.
401401+func (sess *ClientSession) APIClient() *atclient.APIClient {
402402+ c := atclient.APIClient{
403403 Client: sess.Client,
404404 Host: sess.Data.HostURL,
405405 Auth: sess,
+2-2
atproto/auth/oauth/types.go
···77 "slices"
88 "strings"
991010- "github.com/bluesky-social/indigo/atproto/crypto"
1010+ "github.com/bluesky-social/indigo/atproto/atcrypto"
1111 "github.com/bluesky-social/indigo/atproto/syntax"
1212)
1313···1919)
20202121type JWKS struct {
2222- Keys []crypto.JWK `json:"keys"`
2222+ Keys []atcrypto.JWK `json:"keys"`
2323}
24242525// Expected response type from looking up OAuth Protected Resource information on a server (eg, a PDS instance)
···18181919This package tries to use minimal dependencies beyond the Go standard library, to make it easy to reference as a dependency. It does require the [github.com/bluesky-social/indigo/atproto/syntax] and [github.com/bluesky-social/indigo/atproto/identity] sibling packages. In particular, this package does not include any auth methods requiring JWTs, to avoid adding any specific JWT implementation as a dependency.
2020*/
2121-package client
2121+package atclient
···11-// Package crypto provides cryptographic keys and operations, as used in atproto (the protocol)
11+// Package atcrypto provides cryptographic keys and operations, as used in atproto (the protocol)
22//
33// This package attempts to abstract away the specific curves, compressions, signature variations, and other implementation details. The goal is to provide as few knobs and options as possible when working with this library. Use of cryptography in atproto is specified in https://atproto.com/specs/cryptography.
44//
···88// - K-256/secp256r1, internally implemented using https://gitlab.com/yawning/secp256k1-voi
99//
1010// "Low-S" signatures are enforced for both key types, both when creating signatures and during verification, as required by the atproto specification.
1111-package crypto
1111+package atcrypto
···11// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
2233-package data
33+package atdata
4455import (
66 "fmt"
···264264 return err
265265 }
266266267267- // t.Ref (data.CIDLink) (struct)
267267+ // t.Ref (atdata.CIDLink) (struct)
268268 if len("ref") > 1000000 {
269269 return xerrors.Errorf("Value in field \"ref\" was too long")
270270 }
···387387 }
388388389389 switch string(nameBuf[:nameLen]) {
390390- // t.Ref (data.CIDLink) (struct)
390390+ // t.Ref (atdata.CIDLink) (struct)
391391 case "ref":
392392393393 {
+1-1
atproto/data/cidlink.go
atproto/atdata/cidlink.go
···11-package data
11+package atdata
2233import (
44 "encoding/json"
+1-1
atproto/data/const.go
atproto/atdata/const.go
···11-package data
11+package atdata
2233const (
44 // maximum size of any CBOR data, in any context, in atproto
+1-1
atproto/data/data.go
atproto/atdata/data.go
···11-package data
11+package atdata
2233import (
44 "encoding/json"
+2-2
atproto/data/doc.go
atproto/atdata/doc.go
···11/*
22-Package data supports schema-less serializaiton and deserialization of atproto data
22+Package atdata supports schema-less serializaiton and deserialization of atproto data
3344Some restrictions from the data model include:
55- string sizes
···15151616Has a helper for serializing generic data (map[string]interface{}) to CBOR, which handles converting JSON-style object types (like $link and $bytes) as needed. There is no "MarshalJSON" method; simply use the standard library's `encoding/json`.
1717*/
1818-package data
1818+package atdata
+1-1
atproto/data/extract.go
atproto/atdata/extract.go
···11-package data
11+package atdata
2233import (
44 "bytes"
···44 "bytes"
55 "fmt"
6677- "github.com/bluesky-social/indigo/atproto/crypto"
88- "github.com/bluesky-social/indigo/atproto/data"
77+ "github.com/bluesky-social/indigo/atproto/atcrypto"
88+ "github.com/bluesky-social/indigo/atproto/atdata"
99 "github.com/bluesky-social/indigo/atproto/syntax"
10101111 "github.com/ipfs/go-cid"
···4545 d := map[string]any{
4646 "did": c.DID,
4747 "version": c.Version,
4848- "prev": (*data.CIDLink)(c.Prev),
4949- "data": data.CIDLink(c.Data),
4848+ "prev": (*atdata.CIDLink)(c.Prev),
4949+ "data": atdata.CIDLink(c.Data),
5050 }
5151 if c.Sig != nil {
5252- d["sig"] = data.Bytes(c.Sig)
5252+ d["sig"] = atdata.Bytes(c.Sig)
5353 }
5454 if c.Rev != "" {
5555 d["rev"] = c.Rev
···8080}
81818282// Signs the commit, storing the signature in the `Sig` field
8383-func (c *Commit) Sign(privkey crypto.PrivateKey) error {
8383+func (c *Commit) Sign(privkey atcrypto.PrivateKey) error {
8484 b, err := c.UnsignedBytes()
8585 if err != nil {
8686 return err
···9494}
95959696// Verifies `Sig` field using the provided key. Returns `nil` if signature is valid.
9797-func (c *Commit) VerifySignature(pubkey crypto.PublicKey) error {
9797+func (c *Commit) VerifySignature(pubkey atcrypto.PublicKey) error {
9898 if c.Sig == nil {
9999 return fmt.Errorf("can not verify unsigned commit")
100100 }
+4-4
automod/engine/blobs.go
···77 "strings"
88 "time"
991010- "github.com/bluesky-social/indigo/atproto/data"
1010+ "github.com/bluesky-social/indigo/atproto/atdata"
1111 lexutil "github.com/bluesky-social/indigo/lex/util"
12121313 "github.com/carlmjohnson/versioninfo"
···2222 return []lexutil.LexBlob{}, nil
2323 }
24242525- rec, err := data.UnmarshalCBOR(c.RecordOp.RecordCBOR)
2525+ rec, err := atdata.UnmarshalCBOR(c.RecordOp.RecordCBOR)
2626 if err != nil {
2727 return nil, fmt.Errorf("parsing generic record CBOR: %v", err)
2828 }
2929- blobs := data.ExtractBlobs(rec)
2929+ blobs := atdata.ExtractBlobs(rec)
30303131- // convert from data.Blob to lexutil.LexBlob; plan is to merge these types eventually
3131+ // convert from atdata.Blob to lexutil.LexBlob; plan is to merge these types eventually
3232 var out []lexutil.LexBlob
3333 for _, b := range blobs {
3434 lb := lexutil.LexBlob{