206 lines
5.1 KiB
Go
206 lines
5.1 KiB
Go
package keybase
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
type UCANResult struct {
|
|
ID int64 `json:"id"`
|
|
CID string `json:"cid"`
|
|
Issuer string `json:"issuer"`
|
|
Audience string `json:"audience"`
|
|
Subject string `json:"subject,omitempty"`
|
|
Capabilities json.RawMessage `json:"capabilities"`
|
|
NotBefore string `json:"not_before,omitempty"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
IsRevoked bool `json:"is_revoked"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
type NewUCANInput struct {
|
|
CID string `json:"cid"`
|
|
Issuer string `json:"issuer"`
|
|
Audience string `json:"audience"`
|
|
Subject string `json:"subject,omitempty"`
|
|
Capabilities json.RawMessage `json:"capabilities"`
|
|
ProofChain json.RawMessage `json:"proof_chain,omitempty"`
|
|
NotBefore string `json:"not_before,omitempty"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
Nonce string `json:"nonce,omitempty"`
|
|
Facts json.RawMessage `json:"facts,omitempty"`
|
|
Signature string `json:"signature"`
|
|
RawToken string `json:"raw_token"`
|
|
}
|
|
|
|
func (am *ActionManager) CreateUCAN(ctx context.Context, params NewUCANInput) (*UCANResult, error) {
|
|
am.kb.mu.Lock()
|
|
defer am.kb.mu.Unlock()
|
|
|
|
if am.kb.didID == 0 {
|
|
return nil, fmt.Errorf("DID not initialized")
|
|
}
|
|
|
|
var subject, notBefore, nonce *string
|
|
if params.Subject != "" {
|
|
subject = ¶ms.Subject
|
|
}
|
|
if params.NotBefore != "" {
|
|
notBefore = ¶ms.NotBefore
|
|
}
|
|
if params.Nonce != "" {
|
|
nonce = ¶ms.Nonce
|
|
}
|
|
|
|
proofChain := params.ProofChain
|
|
if proofChain == nil {
|
|
proofChain = json.RawMessage(`[]`)
|
|
}
|
|
facts := params.Facts
|
|
if facts == nil {
|
|
facts = json.RawMessage(`{}`)
|
|
}
|
|
|
|
ucan, err := am.kb.queries.CreateUCAN(ctx, CreateUCANParams{
|
|
DidID: am.kb.didID,
|
|
Cid: params.CID,
|
|
Issuer: params.Issuer,
|
|
Audience: params.Audience,
|
|
Subject: subject,
|
|
Capabilities: params.Capabilities,
|
|
ProofChain: proofChain,
|
|
NotBefore: notBefore,
|
|
ExpiresAt: params.ExpiresAt,
|
|
Nonce: nonce,
|
|
Facts: facts,
|
|
Signature: params.Signature,
|
|
RawToken: params.RawToken,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create ucan: %w", err)
|
|
}
|
|
|
|
return ucanToResult(&ucan), nil
|
|
}
|
|
|
|
func (am *ActionManager) ListUCANs(ctx context.Context) ([]UCANResult, error) {
|
|
am.kb.mu.RLock()
|
|
defer am.kb.mu.RUnlock()
|
|
|
|
if am.kb.didID == 0 {
|
|
return []UCANResult{}, nil
|
|
}
|
|
|
|
ucans, err := am.kb.queries.ListUCANsByDID(ctx, am.kb.didID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list ucans: %w", err)
|
|
}
|
|
|
|
results := make([]UCANResult, len(ucans))
|
|
for i, u := range ucans {
|
|
results[i] = *ucanToResult(&u)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func (am *ActionManager) GetUCANByCID(ctx context.Context, cid string) (*UCANResult, error) {
|
|
am.kb.mu.RLock()
|
|
defer am.kb.mu.RUnlock()
|
|
|
|
ucan, err := am.kb.queries.GetUCANByCID(ctx, cid)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get ucan: %w", err)
|
|
}
|
|
|
|
return ucanToResult(&ucan), nil
|
|
}
|
|
|
|
func (am *ActionManager) ListUCANsByAudience(ctx context.Context, audience string) ([]UCANResult, error) {
|
|
am.kb.mu.RLock()
|
|
defer am.kb.mu.RUnlock()
|
|
|
|
ucans, err := am.kb.queries.ListUCANsByAudience(ctx, audience)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list ucans by audience: %w", err)
|
|
}
|
|
|
|
results := make([]UCANResult, len(ucans))
|
|
for i, u := range ucans {
|
|
results[i] = *ucanToResult(&u)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func (am *ActionManager) RevokeUCAN(ctx context.Context, cid string) error {
|
|
am.kb.mu.Lock()
|
|
defer am.kb.mu.Unlock()
|
|
|
|
return am.kb.queries.RevokeUCAN(ctx, cid)
|
|
}
|
|
|
|
func (am *ActionManager) IsUCANRevoked(ctx context.Context, cid string) (bool, error) {
|
|
am.kb.mu.RLock()
|
|
defer am.kb.mu.RUnlock()
|
|
|
|
revoked, err := am.kb.queries.IsUCANRevoked(ctx, cid)
|
|
if err != nil {
|
|
return false, fmt.Errorf("check ucan revocation: %w", err)
|
|
}
|
|
|
|
return revoked == 1, nil
|
|
}
|
|
|
|
func (am *ActionManager) CreateRevocation(ctx context.Context, ucanCID string, revokedBy string, reason string) error {
|
|
am.kb.mu.Lock()
|
|
defer am.kb.mu.Unlock()
|
|
|
|
var reasonPtr *string
|
|
if reason != "" {
|
|
reasonPtr = &reason
|
|
}
|
|
|
|
if err := am.kb.queries.RevokeUCAN(ctx, ucanCID); err != nil {
|
|
return fmt.Errorf("revoke ucan token: %w", err)
|
|
}
|
|
|
|
return am.kb.queries.CreateRevocation(ctx, CreateRevocationParams{
|
|
UcanCid: ucanCID,
|
|
RevokedBy: revokedBy,
|
|
Reason: reasonPtr,
|
|
})
|
|
}
|
|
|
|
func (am *ActionManager) CleanExpiredUCANs(ctx context.Context) error {
|
|
am.kb.mu.Lock()
|
|
defer am.kb.mu.Unlock()
|
|
|
|
return am.kb.queries.CleanExpiredUCANs(ctx)
|
|
}
|
|
|
|
func ucanToResult(u *UcanToken) *UCANResult {
|
|
subject := ""
|
|
if u.Subject != nil {
|
|
subject = *u.Subject
|
|
}
|
|
notBefore := ""
|
|
if u.NotBefore != nil {
|
|
notBefore = *u.NotBefore
|
|
}
|
|
|
|
return &UCANResult{
|
|
ID: u.ID,
|
|
CID: u.Cid,
|
|
Issuer: u.Issuer,
|
|
Audience: u.Audience,
|
|
Subject: subject,
|
|
Capabilities: u.Capabilities,
|
|
NotBefore: notBefore,
|
|
ExpiresAt: u.ExpiresAt,
|
|
IsRevoked: u.IsRevoked == 1,
|
|
CreatedAt: u.CreatedAt,
|
|
}
|
|
}
|