example: add sub-delegation
This commit is contained in:
committed by
Michael Muré
parent
55f38fef4a
commit
c670433335
@@ -1,123 +0,0 @@
|
||||
package issuer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"iter"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/ucan-wg/go-ucan/did"
|
||||
"github.com/ucan-wg/go-ucan/pkg/command"
|
||||
"github.com/ucan-wg/go-ucan/token/delegation"
|
||||
|
||||
"github.com/INFURA/go-ucan-toolkit/client"
|
||||
)
|
||||
|
||||
// DlgIssuingLogic 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
|
||||
// - subject: the DID of the resource to operate on, also the subject (or audience if defined) of the invocation token
|
||||
// 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 DlgIssuingLogic func(iss did.DID, aud did.DID, cmd command.Command, subject did.DID) (*delegation.Token, error)
|
||||
|
||||
var _ client.DelegationRequester = &Issuer{}
|
||||
|
||||
// Issuer is an implementation of a re-delegating 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 Issuer struct {
|
||||
did did.DID
|
||||
privKey crypto.PrivKey
|
||||
|
||||
pool *client.Pool
|
||||
requester client.DelegationRequester
|
||||
logic DlgIssuingLogic
|
||||
}
|
||||
|
||||
func NewIssuer(privKey crypto.PrivKey, requester client.DelegationRequester, logic DlgIssuingLogic) (*Issuer, error) {
|
||||
d, err := did.FromPrivKey(privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Issuer{
|
||||
did: d,
|
||||
privKey: privKey,
|
||||
pool: client.NewPool(),
|
||||
requester: client.RequesterWithRetry(requester, time.Second, 3),
|
||||
logic: logic,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RequestDelegation retrieve chain of delegation for the given parameters.
|
||||
// - audience: the DID of the client, also the issuer of the invocation token
|
||||
// - cmd: the command to execute
|
||||
// - subject: the DID of the resource to operate on, also the subject (or audience if defined) of the invocation token
|
||||
// Note: you can read it as "(audience) does (cmd) on (subject)".
|
||||
// Note: the returned delegation(s) don't have to match exactly the parameters, as long as they allow them.
|
||||
func (i *Issuer) RequestDelegation(ctx context.Context, audience did.DID, cmd command.Command, subject did.DID) (iter.Seq2[*delegation.Bundle, error], error) {
|
||||
if subject != i.did {
|
||||
return nil, fmt.Errorf("subject DID doesn't match the issuer DID")
|
||||
}
|
||||
|
||||
var proof []cid.Cid
|
||||
|
||||
// is there already a valid proof chain?
|
||||
if proof = i.pool.FindProof(audience, cmd, subject); len(proof) > 0 {
|
||||
return i.pool.GetBundles(proof), nil
|
||||
}
|
||||
|
||||
// do we have the power to delegate this?
|
||||
if proof = i.pool.FindProof(i.did, cmd, subject); len(proof) == 0 {
|
||||
// we need to request a new proof
|
||||
proofBundles, err := i.requester.RequestDelegation(ctx, i.did, cmd, subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// cache the new proofs
|
||||
for bundle, err := range proofBundles {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proof = append(proof, bundle.Cid)
|
||||
i.pool.AddBundle(bundle)
|
||||
}
|
||||
}
|
||||
|
||||
// run the custom logic to get what we actually issue
|
||||
dlg, err := i.logic(i.did, audience, cmd, subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dlg.IsRoot() {
|
||||
return nil, fmt.Errorf("issuing logic should return a non-root delegation")
|
||||
}
|
||||
|
||||
// sign and cache the new token
|
||||
dlgBytes, dlgCid, err := dlg.ToSealed(i.privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bundle := &delegation.Bundle{
|
||||
Cid: dlgCid,
|
||||
Decoded: dlg,
|
||||
Sealed: dlgBytes,
|
||||
}
|
||||
|
||||
// output the relevant delegations
|
||||
return func(yield func(*delegation.Bundle, error) bool) {
|
||||
if !yield(bundle, nil) {
|
||||
return
|
||||
}
|
||||
for b, err := range i.pool.GetBundles(proof) {
|
||||
if !yield(b, err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user