Files
ucan/toolkit/issuer/root_issuer.go

77 lines
2.3 KiB
Go
Raw Permalink Normal View History

package issuer
import (
"context"
"fmt"
"iter"
"code.sonr.org/go/did-it"
didkeyctl "code.sonr.org/go/did-it/controller/did-key"
"code.sonr.org/go/did-it/crypto"
2025-08-05 12:11:20 +02:00
"code.sonr.org/go/ucan/pkg/command"
"code.sonr.org/go/ucan/token/delegation"
"code.sonr.org/go/ucan/toolkit/client"
)
// RootIssuingLogic is a function that decides what powers are given to a client.
// - issuer: the DID of our issuer
// - audience: the DID of the client, also the issuer of the invocation token
// - cmd: the command to execute
// Note: you can read it as "(audience) wants to do (cmd) on (subject)".
// Note: you can decide to match the input parameters exactly or issue a broader power, as long as it allows the
// expected action. If you don't want to give that power, return an error instead.
type RootIssuingLogic func(iss did.DID, aud did.DID, cmd command.Command) (*delegation.Token, error)
var _ client.DelegationRequester = &RootIssuer{}
// RootIssuer is an implementation of a root delegation issuer.
// Note: Your actual needs for an issuer can easily be different (caching...) than the choices made here.
// Feel free to replace this component with your own flavor.
type RootIssuer struct {
did did.DID
2025-08-05 12:11:20 +02:00
privKey crypto.PrivateKeySigningBytes
logic RootIssuingLogic
}
2025-08-05 12:11:20 +02:00
func NewRootIssuer(privKey crypto.PrivateKeySigningBytes, logic RootIssuingLogic) (*RootIssuer, error) {
d := didkeyctl.FromPrivateKey(privKey)
return &RootIssuer{
did: d,
privKey: privKey,
logic: logic,
}, nil
}
func (r *RootIssuer) RequestDelegation(ctx context.Context, audience did.DID, cmd command.Command, subject did.DID) (iter.Seq2[*delegation.Bundle, error], error) {
2025-08-05 12:11:20 +02:00
if !subject.Equal(r.did) {
return nil, fmt.Errorf("subject DID doesn't match the issuer DID")
}
// run the custom logic to get what we actually issue
dlg, err := r.logic(r.did, audience, cmd)
if err != nil {
return nil, err
}
if !dlg.IsRoot() {
return nil, fmt.Errorf("issuing logic should return a root delegation")
}
// sign and cache the new token
dlgBytes, dlgCid, err := dlg.ToSealed(r.privKey)
if err != nil {
return nil, err
}
bundle := &delegation.Bundle{
Cid: dlgCid,
Decoded: dlg,
Sealed: dlgBytes,
}
// output the root delegation
return func(yield func(*delegation.Bundle, error) bool) {
yield(bundle, nil)
}, nil
}