github.com/storacha/go-ucanto@v0.7.2/ucan/view.go (about)

     1  package ucan
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/storacha/go-ucanto/did"
     7  	"github.com/storacha/go-ucanto/ucan/crypto/signature"
     8  	udm "github.com/storacha/go-ucanto/ucan/datamodel/ucan"
     9  )
    10  
    11  type UCAN interface {
    12  	// Issuer is the signer of the UCAN.
    13  	Issuer() Principal
    14  	// Audience is the principal delegated to.
    15  	Audience() Principal
    16  	// Version is the spec version the UCAN conforms to.
    17  	Version() Version
    18  	// Capabilities are claimed abilities that can be performed on a resource.
    19  	Capabilities() []Capability[any]
    20  	// Expiration is the time in seconds since the Unix epoch that the UCAN
    21  	// becomes invalid.
    22  	Expiration() *UTCUnixTimestamp
    23  	// NotBefore is the time in seconds since the Unix epoch that the UCAN
    24  	// becomes valid.
    25  	NotBefore() UTCUnixTimestamp
    26  	// Nonce is a randomly generated string to provide a unique
    27  	Nonce() Nonce
    28  	// Facts are arbitrary facts and proofs of knowledge.
    29  	Facts() []Fact
    30  	// Proofs of delegation.
    31  	Proofs() []Link
    32  	// Signature of the UCAN issuer.
    33  	Signature() signature.SignatureView
    34  }
    35  
    36  // View represents a decoded "view" of a UCAN that can be used in your
    37  // domain logic, etc.
    38  type View interface {
    39  	UCAN
    40  	// Model references the underlying IPLD datamodel instance.
    41  	Model() *udm.UCANModel
    42  }
    43  
    44  type ucanView struct {
    45  	model *udm.UCANModel
    46  }
    47  
    48  var _ View = (*ucanView)(nil)
    49  
    50  func (v *ucanView) Audience() Principal {
    51  	did, err := did.Decode(v.model.Aud)
    52  	if err != nil {
    53  		fmt.Printf("Error: decoding audience DID: %s\n", err)
    54  	}
    55  	return did
    56  }
    57  
    58  func (v *ucanView) Capabilities() []Capability[any] {
    59  	caps := []Capability[any]{}
    60  	for _, c := range v.model.Att {
    61  		caps = append(caps, NewCapability[any](c.Can, c.With, c.Nb))
    62  	}
    63  	return caps
    64  }
    65  
    66  func (v *ucanView) Expiration() *UTCUnixTimestamp {
    67  	return v.model.Exp
    68  }
    69  
    70  func (v *ucanView) Facts() []map[string]any {
    71  	facts := []map[string]any{}
    72  	for _, f := range v.model.Fct {
    73  		fact := map[string]any{}
    74  		for k, v := range f.Values {
    75  			fact[k] = v
    76  		}
    77  		facts = append(facts, fact)
    78  	}
    79  	return facts
    80  }
    81  
    82  func (v *ucanView) Issuer() Principal {
    83  	did, err := did.Decode(v.model.Iss)
    84  	if err != nil {
    85  		fmt.Printf("decoding issuer DID: %s\n", err)
    86  	}
    87  	return did
    88  }
    89  
    90  func (v *ucanView) Model() *udm.UCANModel {
    91  	return v.model
    92  }
    93  
    94  func (v *ucanView) Nonce() string {
    95  	if v.model.Nnc == nil {
    96  		return ""
    97  	}
    98  	return *v.model.Nnc
    99  }
   100  
   101  func (v *ucanView) NotBefore() int {
   102  	if v.model.Nbf == nil {
   103  		return 0
   104  	}
   105  	return *v.model.Nbf
   106  }
   107  
   108  func (v *ucanView) Proofs() []Link {
   109  	return v.model.Prf
   110  }
   111  
   112  func (v *ucanView) Signature() signature.SignatureView {
   113  	s := signature.Decode(v.model.S)
   114  	return signature.NewSignatureView(s)
   115  }
   116  
   117  func (v *ucanView) Version() string {
   118  	return v.model.V
   119  }
   120  
   121  // NewUCAN creates a UCAN view from the underlying data model. Please note
   122  // that this function does no verification of the model and it is callers
   123  // responsibility to ensure that:
   124  //
   125  //  1. Data model is correct contains all the field etc.
   126  //  2. Payload of the signature will match paylodad when model is serialized
   127  //     with DAG-JSON.
   128  //
   129  // In other words you should never use this function unless you've parsed or
   130  // decoded a valid UCAN and want to wrap it into a view.
   131  func NewUCAN(model *udm.UCANModel) (View, error) {
   132  	return &ucanView{model}, nil
   133  }