Files
motr-enclave/internal/crypto/mpc/spec/ucan.go

126 lines
3.3 KiB
Go

package spec
import (
"encoding/json"
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/types/bech32"
)
// Token represents a UCAN JWT token with parsed claims
type Token struct {
Raw string `json:"raw"`
Issuer string `json:"iss"`
Audience string `json:"aud"`
ExpiresAt int64 `json:"exp,omitempty"`
NotBefore int64 `json:"nbf,omitempty"`
Attenuations []Attenuation `json:"att"`
Proofs []Proof `json:"prf,omitempty"`
Facts []Fact `json:"fct,omitempty"`
}
// Attenuation represents a UCAN capability attenuation
type Attenuation struct {
Capability Capability `json:"can"`
Resource Resource `json:"with"`
}
// Proof represents a UCAN delegation proof (either JWT or CID)
type Proof string
// Fact represents arbitrary facts in UCAN tokens
type Fact struct {
Data json.RawMessage `json:"data"`
}
// Capability defines what actions can be performed
type Capability interface {
GetActions() []string
Grants(abilities []string) bool
Contains(other Capability) bool
String() string
}
// Resource defines what resource the capability applies to
type Resource interface {
GetScheme() string
GetValue() string
GetURI() string
Matches(other Resource) bool
}
// SimpleCapability implements Capability for single actions
type SimpleCapability struct {
Action string `json:"action"`
}
func (c *SimpleCapability) GetActions() []string { return []string{c.Action} }
func (c *SimpleCapability) Grants(abilities []string) bool {
return len(abilities) == 1 && c.Action == abilities[0]
}
func (c *SimpleCapability) Contains(
other Capability,
) bool {
return c.Action == other.GetActions()[0]
}
func (c *SimpleCapability) String() string { return c.Action }
// SimpleResource implements Resource for basic URI resources
type SimpleResource struct {
Scheme string `json:"scheme"`
Value string `json:"value"`
URI string `json:"uri"`
}
func (r *SimpleResource) GetScheme() string { return r.Scheme }
func (r *SimpleResource) GetValue() string { return r.Value }
func (r *SimpleResource) GetURI() string { return r.URI }
func (r *SimpleResource) Matches(other Resource) bool { return r.URI == other.GetURI() }
// UCAN constants
const (
UCANVersion = "0.9.0"
UCANVersionKey = "ucv"
PrfKey = "prf"
FctKey = "fct"
AttKey = "att"
CapKey = "cap"
)
// CreateSimpleAttenuation creates a basic attenuation
func CreateSimpleAttenuation(action, resourceURI string) Attenuation {
return Attenuation{
Capability: &SimpleCapability{Action: action},
Resource: parseResourceURI(resourceURI),
}
}
// parseResourceURI creates a Resource from URI string
func parseResourceURI(uri string) Resource {
parts := strings.SplitN(uri, "://", 2)
if len(parts) != 2 {
return &SimpleResource{
Scheme: "unknown",
Value: uri,
URI: uri,
}
}
return &SimpleResource{
Scheme: parts[0],
Value: parts[1],
URI: uri,
}
}
// getIssuerDIDFromBytes creates an issuer DID and address from public key bytes (alternative implementation)
func getIssuerDIDFromBytesAlt(pubKeyBytes []byte) (string, string, error) {
addr, err := bech32.ConvertAndEncode("idx", pubKeyBytes)
if err != nil {
return "", "", fmt.Errorf("failed to encode address: %w", err)
}
return fmt.Sprintf("did:sonr:%s", addr), addr, nil
}