An atproto PDS written in Go

use new plc client

Changed files
+51 -32
identity
plc
server
+8 -7
identity/identity.go
···
"strings"
"github.com/bluesky-social/indigo/atproto/syntax"
)
func ResolveHandle(ctx context.Context, handle string) (string, error) {
···
type DidLog []DidLogEntry
type DidLogEntry struct {
-
Sig string `json:"sig"`
-
Prev *string `json:"prev"`
-
Type string `json:"string"`
-
Services map[string]DidDataService `json:"services"`
-
AlsoKnownAs []string `json:"alsoKnownAs"`
-
RotationKeys []string `json:"rotationKeys"`
-
VerificationMethods map[string]string `json:"verificationMethods"`
}
type DidAuditEntry struct {
···
"strings"
"github.com/bluesky-social/indigo/atproto/syntax"
+
"github.com/haileyok/cocoon/plc"
)
func ResolveHandle(ctx context.Context, handle string) (string, error) {
···
type DidLog []DidLogEntry
type DidLogEntry struct {
+
Sig string `json:"sig"`
+
Prev *string `json:"prev"`
+
Type string `json:"string"`
+
Services map[string]plc.OperationService `json:"services"`
+
AlsoKnownAs []string `json:"alsoKnownAs"`
+
RotationKeys []string `json:"rotationKeys"`
+
VerificationMethods map[string]string `json:"verificationMethods"`
}
type DidAuditEntry struct {
+11 -12
plc/client.go
···
}, nil
}
-
func (c *Client) CreateDID(ctx context.Context, sigkey *crypto.PrivateKeyK256, recovery string, handle string) (string, *PlcOperation, error) {
pubsigkey, err := sigkey.PublicKey()
if err != nil {
return "", nil, err
···
}(recovery)
}
-
op := PlcOperation{
Type: "plc_operation",
VerificationMethods: map[string]string{
"atproto": pubsigkey.DIDKey(),
···
AlsoKnownAs: []string{
"at://" + handle,
},
-
Services: map[string]PlcOperationService{
"atproto_pds": {
Type: "AtprotoPersonalDataServer",
Endpoint: "https://" + c.pdsHostname,
···
Prev: nil,
}
-
signed, err := c.FormatAndSignAtprotoOp(sigkey, op)
-
if err != nil {
return "", nil, err
}
-
did, err := didFromOp(signed)
if err != nil {
return "", nil, err
}
···
return did, &op, nil
}
-
func didFromOp(op *PlcOperation) (string, error) {
b, err := op.MarshalCBOR()
if err != nil {
return "", err
···
return "did:plc:" + b32[0:24], nil
}
-
func (c *Client) FormatAndSignAtprotoOp(sigkey *crypto.PrivateKeyK256, op PlcOperation) (*PlcOperation, error) {
b, err := op.MarshalCBOR()
if err != nil {
-
return nil, err
}
sig, err := c.rotationKey.HashAndSign(b)
if err != nil {
-
return nil, err
}
op.Sig = base64.RawURLEncoding.EncodeToString(sig)
-
return &op, nil
}
-
func (c *Client) SendOperation(ctx context.Context, did string, op *PlcOperation) error {
b, err := json.Marshal(op)
if err != nil {
return err
···
}, nil
}
+
func (c *Client) CreateDID(ctx context.Context, sigkey *crypto.PrivateKeyK256, recovery string, handle string) (string, *Operation, error) {
pubsigkey, err := sigkey.PublicKey()
if err != nil {
return "", nil, err
···
}(recovery)
}
+
op := Operation{
Type: "plc_operation",
VerificationMethods: map[string]string{
"atproto": pubsigkey.DIDKey(),
···
AlsoKnownAs: []string{
"at://" + handle,
},
+
Services: map[string]OperationService{
"atproto_pds": {
Type: "AtprotoPersonalDataServer",
Endpoint: "https://" + c.pdsHostname,
···
Prev: nil,
}
+
if err := c.SignOp(sigkey, &op); err != nil {
return "", nil, err
}
+
did, err := didFromOp(&op)
if err != nil {
return "", nil, err
}
···
return did, &op, nil
}
+
func didFromOp(op *Operation) (string, error) {
b, err := op.MarshalCBOR()
if err != nil {
return "", err
···
return "did:plc:" + b32[0:24], nil
}
+
func (c *Client) SignOp(sigkey *crypto.PrivateKeyK256, op *Operation) error {
b, err := op.MarshalCBOR()
if err != nil {
+
return err
}
sig, err := c.rotationKey.HashAndSign(b)
if err != nil {
+
return err
}
op.Sig = base64.RawURLEncoding.EncodeToString(sig)
+
return nil
}
+
func (c *Client) SendOperation(ctx context.Context, did string, op *Operation) error {
b, err := json.Marshal(op)
if err != nil {
return err
+10 -10
plc/types.go
···
cbg "github.com/whyrusleeping/cbor-gen"
)
-
type PlcOperation struct {
-
Type string `json:"type"`
-
VerificationMethods map[string]string `json:"verificationMethods"`
-
RotationKeys []string `json:"rotationKeys"`
-
AlsoKnownAs []string `json:"alsoKnownAs"`
-
Services map[string]PlcOperationService `json:"services"`
-
Prev *string `json:"prev"`
-
Sig string `json:"sig,omitempty"`
}
-
type PlcOperationService struct {
Type string `json:"type"`
Endpoint string `json:"endpoint"`
}
// This is kinda gross. We could just use cborgen i suppose?
-
func (po *PlcOperation) MarshalCBOR() ([]byte, error) {
if po == nil {
return cbg.CborNull, nil
}
···
cbg "github.com/whyrusleeping/cbor-gen"
)
+
type Operation struct {
+
Type string `json:"type"`
+
VerificationMethods map[string]string `json:"verificationMethods"`
+
RotationKeys []string `json:"rotationKeys"`
+
AlsoKnownAs []string `json:"alsoKnownAs"`
+
Services map[string]OperationService `json:"services"`
+
Prev *string `json:"prev"`
+
Sig string `json:"sig,omitempty"`
}
+
type OperationService struct {
Type string `json:"type"`
Endpoint string `json:"endpoint"`
}
// This is kinda gross. We could just use cborgen i suppose?
+
func (po *Operation) MarshalCBOR() ([]byte, error) {
if po == nil {
return cbg.CborNull, nil
}
+22 -3
server/handle_identity_update_handle.go
···
"github.com/haileyok/cocoon/identity"
"github.com/haileyok/cocoon/internal/helpers"
"github.com/haileyok/cocoon/models"
"github.com/labstack/echo/v4"
)
···
latest := log[len(log)-1]
k, err := crypto.ParsePrivateBytesK256(repo.SigningKey)
if err != nil {
s.logger.Error("error parsing signing key", "error", err)
return helpers.ServerError(e, nil)
}
-
op, err := s.plcClient.FormatAndSignAtprotoOp(k, req.Handle, latest.Operation.RotationKeys, &latest.Cid)
-
if err != nil {
return err
}
-
if err := s.plcClient.SendOperation(context.TODO(), repo.Repo.Did, op); err != nil {
return err
}
}
···
"github.com/haileyok/cocoon/identity"
"github.com/haileyok/cocoon/internal/helpers"
"github.com/haileyok/cocoon/models"
+
"github.com/haileyok/cocoon/plc"
"github.com/labstack/echo/v4"
)
···
latest := log[len(log)-1]
+
var newAka []string
+
for _, aka := range latest.Operation.AlsoKnownAs {
+
if aka == "at://"+repo.Handle {
+
continue
+
}
+
newAka = append(newAka, aka)
+
}
+
+
newAka = append(newAka, "at://"+req.Handle)
+
+
op := plc.Operation{
+
Type: "plc_operation",
+
VerificationMethods: latest.Operation.VerificationMethods,
+
RotationKeys: latest.Operation.RotationKeys,
+
AlsoKnownAs: newAka,
+
Services: latest.Operation.Services,
+
Prev: &latest.Cid,
+
}
+
k, err := crypto.ParsePrivateBytesK256(repo.SigningKey)
if err != nil {
s.logger.Error("error parsing signing key", "error", err)
return helpers.ServerError(e, nil)
}
+
if err := s.plcClient.SignOp(k, &op); err != nil {
return err
}
+
if err := s.plcClient.SendOperation(e.Request().Context(), repo.Repo.Did, &op); err != nil {
return err
}
}