+8
-7
identity/identity.go
+8
-7
identity/identity.go
···
10
"strings"
11
12
"github.com/bluesky-social/indigo/atproto/syntax"
13
)
14
15
func ResolveHandle(ctx context.Context, handle string) (string, error) {
···
108
type DidLog []DidLogEntry
109
110
type DidLogEntry struct {
111
-
Sig string `json:"sig"`
112
-
Prev *string `json:"prev"`
113
-
Type string `json:"string"`
114
-
Services map[string]DidDataService `json:"services"`
115
-
AlsoKnownAs []string `json:"alsoKnownAs"`
116
-
RotationKeys []string `json:"rotationKeys"`
117
-
VerificationMethods map[string]string `json:"verificationMethods"`
118
}
119
120
type DidAuditEntry struct {
···
10
"strings"
11
12
"github.com/bluesky-social/indigo/atproto/syntax"
13
+
"github.com/haileyok/cocoon/plc"
14
)
15
16
func ResolveHandle(ctx context.Context, handle string) (string, error) {
···
109
type DidLog []DidLogEntry
110
111
type DidLogEntry struct {
112
+
Sig string `json:"sig"`
113
+
Prev *string `json:"prev"`
114
+
Type string `json:"string"`
115
+
Services map[string]plc.OperationService `json:"services"`
116
+
AlsoKnownAs []string `json:"alsoKnownAs"`
117
+
RotationKeys []string `json:"rotationKeys"`
118
+
VerificationMethods map[string]string `json:"verificationMethods"`
119
}
120
121
type DidAuditEntry struct {
+11
-12
plc/client.go
+11
-12
plc/client.go
···
48
}, nil
49
}
50
51
-
func (c *Client) CreateDID(ctx context.Context, sigkey *crypto.PrivateKeyK256, recovery string, handle string) (string, *PlcOperation, error) {
52
pubsigkey, err := sigkey.PublicKey()
53
if err != nil {
54
return "", nil, err
···
71
}(recovery)
72
}
73
74
-
op := PlcOperation{
75
Type: "plc_operation",
76
VerificationMethods: map[string]string{
77
"atproto": pubsigkey.DIDKey(),
···
80
AlsoKnownAs: []string{
81
"at://" + handle,
82
},
83
-
Services: map[string]PlcOperationService{
84
"atproto_pds": {
85
Type: "AtprotoPersonalDataServer",
86
Endpoint: "https://" + c.pdsHostname,
···
89
Prev: nil,
90
}
91
92
-
signed, err := c.FormatAndSignAtprotoOp(sigkey, op)
93
-
if err != nil {
94
return "", nil, err
95
}
96
97
-
did, err := didFromOp(signed)
98
if err != nil {
99
return "", nil, err
100
}
···
102
return did, &op, nil
103
}
104
105
-
func didFromOp(op *PlcOperation) (string, error) {
106
b, err := op.MarshalCBOR()
107
if err != nil {
108
return "", err
···
112
return "did:plc:" + b32[0:24], nil
113
}
114
115
-
func (c *Client) FormatAndSignAtprotoOp(sigkey *crypto.PrivateKeyK256, op PlcOperation) (*PlcOperation, error) {
116
b, err := op.MarshalCBOR()
117
if err != nil {
118
-
return nil, err
119
}
120
121
sig, err := c.rotationKey.HashAndSign(b)
122
if err != nil {
123
-
return nil, err
124
}
125
126
op.Sig = base64.RawURLEncoding.EncodeToString(sig)
127
128
-
return &op, nil
129
}
130
131
-
func (c *Client) SendOperation(ctx context.Context, did string, op *PlcOperation) error {
132
b, err := json.Marshal(op)
133
if err != nil {
134
return err
···
48
}, nil
49
}
50
51
+
func (c *Client) CreateDID(ctx context.Context, sigkey *crypto.PrivateKeyK256, recovery string, handle string) (string, *Operation, error) {
52
pubsigkey, err := sigkey.PublicKey()
53
if err != nil {
54
return "", nil, err
···
71
}(recovery)
72
}
73
74
+
op := Operation{
75
Type: "plc_operation",
76
VerificationMethods: map[string]string{
77
"atproto": pubsigkey.DIDKey(),
···
80
AlsoKnownAs: []string{
81
"at://" + handle,
82
},
83
+
Services: map[string]OperationService{
84
"atproto_pds": {
85
Type: "AtprotoPersonalDataServer",
86
Endpoint: "https://" + c.pdsHostname,
···
89
Prev: nil,
90
}
91
92
+
if err := c.SignOp(sigkey, &op); err != nil {
93
return "", nil, err
94
}
95
96
+
did, err := didFromOp(&op)
97
if err != nil {
98
return "", nil, err
99
}
···
101
return did, &op, nil
102
}
103
104
+
func didFromOp(op *Operation) (string, error) {
105
b, err := op.MarshalCBOR()
106
if err != nil {
107
return "", err
···
111
return "did:plc:" + b32[0:24], nil
112
}
113
114
+
func (c *Client) SignOp(sigkey *crypto.PrivateKeyK256, op *Operation) error {
115
b, err := op.MarshalCBOR()
116
if err != nil {
117
+
return err
118
}
119
120
sig, err := c.rotationKey.HashAndSign(b)
121
if err != nil {
122
+
return err
123
}
124
125
op.Sig = base64.RawURLEncoding.EncodeToString(sig)
126
127
+
return nil
128
}
129
130
+
func (c *Client) SendOperation(ctx context.Context, did string, op *Operation) error {
131
b, err := json.Marshal(op)
132
if err != nil {
133
return err
+10
-10
plc/types.go
+10
-10
plc/types.go
···
7
cbg "github.com/whyrusleeping/cbor-gen"
8
)
9
10
-
type PlcOperation struct {
11
-
Type string `json:"type"`
12
-
VerificationMethods map[string]string `json:"verificationMethods"`
13
-
RotationKeys []string `json:"rotationKeys"`
14
-
AlsoKnownAs []string `json:"alsoKnownAs"`
15
-
Services map[string]PlcOperationService `json:"services"`
16
-
Prev *string `json:"prev"`
17
-
Sig string `json:"sig,omitempty"`
18
}
19
20
-
type PlcOperationService struct {
21
Type string `json:"type"`
22
Endpoint string `json:"endpoint"`
23
}
24
25
// This is kinda gross. We could just use cborgen i suppose?
26
-
func (po *PlcOperation) MarshalCBOR() ([]byte, error) {
27
if po == nil {
28
return cbg.CborNull, nil
29
}
···
7
cbg "github.com/whyrusleeping/cbor-gen"
8
)
9
10
+
type Operation struct {
11
+
Type string `json:"type"`
12
+
VerificationMethods map[string]string `json:"verificationMethods"`
13
+
RotationKeys []string `json:"rotationKeys"`
14
+
AlsoKnownAs []string `json:"alsoKnownAs"`
15
+
Services map[string]OperationService `json:"services"`
16
+
Prev *string `json:"prev"`
17
+
Sig string `json:"sig,omitempty"`
18
}
19
20
+
type OperationService struct {
21
Type string `json:"type"`
22
Endpoint string `json:"endpoint"`
23
}
24
25
// This is kinda gross. We could just use cborgen i suppose?
26
+
func (po *Operation) MarshalCBOR() ([]byte, error) {
27
if po == nil {
28
return cbg.CborNull, nil
29
}
+22
-3
server/handle_identity_update_handle.go
+22
-3
server/handle_identity_update_handle.go
···
13
"github.com/haileyok/cocoon/identity"
14
"github.com/haileyok/cocoon/internal/helpers"
15
"github.com/haileyok/cocoon/models"
16
"github.com/labstack/echo/v4"
17
)
18
···
46
47
latest := log[len(log)-1]
48
49
k, err := crypto.ParsePrivateBytesK256(repo.SigningKey)
50
if err != nil {
51
s.logger.Error("error parsing signing key", "error", err)
52
return helpers.ServerError(e, nil)
53
}
54
55
-
op, err := s.plcClient.FormatAndSignAtprotoOp(k, req.Handle, latest.Operation.RotationKeys, &latest.Cid)
56
-
if err != nil {
57
return err
58
}
59
60
-
if err := s.plcClient.SendOperation(context.TODO(), repo.Repo.Did, op); err != nil {
61
return err
62
}
63
}
···
13
"github.com/haileyok/cocoon/identity"
14
"github.com/haileyok/cocoon/internal/helpers"
15
"github.com/haileyok/cocoon/models"
16
+
"github.com/haileyok/cocoon/plc"
17
"github.com/labstack/echo/v4"
18
)
19
···
47
48
latest := log[len(log)-1]
49
50
+
var newAka []string
51
+
for _, aka := range latest.Operation.AlsoKnownAs {
52
+
if aka == "at://"+repo.Handle {
53
+
continue
54
+
}
55
+
newAka = append(newAka, aka)
56
+
}
57
+
58
+
newAka = append(newAka, "at://"+req.Handle)
59
+
60
+
op := plc.Operation{
61
+
Type: "plc_operation",
62
+
VerificationMethods: latest.Operation.VerificationMethods,
63
+
RotationKeys: latest.Operation.RotationKeys,
64
+
AlsoKnownAs: newAka,
65
+
Services: latest.Operation.Services,
66
+
Prev: &latest.Cid,
67
+
}
68
+
69
k, err := crypto.ParsePrivateBytesK256(repo.SigningKey)
70
if err != nil {
71
s.logger.Error("error parsing signing key", "error", err)
72
return helpers.ServerError(e, nil)
73
}
74
75
+
if err := s.plcClient.SignOp(k, &op); err != nil {
76
return err
77
}
78
79
+
if err := s.plcClient.SendOperation(e.Request().Context(), repo.Repo.Did, &op); err != nil {
80
return err
81
}
82
}