2024-12-09 16:53:44 +01:00
|
|
|
package client
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2025-03-18 14:18:53 -04:00
|
|
|
"iter"
|
2024-12-09 16:53:44 +01:00
|
|
|
|
2026-01-08 15:45:49 -05:00
|
|
|
"code.sonr.org/go/did-it"
|
|
|
|
|
"code.sonr.org/go/did-it/crypto"
|
2024-12-09 16:53:44 +01:00
|
|
|
"github.com/ipfs/go-cid"
|
2025-08-05 12:11:20 +02:00
|
|
|
|
2026-01-08 15:45:49 -05:00
|
|
|
"code.sonr.org/go/ucan/pkg/command"
|
|
|
|
|
"code.sonr.org/go/ucan/pkg/container"
|
|
|
|
|
"code.sonr.org/go/ucan/pkg/policy"
|
|
|
|
|
"code.sonr.org/go/ucan/token/delegation"
|
|
|
|
|
"code.sonr.org/go/ucan/token/invocation"
|
2024-12-09 16:53:44 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
|
did did.DID
|
2025-08-05 12:11:20 +02:00
|
|
|
privKey crypto.PrivateKeySigningBytes
|
2024-12-09 16:53:44 +01:00
|
|
|
|
|
|
|
|
pool *Pool
|
|
|
|
|
requester DelegationRequester
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-05 12:11:20 +02:00
|
|
|
func NewClient(privKey crypto.PrivateKeySigningBytes, d did.DID, requester DelegationRequester) (*Client, error) {
|
2024-12-09 16:53:44 +01:00
|
|
|
return &Client{
|
|
|
|
|
did: d,
|
|
|
|
|
privKey: privKey,
|
|
|
|
|
pool: NewPool(),
|
|
|
|
|
requester: requester,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 14:18:53 -04:00
|
|
|
// AddBundle adds a delegation.Bundle to the client's pool.
|
|
|
|
|
func (c *Client) AddBundle(bundle *delegation.Bundle) {
|
|
|
|
|
c.pool.AddBundle(bundle)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddBundles adds a sequence of delegation.Bundles to the client's pool.
|
|
|
|
|
func (c *Client) AddBundles(bundles iter.Seq[*delegation.Bundle]) {
|
|
|
|
|
c.pool.AddBundles(bundles)
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 18:03:00 +01:00
|
|
|
// PrepareInvoke returns an invocation, bundled in a container.Writer with the necessary proofs.
|
2024-12-09 16:53:44 +01:00
|
|
|
func (c *Client) PrepareInvoke(ctx context.Context, cmd command.Command, subject did.DID, opts ...invocation.Option) (container.Writer, error) {
|
2025-03-18 18:03:00 +01:00
|
|
|
proof, err := c.findProof(ctx, cmd, subject)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-12-09 16:53:44 +01:00
|
|
|
|
2025-03-18 18:03:00 +01:00
|
|
|
inv, err := invocation.New(c.did, cmd, subject, proof, opts...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
invSealed, _, err := inv.ToSealed(c.privKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cont := container.NewWriter()
|
|
|
|
|
cont.AddSealed(invSealed)
|
|
|
|
|
for bundle, err := range c.pool.GetBundles(proof) {
|
2024-12-09 16:53:44 +01:00
|
|
|
if err != nil {
|
2025-03-18 18:03:00 +01:00
|
|
|
return nil, err
|
2024-12-09 16:53:44 +01:00
|
|
|
}
|
2025-03-18 18:03:00 +01:00
|
|
|
cont.AddSealed(bundle.Sealed)
|
|
|
|
|
}
|
2024-12-09 16:53:44 +01:00
|
|
|
|
2025-03-18 18:03:00 +01:00
|
|
|
return cont, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PrepareDelegation returns a new delegation for a third party DID, bundled in a container.Writer with the necessary proofs.
|
|
|
|
|
func (c *Client) PrepareDelegation(ctx context.Context, aud did.DID, cmd command.Command, subject did.DID, policies policy.Policy, opts ...delegation.Option) (container.Writer, error) {
|
|
|
|
|
proof, err := c.findProof(ctx, cmd, subject)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2024-12-09 16:53:44 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-18 18:03:00 +01:00
|
|
|
dlg, err := delegation.New(c.did, aud, cmd, policies, subject, opts...)
|
2024-12-09 16:53:44 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 18:03:00 +01:00
|
|
|
dlgSealed, _, err := dlg.ToSealed(c.privKey)
|
2024-12-09 16:53:44 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cont := container.NewWriter()
|
2025-03-18 18:03:00 +01:00
|
|
|
cont.AddSealed(dlgSealed)
|
2024-12-09 16:53:44 +01:00
|
|
|
for bundle, err := range c.pool.GetBundles(proof) {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-01-16 15:16:01 +01:00
|
|
|
cont.AddSealed(bundle.Sealed)
|
2024-12-09 16:53:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cont, nil
|
|
|
|
|
}
|
2025-03-18 18:03:00 +01:00
|
|
|
|
|
|
|
|
func (c *Client) findProof(ctx context.Context, cmd command.Command, subject did.DID) ([]cid.Cid, error) {
|
|
|
|
|
var proof []cid.Cid
|
|
|
|
|
|
|
|
|
|
// do we already have a valid proof?
|
|
|
|
|
if proof = c.pool.FindProof(c.did, cmd, subject); len(proof) == 0 {
|
|
|
|
|
// we need to request a new proof
|
|
|
|
|
proofBundles, err := c.requester.RequestDelegation(ctx, c.did, cmd, subject)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("requesting delegation: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cache the new proofs
|
|
|
|
|
for bundle, err := range proofBundles {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
proof = append(proof, bundle.Cid)
|
|
|
|
|
c.pool.AddBundle(bundle)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return proof, nil
|
|
|
|
|
}
|