refactor(keybase): migrate to UCAN v1.0.0-rc.1 envelope format
This commit is contained in:
229
TODO.md
229
TODO.md
@@ -11,7 +11,7 @@ Remaining tasks from [MIGRATION.md](./MIGRATION.md) for the Nebula Key Enclave.
|
||||
| Generated Code | Complete | `internal/keybase/*.go` |
|
||||
| Basic Plugin Functions | Complete | `generate`, `load`, `exec`, `query`, `ping` |
|
||||
| Encryption | Not Started | WebAuthn PRF key derivation needed |
|
||||
| **UCAN v1.0.0-rc.1** | **CRITICAL** | Go implementation uses deprecated JWT format |
|
||||
| **UCAN v1.0.0-rc.1** | **In Progress** | Core types, builders, and policies complete. Uses `go-ucan v1.1.0` |
|
||||
| MPC Key Shares | Not Started | Key share management missing |
|
||||
| Database Serialization | Incomplete | Export dumps comments only |
|
||||
|
||||
@@ -19,114 +19,116 @@ Remaining tasks from [MIGRATION.md](./MIGRATION.md) for the Nebula Key Enclave.
|
||||
|
||||
## 1. UCAN v1.0.0-rc.1 Migration (CRITICAL PRIORITY)
|
||||
|
||||
> **Breaking Change**: Current Go implementation (`internal/crypto/ucan/`) uses deprecated JWT-based UCAN format. Must migrate to envelope format per v1.0.0-rc.1 spec.
|
||||
> **Status**: Core implementation complete using `github.com/ucan-wg/go-ucan v1.1.0`. Deprecated JWT-based files deleted. Remaining work is database integration and MPC signing.
|
||||
|
||||
### Current State (DEPRECATED - Must Replace)
|
||||
### Completed Implementation
|
||||
|
||||
The following files use the **old JWT-based format** and must be rewritten:
|
||||
The following files implement UCAN v1.0.0-rc.1 using the official go-ucan library:
|
||||
|
||||
| File | Status | Issue |
|
||||
|------|--------|-------|
|
||||
| `jwt.go` | DEPRECATED | Uses `github.com/golang-jwt/jwt/v5`, old `can`+`with` format |
|
||||
| `capability.go` | DEPRECATED | Old Attenuation/Resource/Capability model |
|
||||
| `verifier.go` | DEPRECATED | JWT parsing, old proof chain format |
|
||||
| `source.go` | DEPRECATED | JWT token creation with MPC |
|
||||
| `vault.go` | PARTIAL | VaultCapability needs Policy migration |
|
||||
| File | Status | Description |
|
||||
|------|--------|-------------|
|
||||
| `ucan.go` | ✅ Complete | Type re-exports, Sonr commands, pre-parsed constants |
|
||||
| `policy.go` | ✅ Complete | PolicyBuilder fluent API, Sonr-specific policy helpers |
|
||||
| `delegation.go` | ✅ Complete | DelegationBuilder fluent API, Sonr delegation helpers |
|
||||
| `invocation.go` | ✅ Complete | InvocationBuilder fluent API, Sonr invocation helpers |
|
||||
| `types.go` | ✅ Complete | ValidationError, Capability, ExecutionResult, Sonr types |
|
||||
|
||||
### Reference Implementation (Already Compliant)
|
||||
### Dependencies Added
|
||||
|
||||
These files are already aligned with v1.0.0-rc.1:
|
||||
- `github.com/ucan-wg/go-ucan v1.1.0` - Official UCAN library
|
||||
- `github.com/ipld/go-ipld-prime v0.21.0` - IPLD encoding
|
||||
- `github.com/MetaMask/go-did-it v1.0.0-pre1` - DID handling (indirect)
|
||||
- `github.com/ipfs/go-cid v0.5.0` - Content addressing (indirect)
|
||||
|
||||
- `src/ucan.ts` - TypeScript types with envelope format
|
||||
- `internal/codec/ucan-schemas.json` - JSON Schema definitions
|
||||
### Deleted (Deprecated JWT-based)
|
||||
|
||||
- ~~`jwt.go`~~ - Removed
|
||||
- ~~`capability.go`~~ - Removed
|
||||
- ~~`verifier.go`~~ - Removed
|
||||
- ~~`source.go`~~ - Removed
|
||||
- ~~`internal/crypto/mpc/spec/`~~ - Entire directory removed
|
||||
|
||||
### 1.1 Core Data Structures
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/types.go` - v1.0.0-rc.1 types
|
||||
- [ ] `DelegationPayload` struct (iss, aud, sub, cmd, pol, nonce, meta, nbf, exp)
|
||||
- [ ] `InvocationPayload` struct (iss, sub, aud, cmd, args, prf, meta, nonce, exp, iat, cause)
|
||||
- [ ] `Delegation` type as `[Signature, DelegationSigPayload]` tuple
|
||||
- [ ] `Invocation` type as `[Signature, InvocationSigPayload]` tuple
|
||||
- [ ] `Task` struct (sub, cmd, args, nonce)
|
||||
- [ ] `ReceiptPayload` struct (iss, ran, out, fx, meta, iat)
|
||||
- [ ] `RevocationPayload` struct
|
||||
- [x] Create `internal/crypto/ucan/types.go` - v1.0.0-rc.1 types
|
||||
- [x] Re-export `Delegation` and `Invocation` from go-ucan
|
||||
- [x] `Task` struct (sub, cmd, args, nonce)
|
||||
- [x] `ReceiptPayload` struct (iss, ran, out, fx, meta, iat)
|
||||
- [x] `RevocationPayload` struct
|
||||
- [x] `ValidationError` with error codes matching TypeScript
|
||||
- [x] `Capability` struct (sub, cmd, pol)
|
||||
- [x] `ExecutionResult[T, E]` generic type
|
||||
- [x] Sonr-specific types: `VaultCapability`, `DIDCapability`, `DWNCapability`
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/policy.go` - Policy Language
|
||||
- [ ] `PolicyStatement` union type
|
||||
- [ ] `EqualityStatement` - `["==", selector, value]` / `["!=", selector, value]`
|
||||
- [ ] `InequalityStatement` - `[">", selector, number]` etc.
|
||||
- [ ] `LikeStatement` - `["like", selector, glob]`
|
||||
- [ ] `NotStatement` - `["not", statement]`
|
||||
- [ ] `AndStatement` / `OrStatement` - logical connectives
|
||||
- [ ] `AllStatement` / `AnyStatement` - quantifiers
|
||||
- [ ] `Selector` parser (jq-inspired: `.foo`, `.bar[0]`, `.items[-1]`)
|
||||
- [ ] `GlobPattern` matcher
|
||||
- [x] Create `internal/crypto/ucan/policy.go` - Policy Language
|
||||
- [x] `PolicyBuilder` fluent API with all operators
|
||||
- [x] `Equal`, `NotEqual` - equality statements
|
||||
- [x] `GreaterThan`, `LessThan`, etc. - inequality statements
|
||||
- [x] `Like` - glob pattern matching
|
||||
- [x] `Not`, `And`, `Or` - logical connectives
|
||||
- [x] `All`, `Any` - quantifiers
|
||||
- [x] Sonr helpers: `VaultPolicy`, `DIDPolicy`, `ChainPolicy`, `AccountPolicy`
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/command.go` - Command types
|
||||
- [ ] `Command` type with validation (must start with `/`, lowercase, no trailing slash)
|
||||
- [ ] Standard commands: `/crud/*`, `/msg/*`, `/ucan/revoke`, `/wasm/run`
|
||||
- [ ] Custom Sonr commands: `/vault/*`, `/did/*`, `/dwn/*`
|
||||
- [x] Create `internal/crypto/ucan/ucan.go` - Command types
|
||||
- [x] `Command` type re-exported from go-ucan
|
||||
- [x] Sonr commands: `/vault/*`, `/did/*`, `/dwn/*`, `/ucan/revoke`
|
||||
- [x] Pre-parsed command constants: `VaultRead`, `VaultWrite`, `DIDUpdate`, etc.
|
||||
- [x] `CommandSubsumes()` helper using go-ucan's `Covers()` method
|
||||
|
||||
### 1.2 Envelope Format & Encoding
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/envelope.go` - Envelope handling
|
||||
- [ ] `UCANEnvelope[P]` generic type as `[Signature, {h: VarsigHeader} & P]`
|
||||
- [ ] Encode envelope to CBOR (requires `github.com/fxamacker/cbor/v2`)
|
||||
- [ ] Decode envelope from CBOR
|
||||
- [ ] DAG-JSON encoding for interop
|
||||
- [ ] CID computation (DAG-CBOR codec, SHA-256 multihash, base58btc)
|
||||
- [x] Envelope handling via go-ucan library
|
||||
- [x] `ToSealed()` method produces DAG-CBOR bytes + CID
|
||||
- [x] `ToDagCbor()`, `ToDagJson()` encoding methods
|
||||
- [x] CID computation handled by go-ucan
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/varsig.go` - Varsig v1 headers
|
||||
- [ ] Varsig header encoding/decoding
|
||||
- [ ] Algorithm metadata extraction
|
||||
- [ ] Support Ed25519, P-256, secp256k1
|
||||
- [x] Varsig support via go-ucan library
|
||||
- [x] Ed25519, P-256, secp256k1 via `go-did-it/crypto`
|
||||
|
||||
### 1.3 Delegation Operations
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/delegation.go` - Delegation creation/validation
|
||||
- [ ] `NewDelegation(issuer, audience, subject, cmd, policy, exp, meta)` builder
|
||||
- [ ] Sign delegation with issuer private key
|
||||
- [ ] Validate delegation signature
|
||||
- [ ] Validate delegation payload (temporal, structural)
|
||||
- [ ] Extract `Capability` from delegation (sub + cmd + pol)
|
||||
- [x] Create `internal/crypto/ucan/delegation.go` - Delegation creation/validation
|
||||
- [x] `DelegationBuilder` fluent API
|
||||
- [x] `NewDelegation`, `NewRootDelegation`, `NewPowerlineDelegation` re-exports
|
||||
- [x] `BuildSealed(privKey)` for signing
|
||||
- [x] Sonr helpers: `NewVaultDelegation`, `NewDIDDelegation`, `NewDWNDelegation`
|
||||
- [x] Temporal options: `ExpiresAt`, `ExpiresIn`, `NotBefore`, `NotBeforeIn`
|
||||
|
||||
### 1.4 Invocation Operations
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/invocation.go` - Invocation creation/validation
|
||||
- [ ] `NewInvocation(issuer, subject, cmd, args, proofs, exp)` builder
|
||||
- [ ] Sign invocation with invoker private key
|
||||
- [ ] Validate invocation signature
|
||||
- [ ] Validate proof chain (CID references to delegations)
|
||||
- [ ] Evaluate policies against invocation args
|
||||
- [x] Create `internal/crypto/ucan/invocation.go` - Invocation creation/validation
|
||||
- [x] `InvocationBuilder` fluent API
|
||||
- [x] `NewInvocation` re-export
|
||||
- [x] `BuildSealed(privKey)` for signing
|
||||
- [x] Proof chain management: `Proof()`, `Proofs()`
|
||||
- [x] Sonr helpers: `VaultReadInvocation`, `VaultSignInvocation`, `DIDUpdateInvocation`
|
||||
|
||||
### 1.5 Policy Evaluation Engine
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/eval.go` - Policy evaluation
|
||||
- [ ] `EvaluatePolicy(policy Policy, args Arguments) (bool, error)`
|
||||
- [ ] Selector resolution against IPLD data
|
||||
- [ ] Equality comparison (deep IPLD equality)
|
||||
- [ ] Numeric comparisons
|
||||
- [ ] Glob pattern matching for `like` operator
|
||||
- [ ] Logical connectives (`and`, `or`, `not`)
|
||||
- [ ] Quantifiers (`all`, `any`) over collections
|
||||
> Note: go-ucan provides `ExecutionAllowed()` on invocations which validates proofs and evaluates policies.
|
||||
|
||||
- [x] Policy evaluation via go-ucan's `invocation.ExecutionAllowed(loader)`
|
||||
- [ ] Create `internal/crypto/ucan/eval.go` - Additional evaluation helpers (if needed)
|
||||
- [ ] Custom selector resolution for Sonr-specific args
|
||||
- [ ] Caching layer for repeated evaluations
|
||||
|
||||
### 1.6 Proof Chain Validation
|
||||
|
||||
- [ ] Create `internal/crypto/ucan/chain.go` - Chain validation
|
||||
- [ ] Resolve CID to Delegation (requires delegation store)
|
||||
- [ ] Validate chain continuity (child.iss == parent.aud)
|
||||
- [ ] Validate capability attenuation (child.cmd subsumes parent.cmd)
|
||||
- [ ] Validate policy attenuation (child.pol more restrictive than parent.pol)
|
||||
- [ ] Validate temporal bounds (child.exp <= parent.exp)
|
||||
- [ ] Check revocation status for all chain members
|
||||
> Note: go-ucan handles chain validation internally via `ExecutionAllowed()`.
|
||||
|
||||
- [x] Chain validation via go-ucan library
|
||||
- [ ] Create `internal/crypto/ucan/store.go` - Delegation store
|
||||
- [ ] Implement `delegation.Loader` interface
|
||||
- [ ] `GetDelegation(cid.Cid) (*delegation.Token, error)`
|
||||
- [ ] Cache loaded delegations for performance
|
||||
|
||||
### 1.7 Revocation
|
||||
|
||||
- [x] `RevocationInvocation()` helper in `invocation.go`
|
||||
- [ ] Create `internal/crypto/ucan/revocation.go` - Revocation handling
|
||||
- [ ] `NewRevocation(revoker, delegation_cid)` builder
|
||||
- [ ] Validate revoker is in delegation's issuer chain
|
||||
- [ ] Store revocation in database
|
||||
- [ ] Query revocation status by CID
|
||||
- [ ] Revocation store implementation
|
||||
- [ ] `IsRevoked(cid.Cid) (bool, error)` query
|
||||
- [ ] Integration with chain validation
|
||||
|
||||
### 1.8 Database Integration
|
||||
|
||||
@@ -141,20 +143,18 @@ These files are already aligned with v1.0.0-rc.1:
|
||||
- [ ] `InsertInvocation`, `GetInvocationByCID`
|
||||
- [ ] `InsertRevocation`, `IsRevoked`, `GetRevocationsByDelegation`
|
||||
|
||||
### 1.9 Migration from Old Format
|
||||
### 1.9 MPC Signing Integration
|
||||
|
||||
- [ ] Create migration script for existing UCAN data (if any)
|
||||
- [ ] Remove deprecated files after migration complete:
|
||||
- [ ] `jwt.go` - Remove entirely
|
||||
- [ ] `capability.go` - Replace with policy-based capabilities
|
||||
- [ ] `verifier.go` - Replace with envelope-based verification
|
||||
- [ ] `source.go` - Replace with envelope-based token creation
|
||||
- [ ] Create `internal/crypto/ucan/signer.go` - MPC key integration
|
||||
- [ ] Implement `crypto.PrivateKeySigningBytes` interface for MPC
|
||||
- [ ] Sign delegations with MPC key shares
|
||||
- [ ] Sign invocations with MPC key shares
|
||||
|
||||
### 1.10 Testing
|
||||
|
||||
- [ ] Unit tests for policy evaluation
|
||||
- [ ] Unit tests for envelope encoding/decoding
|
||||
- [ ] Unit tests for chain validation
|
||||
- [ ] Unit tests for builders (DelegationBuilder, InvocationBuilder)
|
||||
- [ ] Unit tests for policy helpers
|
||||
- [ ] Unit tests for Sonr-specific invocations
|
||||
- [ ] Interoperability tests against TypeScript implementation
|
||||
- [ ] Test vectors from UCAN spec
|
||||
|
||||
@@ -478,23 +478,26 @@ These files are already aligned with v1.0.0-rc.1:
|
||||
|
||||
## Priority Order
|
||||
|
||||
1. **CRITICAL (Spec Compliance)**
|
||||
- UCAN v1.0.0-rc.1 Migration (Section 1)
|
||||
- Core data structures (1.1)
|
||||
- Envelope format (1.2)
|
||||
- Delegation operations (1.3)
|
||||
- Policy evaluation (1.5)
|
||||
1. **CRITICAL (Spec Compliance)** - ✅ Core Complete
|
||||
- ~~UCAN v1.0.0-rc.1 Migration (Section 1)~~ ✅ Core types, builders, policies done
|
||||
- ~~Core data structures (1.1)~~ ✅ Using go-ucan v1.1.0
|
||||
- ~~Envelope format (1.2)~~ ✅ Handled by go-ucan
|
||||
- ~~Delegation operations (1.3)~~ ✅ DelegationBuilder complete
|
||||
- ~~Invocation operations (1.4)~~ ✅ InvocationBuilder complete
|
||||
- Database integration (1.8) - Next priority
|
||||
- MPC signing integration (1.9) - Next priority
|
||||
|
||||
2. **High Priority (Core Functionality)**
|
||||
- Database Serialization (3.1, 3.2)
|
||||
- Credential Creation (6.2, 4.7)
|
||||
- Key Share Actions (4.1)
|
||||
- Account Actions (4.6)
|
||||
- UCAN Database Integration (1.8)
|
||||
|
||||
3. **Medium Priority (Authorization)**
|
||||
- Invocation operations (1.4)
|
||||
- Proof chain validation (1.6)
|
||||
- Revocation (1.7)
|
||||
- Delegation store (1.6)
|
||||
- Revocation store (1.7)
|
||||
- MPC Signing (1.9)
|
||||
- Encryption Strategy (2.1, 2.2)
|
||||
|
||||
4. **Lower Priority (Enhancement)**
|
||||
@@ -506,13 +509,39 @@ These files are already aligned with v1.0.0-rc.1:
|
||||
|
||||
---
|
||||
|
||||
## Completed Items
|
||||
|
||||
### UCAN v1.0.0-rc.1 Core (January 2025)
|
||||
|
||||
The following was completed using `github.com/ucan-wg/go-ucan v1.1.0`:
|
||||
|
||||
- ✅ Type re-exports from go-ucan (Delegation, Invocation, Command, Policy)
|
||||
- ✅ Sonr command constants (/vault/*, /did/*, /dwn/*)
|
||||
- ✅ DelegationBuilder fluent API with Sonr-specific helpers
|
||||
- ✅ InvocationBuilder fluent API with Sonr-specific helpers
|
||||
- ✅ PolicyBuilder fluent API with all operators
|
||||
- ✅ Sonr policy helpers (VaultPolicy, DIDPolicy, ChainPolicy)
|
||||
- ✅ ValidationError types matching TypeScript definitions
|
||||
- ✅ Capability, ExecutionResult, and related types
|
||||
|
||||
### Deleted (Deprecated JWT-based)
|
||||
|
||||
- ✅ Deleted `jwt.go` - Old JWT token handling
|
||||
- ✅ Deleted `capability.go` - Old Attenuation/Resource/Capability model
|
||||
- ✅ Deleted `verifier.go` - Old JWT verification
|
||||
- ✅ Deleted `source.go` - Old JWT token creation
|
||||
- ✅ Deleted `internal/crypto/mpc/spec/` - Old MPC JWT integration
|
||||
- ✅ Removed `github.com/golang-jwt/jwt/v5` dependency
|
||||
|
||||
---
|
||||
|
||||
## Deprecated Items (Removed)
|
||||
|
||||
The following items from the previous TODO have been removed as they reference the **deprecated JWT-based UCAN format**:
|
||||
|
||||
- ~~Section 4.1 "Token Validation" - JWT parsing~~ -> Replaced by envelope validation (1.2, 1.3)
|
||||
- ~~Section 4.2 "Capability Verification" - `can`/`with` format~~ -> Replaced by policy evaluation (1.5)
|
||||
- ~~Section 4.3 "Proof Chain Validation" - JWT proof strings~~ -> Replaced by CID-based chain (1.6)
|
||||
- ~~Section 4.1 "Token Validation" - JWT parsing~~ -> Replaced by go-ucan validation
|
||||
- ~~Section 4.2 "Capability Verification" - `can`/`with` format~~ -> Replaced by policy evaluation
|
||||
- ~~Section 4.3 "Proof Chain Validation" - JWT proof strings~~ -> Replaced by CID-based chain
|
||||
- ~~Section 3.2 "UCAN Token Actions" - Old format~~ -> Replaced by v1.0.0-rc.1 actions (4.2)
|
||||
- ~~Section 3.3 "Delegation Actions" - Old delegation model~~ -> Merged into Section 1 and 4.2
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ func (am *ActionManager) ListAccounts(ctx context.Context) ([]AccountResult, err
|
||||
AddressIndex: row.AddressIndex,
|
||||
Label: label,
|
||||
IsDefault: row.IsDefault == 1,
|
||||
PublicKey: row.PublicKey,
|
||||
PublicKey: row.SharePublicKey,
|
||||
Curve: row.Curve,
|
||||
CreatedAt: row.CreatedAt,
|
||||
}
|
||||
@@ -481,7 +481,7 @@ func (am *ActionManager) ResolveDID(ctx context.Context, did string) (*DIDDocume
|
||||
AddressIndex: row.AddressIndex,
|
||||
Label: label,
|
||||
IsDefault: row.IsDefault == 1,
|
||||
PublicKey: row.PublicKey,
|
||||
PublicKey: row.SharePublicKey,
|
||||
Curve: row.Curve,
|
||||
CreatedAt: row.CreatedAt,
|
||||
}
|
||||
|
||||
@@ -2,37 +2,46 @@ package keybase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// DELEGATION ACTIONS (UCAN v1.0.0-rc.1)
|
||||
// =============================================================================
|
||||
|
||||
// DelegationResult represents a delegation in API responses.
|
||||
type DelegationResult struct {
|
||||
ID int64 `json:"id"`
|
||||
UcanID int64 `json:"ucan_id"`
|
||||
Delegator string `json:"delegator"`
|
||||
Delegate string `json:"delegate"`
|
||||
Resource string `json:"resource"`
|
||||
Action string `json:"action"`
|
||||
Caveats json.RawMessage `json:"caveats"`
|
||||
Depth int64 `json:"depth"`
|
||||
Status string `json:"status"`
|
||||
CID string `json:"cid"`
|
||||
Issuer string `json:"iss"`
|
||||
Audience string `json:"aud"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Command string `json:"cmd"`
|
||||
Policy string `json:"pol,omitempty"`
|
||||
NotBefore string `json:"nbf,omitempty"`
|
||||
Expiration string `json:"exp,omitempty"`
|
||||
IsRoot bool `json:"is_root"`
|
||||
IsPowerline bool `json:"is_powerline"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
ExpiresAt string `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
type NewDelegationInput struct {
|
||||
UcanID int64 `json:"ucan_id"`
|
||||
Delegator string `json:"delegator"`
|
||||
Delegate string `json:"delegate"`
|
||||
Resource string `json:"resource"`
|
||||
Action string `json:"action"`
|
||||
Caveats json.RawMessage `json:"caveats,omitempty"`
|
||||
ParentID int64 `json:"parent_id,omitempty"`
|
||||
Depth int64 `json:"depth"`
|
||||
ExpiresAt string `json:"expires_at,omitempty"`
|
||||
// StoreDelegationParams contains parameters for storing a delegation.
|
||||
type StoreDelegationParams struct {
|
||||
CID string `json:"cid"`
|
||||
Envelope []byte `json:"envelope"`
|
||||
Issuer string `json:"iss"`
|
||||
Audience string `json:"aud"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Command string `json:"cmd"`
|
||||
Policy string `json:"pol,omitempty"`
|
||||
NotBefore string `json:"nbf,omitempty"`
|
||||
Expiration string `json:"exp,omitempty"`
|
||||
IsRoot bool `json:"is_root"`
|
||||
IsPowerline bool `json:"is_powerline"`
|
||||
}
|
||||
|
||||
func (am *ActionManager) CreateDelegation(ctx context.Context, params NewDelegationInput) (*DelegationResult, error) {
|
||||
// StoreDelegation stores a new UCAN delegation envelope.
|
||||
func (am *ActionManager) StoreDelegation(ctx context.Context, params StoreDelegationParams) (*DelegationResult, error) {
|
||||
am.kb.mu.Lock()
|
||||
defer am.kb.mu.Unlock()
|
||||
|
||||
@@ -40,75 +49,78 @@ func (am *ActionManager) CreateDelegation(ctx context.Context, params NewDelegat
|
||||
return nil, fmt.Errorf("DID not initialized")
|
||||
}
|
||||
|
||||
var parentID *int64
|
||||
if params.ParentID != 0 {
|
||||
parentID = ¶ms.ParentID
|
||||
var sub, pol, nbf, exp *string
|
||||
if params.Subject != "" {
|
||||
sub = ¶ms.Subject
|
||||
}
|
||||
if params.Policy != "" {
|
||||
pol = ¶ms.Policy
|
||||
}
|
||||
if params.NotBefore != "" {
|
||||
nbf = ¶ms.NotBefore
|
||||
}
|
||||
if params.Expiration != "" {
|
||||
exp = ¶ms.Expiration
|
||||
}
|
||||
|
||||
var expiresAt *string
|
||||
if params.ExpiresAt != "" {
|
||||
expiresAt = ¶ms.ExpiresAt
|
||||
isRoot := int64(0)
|
||||
if params.IsRoot {
|
||||
isRoot = 1
|
||||
}
|
||||
|
||||
caveats := params.Caveats
|
||||
if caveats == nil {
|
||||
caveats = json.RawMessage(`{}`)
|
||||
isPowerline := int64(0)
|
||||
if params.IsPowerline {
|
||||
isPowerline = 1
|
||||
}
|
||||
|
||||
d, err := am.kb.queries.CreateDelegation(ctx, CreateDelegationParams{
|
||||
DidID: am.kb.didID,
|
||||
UcanID: params.UcanID,
|
||||
Delegator: params.Delegator,
|
||||
Delegate: params.Delegate,
|
||||
Resource: params.Resource,
|
||||
Action: params.Action,
|
||||
Caveats: caveats,
|
||||
ParentID: parentID,
|
||||
Depth: params.Depth,
|
||||
ExpiresAt: expiresAt,
|
||||
Cid: params.CID,
|
||||
Envelope: params.Envelope,
|
||||
Iss: params.Issuer,
|
||||
Aud: params.Audience,
|
||||
Sub: sub,
|
||||
Cmd: params.Command,
|
||||
Pol: pol,
|
||||
Nbf: nbf,
|
||||
Exp: exp,
|
||||
IsRoot: isRoot,
|
||||
IsPowerline: isPowerline,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create delegation: %w", err)
|
||||
}
|
||||
|
||||
return delegationToResult(&d), nil
|
||||
return delegationToResult(d), nil
|
||||
}
|
||||
|
||||
func (am *ActionManager) ListDelegationsByDelegator(ctx context.Context, delegator string) ([]DelegationResult, error) {
|
||||
// GetDelegationByCID retrieves a delegation by its CID.
|
||||
func (am *ActionManager) GetDelegationByCID(ctx context.Context, cid string) (*DelegationResult, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
delegations, err := am.kb.queries.ListDelegationsByDelegator(ctx, delegator)
|
||||
d, err := am.kb.queries.GetDelegationByCID(ctx, cid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list delegations by delegator: %w", err)
|
||||
return nil, fmt.Errorf("get delegation: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(&d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
return delegationToResult(d), nil
|
||||
}
|
||||
|
||||
func (am *ActionManager) ListDelegationsByDelegate(ctx context.Context, delegate string) ([]DelegationResult, error) {
|
||||
// GetDelegationEnvelope retrieves the raw CBOR envelope for a delegation.
|
||||
func (am *ActionManager) GetDelegationEnvelope(ctx context.Context, cid string) ([]byte, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
delegations, err := am.kb.queries.ListDelegationsByDelegate(ctx, delegate)
|
||||
envelope, err := am.kb.queries.GetDelegationEnvelopeByCID(ctx, cid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list delegations by delegate: %w", err)
|
||||
return nil, fmt.Errorf("get delegation envelope: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(&d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
return envelope, nil
|
||||
}
|
||||
|
||||
func (am *ActionManager) ListDelegationsForResource(ctx context.Context, resource string) ([]DelegationResult, error) {
|
||||
// ListDelegations returns all active delegations for the current DID.
|
||||
func (am *ActionManager) ListDelegations(ctx context.Context) ([]DelegationResult, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
@@ -116,66 +128,191 @@ func (am *ActionManager) ListDelegationsForResource(ctx context.Context, resourc
|
||||
return []DelegationResult{}, nil
|
||||
}
|
||||
|
||||
delegations, err := am.kb.queries.ListDelegationsForResource(ctx, ListDelegationsForResourceParams{
|
||||
DidID: am.kb.didID,
|
||||
Resource: resource,
|
||||
})
|
||||
delegations, err := am.kb.queries.ListDelegationsByDID(ctx, am.kb.didID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list delegations for resource: %w", err)
|
||||
return nil, fmt.Errorf("list delegations: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(&d)
|
||||
results[i] = *delegationToResult(d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (am *ActionManager) GetDelegationChain(ctx context.Context, delegationID int64) ([]DelegationResult, error) {
|
||||
// ListDelegationsByIssuer returns delegations issued by a specific DID.
|
||||
func (am *ActionManager) ListDelegationsByIssuer(ctx context.Context, issuer string) ([]DelegationResult, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
delegations, err := am.kb.queries.GetDelegationChain(ctx, GetDelegationChainParams{
|
||||
ID: delegationID,
|
||||
ParentID: &delegationID,
|
||||
})
|
||||
delegations, err := am.kb.queries.ListDelegationsByIssuer(ctx, issuer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get delegation chain: %w", err)
|
||||
return nil, fmt.Errorf("list delegations by issuer: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(&d)
|
||||
results[i] = *delegationToResult(d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (am *ActionManager) RevokeDelegation(ctx context.Context, delegationID int64) error {
|
||||
// ListDelegationsByAudience returns delegations granted to a specific DID.
|
||||
func (am *ActionManager) ListDelegationsByAudience(ctx context.Context, audience string) ([]DelegationResult, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
delegations, err := am.kb.queries.ListDelegationsByAudience(ctx, audience)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list delegations by audience: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// ListDelegationsForCommand returns delegations that grant a specific command.
|
||||
func (am *ActionManager) ListDelegationsForCommand(ctx context.Context, cmd string) ([]DelegationResult, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
if am.kb.didID == 0 {
|
||||
return []DelegationResult{}, nil
|
||||
}
|
||||
|
||||
delegations, err := am.kb.queries.ListDelegationsForCommand(ctx, ListDelegationsForCommandParams{
|
||||
DidID: am.kb.didID,
|
||||
Cmd: cmd,
|
||||
Cmd_2: cmd,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list delegations for command: %w", err)
|
||||
}
|
||||
|
||||
results := make([]DelegationResult, len(delegations))
|
||||
for i, d := range delegations {
|
||||
results[i] = *delegationToResult(d)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// IsDelegationRevoked checks if a delegation has been revoked.
|
||||
func (am *ActionManager) IsDelegationRevoked(ctx context.Context, cid string) (bool, error) {
|
||||
am.kb.mu.RLock()
|
||||
defer am.kb.mu.RUnlock()
|
||||
|
||||
revoked, err := am.kb.queries.IsDelegationRevoked(ctx, cid)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("check revocation: %w", err)
|
||||
}
|
||||
|
||||
return revoked == 1, nil
|
||||
}
|
||||
|
||||
// RevokeDelegationParams contains parameters for revoking a delegation.
|
||||
type RevokeDelegationParams struct {
|
||||
DelegationCID string `json:"delegation_cid"`
|
||||
RevokedBy string `json:"revoked_by"`
|
||||
InvocationCID string `json:"invocation_cid,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// RevokeDelegation revokes a delegation by creating a revocation record.
|
||||
func (am *ActionManager) RevokeDelegation(ctx context.Context, params RevokeDelegationParams) error {
|
||||
am.kb.mu.Lock()
|
||||
defer am.kb.mu.Unlock()
|
||||
|
||||
return am.kb.queries.RevokeDelegation(ctx, delegationID)
|
||||
var invocationCID, reason *string
|
||||
if params.InvocationCID != "" {
|
||||
invocationCID = ¶ms.InvocationCID
|
||||
}
|
||||
if params.Reason != "" {
|
||||
reason = ¶ms.Reason
|
||||
}
|
||||
|
||||
err := am.kb.queries.CreateRevocation(ctx, CreateRevocationParams{
|
||||
DelegationCid: params.DelegationCID,
|
||||
RevokedBy: params.RevokedBy,
|
||||
InvocationCid: invocationCID,
|
||||
Reason: reason,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("create revocation: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func delegationToResult(d *Delegation) *DelegationResult {
|
||||
expiresAt := ""
|
||||
if d.ExpiresAt != nil {
|
||||
expiresAt = *d.ExpiresAt
|
||||
// DeleteDelegation deletes a delegation from the database.
|
||||
func (am *ActionManager) DeleteDelegation(ctx context.Context, cid string) error {
|
||||
am.kb.mu.Lock()
|
||||
defer am.kb.mu.Unlock()
|
||||
|
||||
if am.kb.didID == 0 {
|
||||
return fmt.Errorf("DID not initialized")
|
||||
}
|
||||
|
||||
err := am.kb.queries.DeleteDelegation(ctx, DeleteDelegationParams{
|
||||
Cid: cid,
|
||||
DidID: am.kb.didID,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete delegation: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanExpiredDelegations removes delegations expired more than 30 days ago.
|
||||
func (am *ActionManager) CleanExpiredDelegations(ctx context.Context) error {
|
||||
am.kb.mu.Lock()
|
||||
defer am.kb.mu.Unlock()
|
||||
|
||||
if err := am.kb.queries.CleanExpiredDelegations(ctx); err != nil {
|
||||
return fmt.Errorf("clean expired delegations: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// delegationToResult converts a UcanDelegation to DelegationResult.
|
||||
func delegationToResult(d UcanDelegation) *DelegationResult {
|
||||
subject := ""
|
||||
if d.Sub != nil {
|
||||
subject = *d.Sub
|
||||
}
|
||||
policy := ""
|
||||
if d.Pol != nil {
|
||||
policy = *d.Pol
|
||||
}
|
||||
notBefore := ""
|
||||
if d.Nbf != nil {
|
||||
notBefore = *d.Nbf
|
||||
}
|
||||
expiration := ""
|
||||
if d.Exp != nil {
|
||||
expiration = *d.Exp
|
||||
}
|
||||
|
||||
return &DelegationResult{
|
||||
ID: d.ID,
|
||||
UcanID: d.UcanID,
|
||||
Delegator: d.Delegator,
|
||||
Delegate: d.Delegate,
|
||||
Resource: d.Resource,
|
||||
Action: d.Action,
|
||||
Caveats: d.Caveats,
|
||||
Depth: d.Depth,
|
||||
Status: d.Status,
|
||||
CID: d.Cid,
|
||||
Issuer: d.Iss,
|
||||
Audience: d.Aud,
|
||||
Subject: subject,
|
||||
Command: d.Cmd,
|
||||
Policy: policy,
|
||||
NotBefore: notBefore,
|
||||
Expiration: expiration,
|
||||
IsRoot: d.IsRoot == 1,
|
||||
IsPowerline: d.IsPowerline == 1,
|
||||
CreatedAt: d.CreatedAt,
|
||||
ExpiresAt: expiresAt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
type NewGrantInput struct {
|
||||
ServiceID int64 `json:"service_id"`
|
||||
UcanID int64 `json:"ucan_id,omitempty"`
|
||||
DelegationCID string `json:"delegation_cid,omitempty"`
|
||||
Scopes json.RawMessage `json:"scopes"`
|
||||
Accounts json.RawMessage `json:"accounts"`
|
||||
ExpiresAt string `json:"expires_at,omitempty"`
|
||||
@@ -22,9 +22,9 @@ func (am *ActionManager) CreateGrant(ctx context.Context, params NewGrantInput)
|
||||
return nil, fmt.Errorf("DID not initialized")
|
||||
}
|
||||
|
||||
var ucanID *int64
|
||||
if params.UcanID != 0 {
|
||||
ucanID = ¶ms.UcanID
|
||||
var delegationCID *string
|
||||
if params.DelegationCID != "" {
|
||||
delegationCID = ¶ms.DelegationCID
|
||||
}
|
||||
|
||||
var expiresAt *string
|
||||
@@ -44,7 +44,7 @@ func (am *ActionManager) CreateGrant(ctx context.Context, params NewGrantInput)
|
||||
g, err := am.kb.queries.CreateGrant(ctx, CreateGrantParams{
|
||||
DidID: am.kb.didID,
|
||||
ServiceID: params.ServiceID,
|
||||
UcanID: ucanID,
|
||||
DelegationCid: delegationCID,
|
||||
Scopes: scopes,
|
||||
Accounts: accounts,
|
||||
ExpiresAt: expiresAt,
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...any) (sql.Result, error)
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...any) *sql.Row
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
|
||||
@@ -40,22 +40,6 @@ type Credential struct {
|
||||
LastUsed string `json:"last_used"`
|
||||
}
|
||||
|
||||
type Delegation struct {
|
||||
ID int64 `json:"id"`
|
||||
DidID int64 `json:"did_id"`
|
||||
UcanID int64 `json:"ucan_id"`
|
||||
Delegator string `json:"delegator"`
|
||||
Delegate string `json:"delegate"`
|
||||
Resource string `json:"resource"`
|
||||
Action string `json:"action"`
|
||||
Caveats json.RawMessage `json:"caveats"`
|
||||
ParentID *int64 `json:"parent_id"`
|
||||
Depth int64 `json:"depth"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
ExpiresAt *string `json:"expires_at"`
|
||||
}
|
||||
|
||||
type DidDocument struct {
|
||||
ID int64 `json:"id"`
|
||||
Did string `json:"did"`
|
||||
@@ -71,7 +55,7 @@ type Grant struct {
|
||||
ID int64 `json:"id"`
|
||||
DidID int64 `json:"did_id"`
|
||||
ServiceID int64 `json:"service_id"`
|
||||
UcanID *int64 `json:"ucan_id"`
|
||||
DelegationCid *string `json:"delegation_cid"`
|
||||
Scopes json.RawMessage `json:"scopes"`
|
||||
Accounts json.RawMessage `json:"accounts"`
|
||||
Status string `json:"status"`
|
||||
@@ -131,33 +115,49 @@ type SyncCheckpoint struct {
|
||||
LastSynced string `json:"last_synced"`
|
||||
}
|
||||
|
||||
type UcanRevocation struct {
|
||||
ID int64 `json:"id"`
|
||||
UcanCid string `json:"ucan_cid"`
|
||||
RevokedBy string `json:"revoked_by"`
|
||||
Reason *string `json:"reason"`
|
||||
RevokedAt string `json:"revoked_at"`
|
||||
}
|
||||
|
||||
type UcanToken struct {
|
||||
type UcanDelegation struct {
|
||||
ID int64 `json:"id"`
|
||||
DidID int64 `json:"did_id"`
|
||||
Cid string `json:"cid"`
|
||||
Issuer string `json:"issuer"`
|
||||
Audience string `json:"audience"`
|
||||
Subject *string `json:"subject"`
|
||||
Capabilities json.RawMessage `json:"capabilities"`
|
||||
ProofChain json.RawMessage `json:"proof_chain"`
|
||||
NotBefore *string `json:"not_before"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Nonce *string `json:"nonce"`
|
||||
Facts json.RawMessage `json:"facts"`
|
||||
Signature string `json:"signature"`
|
||||
RawToken string `json:"raw_token"`
|
||||
IsRevoked int64 `json:"is_revoked"`
|
||||
Envelope []byte `json:"envelope"`
|
||||
Iss string `json:"iss"`
|
||||
Aud string `json:"aud"`
|
||||
Sub *string `json:"sub"`
|
||||
Cmd string `json:"cmd"`
|
||||
Pol *string `json:"pol"`
|
||||
Nbf *string `json:"nbf"`
|
||||
Exp *string `json:"exp"`
|
||||
IsRoot int64 `json:"is_root"`
|
||||
IsPowerline int64 `json:"is_powerline"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type UcanInvocation struct {
|
||||
ID int64 `json:"id"`
|
||||
DidID int64 `json:"did_id"`
|
||||
Cid string `json:"cid"`
|
||||
Envelope []byte `json:"envelope"`
|
||||
Iss string `json:"iss"`
|
||||
Sub string `json:"sub"`
|
||||
Aud *string `json:"aud"`
|
||||
Cmd string `json:"cmd"`
|
||||
Prf string `json:"prf"`
|
||||
Exp *string `json:"exp"`
|
||||
Iat *string `json:"iat"`
|
||||
ExecutedAt *string `json:"executed_at"`
|
||||
ResultCid *string `json:"result_cid"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type UcanRevocation struct {
|
||||
ID int64 `json:"id"`
|
||||
DelegationCid string `json:"delegation_cid"`
|
||||
RevokedBy string `json:"revoked_by"`
|
||||
InvocationCid *string `json:"invocation_cid"`
|
||||
Reason *string `json:"reason"`
|
||||
RevokedAt string `json:"revoked_at"`
|
||||
}
|
||||
|
||||
type VerificationMethod struct {
|
||||
ID int64 `json:"id"`
|
||||
DidID int64 `json:"did_id"`
|
||||
|
||||
@@ -10,22 +10,27 @@ import (
|
||||
|
||||
type Querier interface {
|
||||
ArchiveKeyShare(ctx context.Context, id int64) error
|
||||
CleanExpiredUCANs(ctx context.Context) error
|
||||
CleanExpiredDelegations(ctx context.Context) error
|
||||
CleanOldInvocations(ctx context.Context) error
|
||||
CountActiveGrants(ctx context.Context, didID int64) (int64, error)
|
||||
CountCredentialsByDID(ctx context.Context, didID int64) (int64, error)
|
||||
CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error)
|
||||
CreateCredential(ctx context.Context, arg CreateCredentialParams) (Credential, error)
|
||||
CreateDID(ctx context.Context, arg CreateDIDParams) (DidDocument, error)
|
||||
CreateDelegation(ctx context.Context, arg CreateDelegationParams) (Delegation, error)
|
||||
CreateDelegation(ctx context.Context, arg CreateDelegationParams) (UcanDelegation, error)
|
||||
CreateGrant(ctx context.Context, arg CreateGrantParams) (Grant, error)
|
||||
CreateInvocation(ctx context.Context, arg CreateInvocationParams) (UcanInvocation, error)
|
||||
CreateKeyShare(ctx context.Context, arg CreateKeyShareParams) (KeyShare, error)
|
||||
// =============================================================================
|
||||
// UCAN REVOCATION QUERIES
|
||||
// =============================================================================
|
||||
CreateRevocation(ctx context.Context, arg CreateRevocationParams) error
|
||||
CreateService(ctx context.Context, arg CreateServiceParams) (Service, error)
|
||||
CreateSession(ctx context.Context, arg CreateSessionParams) (Session, error)
|
||||
CreateUCAN(ctx context.Context, arg CreateUCANParams) (UcanToken, error)
|
||||
CreateVerificationMethod(ctx context.Context, arg CreateVerificationMethodParams) (VerificationMethod, error)
|
||||
DeleteAccount(ctx context.Context, arg DeleteAccountParams) error
|
||||
DeleteCredential(ctx context.Context, arg DeleteCredentialParams) error
|
||||
DeleteDelegation(ctx context.Context, arg DeleteDelegationParams) error
|
||||
DeleteExpiredSessions(ctx context.Context) error
|
||||
DeleteKeyShare(ctx context.Context, arg DeleteKeyShareParams) error
|
||||
DeleteSession(ctx context.Context, id int64) error
|
||||
@@ -39,10 +44,20 @@ type Querier interface {
|
||||
GetDIDByDID(ctx context.Context, did string) (DidDocument, error)
|
||||
GetDIDByID(ctx context.Context, id int64) (DidDocument, error)
|
||||
GetDefaultAccount(ctx context.Context, arg GetDefaultAccountParams) (Account, error)
|
||||
GetDelegationChain(ctx context.Context, arg GetDelegationChainParams) ([]Delegation, error)
|
||||
// =============================================================================
|
||||
// UCAN DELEGATION QUERIES (v1.0.0-rc.1)
|
||||
// =============================================================================
|
||||
GetDelegationByCID(ctx context.Context, cid string) (UcanDelegation, error)
|
||||
GetDelegationEnvelopeByCID(ctx context.Context, cid string) ([]byte, error)
|
||||
GetGrantByService(ctx context.Context, arg GetGrantByServiceParams) (Grant, error)
|
||||
// =============================================================================
|
||||
// UCAN INVOCATION QUERIES (v1.0.0-rc.1)
|
||||
// =============================================================================
|
||||
GetInvocationByCID(ctx context.Context, cid string) (UcanInvocation, error)
|
||||
GetInvocationEnvelopeByCID(ctx context.Context, cid string) ([]byte, error)
|
||||
GetKeyShareByID(ctx context.Context, shareID string) (KeyShare, error)
|
||||
GetKeyShareByKeyID(ctx context.Context, arg GetKeyShareByKeyIDParams) (KeyShare, error)
|
||||
GetRevocation(ctx context.Context, delegationCid string) (UcanRevocation, error)
|
||||
GetServiceByID(ctx context.Context, id int64) (Service, error)
|
||||
// =============================================================================
|
||||
// SERVICE QUERIES
|
||||
@@ -53,9 +68,8 @@ type Querier interface {
|
||||
// SYNC QUERIES
|
||||
// =============================================================================
|
||||
GetSyncCheckpoint(ctx context.Context, arg GetSyncCheckpointParams) (SyncCheckpoint, error)
|
||||
GetUCANByCID(ctx context.Context, cid string) (UcanToken, error)
|
||||
GetVerificationMethod(ctx context.Context, arg GetVerificationMethodParams) (VerificationMethod, error)
|
||||
IsUCANRevoked(ctx context.Context, ucanCid string) (int64, error)
|
||||
IsDelegationRevoked(ctx context.Context, delegationCid string) (int64, error)
|
||||
ListAccountsByChain(ctx context.Context, arg ListAccountsByChainParams) ([]Account, error)
|
||||
// =============================================================================
|
||||
// ACCOUNT QUERIES
|
||||
@@ -66,41 +80,41 @@ type Querier interface {
|
||||
// CREDENTIAL QUERIES
|
||||
// =============================================================================
|
||||
ListCredentialsByDID(ctx context.Context, didID int64) ([]Credential, error)
|
||||
ListDelegationsByDelegate(ctx context.Context, delegate string) ([]Delegation, error)
|
||||
// =============================================================================
|
||||
// DELEGATION QUERIES
|
||||
// =============================================================================
|
||||
ListDelegationsByDelegator(ctx context.Context, delegator string) ([]Delegation, error)
|
||||
ListDelegationsForResource(ctx context.Context, arg ListDelegationsForResourceParams) ([]Delegation, error)
|
||||
ListDelegationsByAudience(ctx context.Context, aud string) ([]UcanDelegation, error)
|
||||
ListDelegationsByDID(ctx context.Context, didID int64) ([]UcanDelegation, error)
|
||||
ListDelegationsByIssuer(ctx context.Context, iss string) ([]UcanDelegation, error)
|
||||
ListDelegationsBySubject(ctx context.Context, sub *string) ([]UcanDelegation, error)
|
||||
ListDelegationsForCommand(ctx context.Context, arg ListDelegationsForCommandParams) ([]UcanDelegation, error)
|
||||
// =============================================================================
|
||||
// GRANT QUERIES
|
||||
// =============================================================================
|
||||
ListGrantsByDID(ctx context.Context, didID int64) ([]ListGrantsByDIDRow, error)
|
||||
ListInvocationsByDID(ctx context.Context, arg ListInvocationsByDIDParams) ([]UcanInvocation, error)
|
||||
ListInvocationsByIssuer(ctx context.Context, arg ListInvocationsByIssuerParams) ([]UcanInvocation, error)
|
||||
ListInvocationsBySubject(ctx context.Context, arg ListInvocationsBySubjectParams) ([]UcanInvocation, error)
|
||||
ListInvocationsForCommand(ctx context.Context, arg ListInvocationsForCommandParams) ([]UcanInvocation, error)
|
||||
// =============================================================================
|
||||
// KEY SHARE QUERIES
|
||||
// =============================================================================
|
||||
ListKeySharesByDID(ctx context.Context, didID int64) ([]KeyShare, error)
|
||||
ListPendingInvocations(ctx context.Context, didID int64) ([]UcanInvocation, error)
|
||||
ListPowerlineDelegations(ctx context.Context, didID int64) ([]UcanDelegation, error)
|
||||
ListRevocationsByRevoker(ctx context.Context, revokedBy string) ([]UcanRevocation, error)
|
||||
ListRootDelegations(ctx context.Context, didID int64) ([]UcanDelegation, error)
|
||||
// =============================================================================
|
||||
// SESSION QUERIES
|
||||
// =============================================================================
|
||||
ListSessionsByDID(ctx context.Context, didID int64) ([]ListSessionsByDIDRow, error)
|
||||
ListSyncCheckpoints(ctx context.Context, didID int64) ([]SyncCheckpoint, error)
|
||||
ListUCANsByAudience(ctx context.Context, audience string) ([]UcanToken, error)
|
||||
// =============================================================================
|
||||
// UCAN TOKEN QUERIES
|
||||
// =============================================================================
|
||||
ListUCANsByDID(ctx context.Context, didID int64) ([]UcanToken, error)
|
||||
// =============================================================================
|
||||
// VERIFICATION METHOD QUERIES
|
||||
// =============================================================================
|
||||
ListVerificationMethods(ctx context.Context, didID int64) ([]VerificationMethod, error)
|
||||
ListVerifiedServices(ctx context.Context) ([]Service, error)
|
||||
MarkInvocationExecuted(ctx context.Context, arg MarkInvocationExecutedParams) error
|
||||
ReactivateGrant(ctx context.Context, id int64) error
|
||||
RenameCredential(ctx context.Context, arg RenameCredentialParams) error
|
||||
RevokeDelegation(ctx context.Context, id int64) error
|
||||
RevokeDelegationChain(ctx context.Context, arg RevokeDelegationChainParams) error
|
||||
RevokeGrant(ctx context.Context, id int64) error
|
||||
RevokeUCAN(ctx context.Context, cid string) error
|
||||
RotateKeyShare(ctx context.Context, id int64) error
|
||||
SetCurrentSession(ctx context.Context, arg SetCurrentSessionParams) error
|
||||
SetDefaultAccount(ctx context.Context, arg SetDefaultAccountParams) error
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -108,7 +108,7 @@ DELETE FROM key_shares WHERE id = ? AND did_id = ?;
|
||||
-- =============================================================================
|
||||
|
||||
-- name: ListAccountsByDID :many
|
||||
SELECT a.*, k.public_key, k.curve
|
||||
SELECT a.*, k.public_key as share_public_key, k.curve
|
||||
FROM accounts a
|
||||
JOIN key_shares k ON a.key_share_id = k.id
|
||||
WHERE a.did_id = ?
|
||||
@@ -140,42 +140,137 @@ UPDATE accounts SET label = ? WHERE id = ?;
|
||||
DELETE FROM accounts WHERE id = ? AND did_id = ?;
|
||||
|
||||
-- =============================================================================
|
||||
-- UCAN TOKEN QUERIES
|
||||
-- UCAN DELEGATION QUERIES (v1.0.0-rc.1)
|
||||
-- =============================================================================
|
||||
|
||||
-- name: ListUCANsByDID :many
|
||||
SELECT * FROM ucan_tokens
|
||||
WHERE did_id = ? AND is_revoked = 0 AND expires_at > datetime('now')
|
||||
ORDER BY created_at DESC;
|
||||
-- name: GetDelegationByCID :one
|
||||
SELECT * FROM ucan_delegations WHERE cid = ? LIMIT 1;
|
||||
|
||||
-- name: ListUCANsByAudience :many
|
||||
SELECT * FROM ucan_tokens
|
||||
WHERE audience = ? AND is_revoked = 0 AND expires_at > datetime('now')
|
||||
ORDER BY created_at DESC;
|
||||
-- name: GetDelegationEnvelopeByCID :one
|
||||
SELECT envelope FROM ucan_delegations WHERE cid = ? LIMIT 1;
|
||||
|
||||
-- name: GetUCANByCID :one
|
||||
SELECT * FROM ucan_tokens WHERE cid = ? LIMIT 1;
|
||||
|
||||
-- name: CreateUCAN :one
|
||||
INSERT INTO ucan_tokens (
|
||||
did_id, cid, issuer, audience, subject, capabilities,
|
||||
proof_chain, not_before, expires_at, nonce, facts, signature, raw_token
|
||||
-- name: CreateDelegation :one
|
||||
INSERT INTO ucan_delegations (
|
||||
did_id, cid, envelope, iss, aud, sub, cmd, pol, nbf, exp, is_root, is_powerline
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING *;
|
||||
|
||||
-- name: RevokeUCAN :exec
|
||||
UPDATE ucan_tokens SET is_revoked = 1 WHERE cid = ?;
|
||||
-- name: ListDelegationsByDID :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE did_id = ? AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: IsUCANRevoked :one
|
||||
SELECT EXISTS(SELECT 1 FROM ucan_revocations WHERE ucan_cid = ?) as revoked;
|
||||
-- name: ListDelegationsByIssuer :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE iss = ? AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListDelegationsByAudience :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE aud = ? AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListDelegationsBySubject :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE sub = ? AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListDelegationsForCommand :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE did_id = ?
|
||||
AND (cmd = ? OR cmd = '/' OR ? LIKE cmd || '/%')
|
||||
AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListRootDelegations :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE did_id = ? AND is_root = 1 AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListPowerlineDelegations :many
|
||||
SELECT * FROM ucan_delegations
|
||||
WHERE did_id = ? AND is_powerline = 1 AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: DeleteDelegation :exec
|
||||
DELETE FROM ucan_delegations WHERE cid = ? AND did_id = ?;
|
||||
|
||||
-- name: CleanExpiredDelegations :exec
|
||||
DELETE FROM ucan_delegations WHERE exp < datetime('now', '-30 days');
|
||||
|
||||
-- =============================================================================
|
||||
-- UCAN INVOCATION QUERIES (v1.0.0-rc.1)
|
||||
-- =============================================================================
|
||||
|
||||
-- name: GetInvocationByCID :one
|
||||
SELECT * FROM ucan_invocations WHERE cid = ? LIMIT 1;
|
||||
|
||||
-- name: GetInvocationEnvelopeByCID :one
|
||||
SELECT envelope FROM ucan_invocations WHERE cid = ? LIMIT 1;
|
||||
|
||||
-- name: CreateInvocation :one
|
||||
INSERT INTO ucan_invocations (
|
||||
did_id, cid, envelope, iss, sub, aud, cmd, prf, exp, iat
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING *;
|
||||
|
||||
-- name: ListInvocationsByDID :many
|
||||
SELECT * FROM ucan_invocations
|
||||
WHERE did_id = ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?;
|
||||
|
||||
-- name: ListInvocationsByIssuer :many
|
||||
SELECT * FROM ucan_invocations
|
||||
WHERE iss = ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?;
|
||||
|
||||
-- name: ListInvocationsBySubject :many
|
||||
SELECT * FROM ucan_invocations
|
||||
WHERE sub = ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?;
|
||||
|
||||
-- name: ListInvocationsForCommand :many
|
||||
SELECT * FROM ucan_invocations
|
||||
WHERE did_id = ? AND cmd = ?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?;
|
||||
|
||||
-- name: MarkInvocationExecuted :exec
|
||||
UPDATE ucan_invocations
|
||||
SET executed_at = datetime('now'), result_cid = ?
|
||||
WHERE cid = ?;
|
||||
|
||||
-- name: ListPendingInvocations :many
|
||||
SELECT * FROM ucan_invocations
|
||||
WHERE did_id = ? AND executed_at IS NULL AND (exp IS NULL OR exp > datetime('now'))
|
||||
ORDER BY created_at ASC;
|
||||
|
||||
-- name: CleanOldInvocations :exec
|
||||
DELETE FROM ucan_invocations WHERE created_at < datetime('now', '-90 days');
|
||||
|
||||
-- =============================================================================
|
||||
-- UCAN REVOCATION QUERIES
|
||||
-- =============================================================================
|
||||
|
||||
-- name: CreateRevocation :exec
|
||||
INSERT INTO ucan_revocations (ucan_cid, revoked_by, reason)
|
||||
VALUES (?, ?, ?);
|
||||
INSERT INTO ucan_revocations (delegation_cid, revoked_by, invocation_cid, reason)
|
||||
VALUES (?, ?, ?, ?);
|
||||
|
||||
-- name: CleanExpiredUCANs :exec
|
||||
DELETE FROM ucan_tokens WHERE expires_at < datetime('now', '-30 days');
|
||||
-- name: IsDelegationRevoked :one
|
||||
SELECT EXISTS(SELECT 1 FROM ucan_revocations WHERE delegation_cid = ?) as revoked;
|
||||
|
||||
-- name: GetRevocation :one
|
||||
SELECT * FROM ucan_revocations WHERE delegation_cid = ? LIMIT 1;
|
||||
|
||||
-- name: ListRevocationsByRevoker :many
|
||||
SELECT * FROM ucan_revocations
|
||||
WHERE revoked_by = ?
|
||||
ORDER BY revoked_at DESC;
|
||||
|
||||
-- =============================================================================
|
||||
-- SESSION QUERIES
|
||||
@@ -251,7 +346,7 @@ ORDER BY g.last_used DESC NULLS LAST;
|
||||
SELECT * FROM grants WHERE did_id = ? AND service_id = ? LIMIT 1;
|
||||
|
||||
-- name: CreateGrant :one
|
||||
INSERT INTO grants (did_id, service_id, ucan_id, scopes, accounts, expires_at)
|
||||
INSERT INTO grants (did_id, service_id, delegation_cid, scopes, accounts, expires_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
RETURNING *;
|
||||
|
||||
@@ -273,41 +368,6 @@ UPDATE grants SET status = 'active' WHERE id = ? AND status = 'suspended';
|
||||
-- name: CountActiveGrants :one
|
||||
SELECT COUNT(*) FROM grants WHERE did_id = ? AND status = 'active';
|
||||
|
||||
-- =============================================================================
|
||||
-- DELEGATION QUERIES
|
||||
-- =============================================================================
|
||||
|
||||
-- name: ListDelegationsByDelegator :many
|
||||
SELECT * FROM delegations
|
||||
WHERE delegator = ? AND status = 'active'
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListDelegationsByDelegate :many
|
||||
SELECT * FROM delegations
|
||||
WHERE delegate = ? AND status = 'active' AND (expires_at IS NULL OR expires_at > datetime('now'))
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListDelegationsForResource :many
|
||||
SELECT * FROM delegations
|
||||
WHERE did_id = ? AND resource = ? AND status = 'active'
|
||||
ORDER BY depth, created_at;
|
||||
|
||||
-- name: GetDelegationChain :many
|
||||
SELECT * FROM delegations WHERE id = ? OR parent_id = ? ORDER BY depth DESC;
|
||||
|
||||
-- name: CreateDelegation :one
|
||||
INSERT INTO delegations (
|
||||
did_id, ucan_id, delegator, delegate, resource, action, caveats, parent_id, depth, expires_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING *;
|
||||
|
||||
-- name: RevokeDelegation :exec
|
||||
UPDATE delegations SET status = 'revoked' WHERE id = ?;
|
||||
|
||||
-- name: RevokeDelegationChain :exec
|
||||
UPDATE delegations SET status = 'revoked' WHERE id = ? OR parent_id = ?;
|
||||
|
||||
-- =============================================================================
|
||||
-- SYNC QUERIES
|
||||
-- =============================================================================
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
-- =============================================================================
|
||||
-- NEBULA KEY ENCLAVE SCHEMA
|
||||
-- Encrypted SQLite database for sensitive wallet data
|
||||
-- UCAN v1.0.0-rc.1 compliant
|
||||
-- =============================================================================
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
@@ -112,44 +113,97 @@ CREATE INDEX idx_accounts_address ON accounts(address);
|
||||
CREATE INDEX idx_accounts_chain_id ON accounts(chain_id);
|
||||
|
||||
-- =============================================================================
|
||||
-- UCAN AUTHORIZATION
|
||||
-- UCAN AUTHORIZATION (v1.0.0-rc.1)
|
||||
-- =============================================================================
|
||||
|
||||
-- UCAN Tokens: Capability authorization tokens
|
||||
CREATE TABLE IF NOT EXISTS ucan_tokens (
|
||||
-- UCAN Delegations: v1.0.0-rc.1 delegation envelopes
|
||||
-- Stores sealed DAG-CBOR envelopes with extracted fields for indexing
|
||||
CREATE TABLE IF NOT EXISTS ucan_delegations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
did_id INTEGER NOT NULL REFERENCES did_documents(id) ON DELETE CASCADE,
|
||||
cid TEXT NOT NULL UNIQUE, -- Content ID of UCAN (for dedup)
|
||||
issuer TEXT NOT NULL, -- iss: DID of issuer
|
||||
audience TEXT NOT NULL, -- aud: DID of recipient
|
||||
subject TEXT, -- sub: DID token is about (optional)
|
||||
capabilities TEXT NOT NULL, -- JSON array of capabilities
|
||||
proof_chain TEXT DEFAULT '[]', -- JSON array of parent UCAN CIDs
|
||||
not_before TEXT, -- nbf: validity start
|
||||
expires_at TEXT NOT NULL, -- exp: expiration time
|
||||
nonce TEXT, -- Replay protection
|
||||
facts TEXT DEFAULT '{}', -- Additional facts (JSON)
|
||||
signature TEXT NOT NULL, -- Base64 encoded signature
|
||||
raw_token TEXT NOT NULL, -- Full encoded UCAN token
|
||||
is_revoked INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- Content Identifier (immutable, unique)
|
||||
cid TEXT NOT NULL UNIQUE,
|
||||
|
||||
-- Sealed envelope (DAG-CBOR encoded)
|
||||
envelope BLOB NOT NULL,
|
||||
|
||||
-- Extracted fields for indexing/queries
|
||||
iss TEXT NOT NULL, -- Issuer DID
|
||||
aud TEXT NOT NULL, -- Audience DID
|
||||
sub TEXT, -- Subject DID (null = powerline)
|
||||
cmd TEXT NOT NULL, -- Command (e.g., "/vault/read")
|
||||
|
||||
-- Policy stored as JSON for inspection
|
||||
pol TEXT DEFAULT '[]', -- Policy JSON
|
||||
|
||||
-- Temporal fields
|
||||
nbf TEXT, -- Not before (ISO8601)
|
||||
exp TEXT, -- Expiration (ISO8601, null = never)
|
||||
|
||||
-- Metadata
|
||||
is_root INTEGER NOT NULL DEFAULT 0, -- iss == sub
|
||||
is_powerline INTEGER NOT NULL DEFAULT 0, -- sub IS NULL
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ucan_tokens_did_id ON ucan_tokens(did_id);
|
||||
CREATE INDEX idx_ucan_tokens_issuer ON ucan_tokens(issuer);
|
||||
CREATE INDEX idx_ucan_tokens_audience ON ucan_tokens(audience);
|
||||
CREATE INDEX idx_ucan_tokens_expires_at ON ucan_tokens(expires_at);
|
||||
CREATE INDEX idx_ucan_delegations_cid ON ucan_delegations(cid);
|
||||
CREATE INDEX idx_ucan_delegations_did_id ON ucan_delegations(did_id);
|
||||
CREATE INDEX idx_ucan_delegations_iss ON ucan_delegations(iss);
|
||||
CREATE INDEX idx_ucan_delegations_aud ON ucan_delegations(aud);
|
||||
CREATE INDEX idx_ucan_delegations_sub ON ucan_delegations(sub);
|
||||
CREATE INDEX idx_ucan_delegations_cmd ON ucan_delegations(cmd);
|
||||
CREATE INDEX idx_ucan_delegations_exp ON ucan_delegations(exp);
|
||||
|
||||
-- UCAN Revocations: Revoked UCAN tokens
|
||||
-- UCAN Invocations: v1.0.0-rc.1 invocation envelopes (audit log)
|
||||
CREATE TABLE IF NOT EXISTS ucan_invocations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
did_id INTEGER NOT NULL REFERENCES did_documents(id) ON DELETE CASCADE,
|
||||
|
||||
-- Content Identifier
|
||||
cid TEXT NOT NULL UNIQUE,
|
||||
|
||||
-- Sealed envelope (DAG-CBOR encoded)
|
||||
envelope BLOB NOT NULL,
|
||||
|
||||
-- Extracted fields for indexing
|
||||
iss TEXT NOT NULL, -- Invoker DID
|
||||
sub TEXT NOT NULL, -- Subject DID
|
||||
aud TEXT, -- Executor DID (if different from sub)
|
||||
cmd TEXT NOT NULL, -- Command invoked
|
||||
|
||||
-- Proof chain (JSON array of delegation CIDs)
|
||||
prf TEXT NOT NULL DEFAULT '[]',
|
||||
|
||||
-- Temporal
|
||||
exp TEXT, -- Expiration
|
||||
iat TEXT, -- Issued at
|
||||
|
||||
-- Execution tracking
|
||||
executed_at TEXT, -- When actually executed
|
||||
result_cid TEXT, -- CID of receipt (if executed)
|
||||
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ucan_invocations_cid ON ucan_invocations(cid);
|
||||
CREATE INDEX idx_ucan_invocations_did_id ON ucan_invocations(did_id);
|
||||
CREATE INDEX idx_ucan_invocations_iss ON ucan_invocations(iss);
|
||||
CREATE INDEX idx_ucan_invocations_sub ON ucan_invocations(sub);
|
||||
CREATE INDEX idx_ucan_invocations_cmd ON ucan_invocations(cmd);
|
||||
|
||||
-- UCAN Revocations: Track revoked delegations
|
||||
CREATE TABLE IF NOT EXISTS ucan_revocations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
ucan_cid TEXT NOT NULL UNIQUE, -- CID of revoked UCAN
|
||||
revoked_by TEXT NOT NULL, -- DID that revoked
|
||||
delegation_cid TEXT NOT NULL UNIQUE, -- CID of revoked delegation
|
||||
revoked_by TEXT NOT NULL, -- Revoker DID
|
||||
invocation_cid TEXT, -- CID of revocation invocation
|
||||
reason TEXT,
|
||||
revoked_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ucan_revocations_cid ON ucan_revocations(ucan_cid);
|
||||
CREATE INDEX idx_ucan_revocations_delegation_cid ON ucan_revocations(delegation_cid);
|
||||
CREATE INDEX idx_ucan_revocations_revoked_by ON ucan_revocations(revoked_by);
|
||||
|
||||
-- =============================================================================
|
||||
-- DEVICE SESSIONS
|
||||
@@ -191,12 +245,12 @@ CREATE TABLE IF NOT EXISTS services (
|
||||
|
||||
CREATE INDEX idx_services_origin ON services(origin);
|
||||
|
||||
-- Grants: User grants to services
|
||||
-- Grants: User grants to services (backed by UCAN delegations)
|
||||
CREATE TABLE IF NOT EXISTS grants (
|
||||
id INTEGER PRIMARY KEY,
|
||||
did_id INTEGER NOT NULL REFERENCES did_documents(id) ON DELETE CASCADE,
|
||||
service_id INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE,
|
||||
ucan_id INTEGER REFERENCES ucan_tokens(id) ON DELETE SET NULL,
|
||||
delegation_cid TEXT REFERENCES ucan_delegations(cid) ON DELETE SET NULL, -- v1.0.0-rc.1 delegation
|
||||
scopes TEXT NOT NULL DEFAULT '[]', -- JSON array of granted scopes
|
||||
accounts TEXT NOT NULL DEFAULT '[]', -- JSON array of account IDs exposed
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'revoked')),
|
||||
@@ -209,32 +263,7 @@ CREATE TABLE IF NOT EXISTS grants (
|
||||
CREATE INDEX idx_grants_did_id ON grants(did_id);
|
||||
CREATE INDEX idx_grants_service_id ON grants(service_id);
|
||||
CREATE INDEX idx_grants_status ON grants(status);
|
||||
|
||||
-- =============================================================================
|
||||
-- CAPABILITY DELEGATIONS
|
||||
-- =============================================================================
|
||||
|
||||
-- Delegations: Capability delegation chains
|
||||
CREATE TABLE IF NOT EXISTS delegations (
|
||||
id INTEGER PRIMARY KEY,
|
||||
did_id INTEGER NOT NULL REFERENCES did_documents(id) ON DELETE CASCADE,
|
||||
ucan_id INTEGER NOT NULL REFERENCES ucan_tokens(id) ON DELETE CASCADE,
|
||||
delegator TEXT NOT NULL, -- DID that delegated
|
||||
delegate TEXT NOT NULL, -- DID that received delegation
|
||||
resource TEXT NOT NULL, -- Resource URI (e.g., "sonr://vault/*")
|
||||
action TEXT NOT NULL, -- Action (e.g., "sign", "read", "write")
|
||||
caveats TEXT DEFAULT '{}', -- JSON: restrictions/conditions
|
||||
parent_id INTEGER REFERENCES delegations(id), -- Parent delegation (for chains)
|
||||
depth INTEGER NOT NULL DEFAULT 0, -- Delegation depth (0 = root)
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'revoked', 'expired')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
expires_at TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX idx_delegations_did_id ON delegations(did_id);
|
||||
CREATE INDEX idx_delegations_delegator ON delegations(delegator);
|
||||
CREATE INDEX idx_delegations_delegate ON delegations(delegate);
|
||||
CREATE INDEX idx_delegations_resource ON delegations(resource);
|
||||
CREATE INDEX idx_grants_delegation_cid ON grants(delegation_cid);
|
||||
|
||||
-- =============================================================================
|
||||
-- SYNC STATE
|
||||
|
||||
Reference in New Issue
Block a user