2024-10-24 12:59:38 -04:00
|
|
|
package invocation_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"time"
|
|
|
|
|
|
2026-01-08 15:45:57 -05:00
|
|
|
"code.sonr.org/go/did-it"
|
|
|
|
|
didkeyctl "code.sonr.org/go/did-it/controller/did-key"
|
|
|
|
|
"code.sonr.org/go/did-it/crypto/ed25519"
|
2024-10-24 12:59:38 -04:00
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
|
"github.com/ipld/go-ipld-prime"
|
|
|
|
|
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
|
|
|
|
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
|
|
|
|
"github.com/ipld/go-ipld-prime/node/basicnode"
|
2024-11-05 17:39:39 +01:00
|
|
|
|
2026-01-08 15:45:57 -05:00
|
|
|
"code.sonr.org/go/ucan/pkg/command"
|
|
|
|
|
"code.sonr.org/go/ucan/token/invocation"
|
2024-10-24 12:59:38 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func ExampleNew() {
|
|
|
|
|
privKey, iss, sub, cmd, args, prf, meta, err := setupExampleNew()
|
|
|
|
|
if err != nil {
|
2024-11-04 16:07:11 -05:00
|
|
|
fmt.Println("failed to create setup:", err.Error())
|
2024-10-24 12:59:38 -04:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-09 20:39:47 +01:00
|
|
|
inv, err := invocation.New(iss, cmd, sub, prf,
|
2024-11-07 13:50:20 -05:00
|
|
|
invocation.WithArgument("uri", args["uri"]),
|
|
|
|
|
invocation.WithArgument("headers", args["headers"]),
|
|
|
|
|
invocation.WithArgument("payload", args["payload"]),
|
2024-10-24 12:59:38 -04:00
|
|
|
invocation.WithMeta("env", "development"),
|
|
|
|
|
invocation.WithMeta("tags", meta["tags"]),
|
|
|
|
|
invocation.WithExpirationIn(time.Minute),
|
2025-03-11 13:04:00 -04:00
|
|
|
invocation.WithoutIssuedAt())
|
2024-10-24 12:59:38 -04:00
|
|
|
if err != nil {
|
2024-11-04 16:07:11 -05:00
|
|
|
fmt.Println("failed to create invocation:", err.Error())
|
2024-10-24 12:59:38 -04:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, cid, err := inv.ToSealed(privKey)
|
|
|
|
|
if err != nil {
|
2024-11-04 16:07:11 -05:00
|
|
|
fmt.Println("failed to seal invocation:", err.Error())
|
2024-10-24 12:59:38 -04:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
json, err := prettyDAGJSON(data)
|
|
|
|
|
if err != nil {
|
2024-11-04 16:07:11 -05:00
|
|
|
fmt.Println("failed to pretty DAG-JSON:", err.Error())
|
2024-10-24 12:59:38 -04:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("CID:", cid)
|
|
|
|
|
fmt.Println("Token (pretty DAG-JSON):")
|
|
|
|
|
fmt.Println(json)
|
|
|
|
|
|
|
|
|
|
// Expected CID and DAG-JSON output:
|
2025-07-31 14:43:42 +02:00
|
|
|
// CID: bafyreicgyuf6g7geoupyzpo3lgvyvsyhtc6tvnhiajkoo7lmy6woavkhra
|
2024-10-24 12:59:38 -04:00
|
|
|
// Token (pretty DAG-JSON):
|
|
|
|
|
// [
|
|
|
|
|
// {
|
|
|
|
|
// "/": {
|
2025-07-31 14:43:42 +02:00
|
|
|
// "bytes": "nWYKygq0TTooQGdQsfQWwMOCuX7+KYNRSyW8h4AcRoTIJHsYyG/mpU3iBhAdsAGhi8Brnm+/Z0tC2KoC/KUlDA"
|
2024-10-24 12:59:38 -04:00
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// "h": {
|
|
|
|
|
// "/": {
|
2025-07-31 14:43:42 +02:00
|
|
|
// "bytes": "NAHtAe0BE3E"
|
2024-10-24 12:59:38 -04:00
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// "ucan/inv@1.0.0-rc.1": {
|
|
|
|
|
// "args": {
|
|
|
|
|
// "headers": {
|
|
|
|
|
// "Content-Type": "application/json"
|
|
|
|
|
// },
|
|
|
|
|
// "payload": {
|
|
|
|
|
// "body": "UCAN is great",
|
|
|
|
|
// "draft": true,
|
|
|
|
|
// "title": "UCAN for Fun and Profit",
|
|
|
|
|
// "topics": [
|
|
|
|
|
// "authz",
|
|
|
|
|
// "journal"
|
|
|
|
|
// ]
|
|
|
|
|
// },
|
|
|
|
|
// "uri": "https://example.com/blog/posts"
|
|
|
|
|
// },
|
|
|
|
|
// "cmd": "/crud/create",
|
2025-07-31 14:43:42 +02:00
|
|
|
// "exp": 1753965273,
|
|
|
|
|
// "iss": "did:key:z6MknZNRLJ8zD2x5QhFuPsXYKAJ8PJpCe76bC5p7bGZXC5HD",
|
2024-10-24 12:59:38 -04:00
|
|
|
// "meta": {
|
|
|
|
|
// "env": "development",
|
|
|
|
|
// "tags": [
|
|
|
|
|
// "blog",
|
|
|
|
|
// "post",
|
|
|
|
|
// "pr#123"
|
|
|
|
|
// ]
|
|
|
|
|
// },
|
|
|
|
|
// "nonce": {
|
|
|
|
|
// "/": {
|
2025-07-31 14:43:42 +02:00
|
|
|
// "bytes": "y4kwaLuEHOPBUgrl"
|
2024-10-24 12:59:38 -04:00
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// "prf": [
|
|
|
|
|
// {
|
|
|
|
|
// "/": "bafyreigx3qxd2cndpe66j2mdssj773ecv7tqd7wovcnz5raguw6lj7sjoe"
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// "/": "bafyreib34ira254zdqgehz6f2bhwme2ja2re3ltcalejv4x4tkcveujvpa"
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// "/": "bafyreibkb66tpo2ixqx3fe5hmekkbuasrod6olt5bwm5u5pi726mduuwlq"
|
|
|
|
|
// }
|
|
|
|
|
// ],
|
2025-07-31 14:43:42 +02:00
|
|
|
// "sub": "did:key:z6MkqEBN9zEGU9Euh9toLGFkTaSguXPavv55yS9m3VnwWeMW"
|
2024-10-24 12:59:38 -04:00
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// ]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func prettyDAGJSON(data []byte) (string, error) {
|
|
|
|
|
var node ipld.Node
|
|
|
|
|
|
|
|
|
|
node, err := ipld.Decode(data, dagcbor.Decode)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jsonData, err := ipld.Encode(node, dagjson.Encode)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var out bytes.Buffer
|
|
|
|
|
if err := json.Indent(&out, jsonData, "", " "); err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return out.String(), nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 14:43:42 +02:00
|
|
|
func setupExampleNew() (privKey ed25519.PrivateKey, iss, sub did.DID, cmd command.Command, args map[string]any, prf []cid.Cid, meta map[string]any, errs error) {
|
2024-10-24 12:59:38 -04:00
|
|
|
var err error
|
|
|
|
|
|
2025-07-31 14:43:42 +02:00
|
|
|
_, privKey, err = ed25519.GenerateKeyPair()
|
2024-10-24 12:59:38 -04:00
|
|
|
if err != nil {
|
2025-07-31 14:43:42 +02:00
|
|
|
errs = errors.Join(errs, fmt.Errorf("failed to generate Ed25519 keypair: %w", err))
|
|
|
|
|
return
|
2024-10-24 12:59:38 -04:00
|
|
|
}
|
2025-07-31 14:43:42 +02:00
|
|
|
iss = didkeyctl.FromPrivateKey(privKey)
|
2024-10-24 12:59:38 -04:00
|
|
|
|
2025-07-31 14:43:42 +02:00
|
|
|
_, privKeySub, err := ed25519.GenerateKeyPair()
|
2024-10-24 12:59:38 -04:00
|
|
|
if err != nil {
|
2025-07-31 14:43:42 +02:00
|
|
|
errs = errors.Join(errs, fmt.Errorf("failed to generate Ed25519 keypair: %w", err))
|
|
|
|
|
return
|
2024-10-24 12:59:38 -04:00
|
|
|
}
|
2025-07-31 14:43:42 +02:00
|
|
|
sub = didkeyctl.FromPrivateKey(privKeySub)
|
2024-10-24 12:59:38 -04:00
|
|
|
|
|
|
|
|
cmd, err = command.Parse("/crud/create")
|
|
|
|
|
if err != nil {
|
|
|
|
|
errs = errors.Join(errs, fmt.Errorf("failed to parse command: %w", err))
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-12 13:05:48 +01:00
|
|
|
headers := map[string]string{
|
|
|
|
|
"Content-Type": "application/json",
|
2024-10-24 12:59:38 -04:00
|
|
|
}
|
2024-11-04 16:07:11 -05:00
|
|
|
|
2024-11-12 13:05:48 +01:00
|
|
|
payload := map[string]any{
|
|
|
|
|
"body": "UCAN is great",
|
|
|
|
|
"draft": true,
|
|
|
|
|
"title": "UCAN for Fun and Profit",
|
|
|
|
|
"topics": []string{"authz", "journal"},
|
2024-10-24 12:59:38 -04:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 13:05:48 +01:00
|
|
|
args = map[string]any{
|
|
|
|
|
// you can also directly pass IPLD values
|
2024-10-24 12:59:38 -04:00
|
|
|
"uri": basicnode.NewString("https://example.com/blog/posts"),
|
|
|
|
|
"headers": headers,
|
|
|
|
|
"payload": payload,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prf = make([]cid.Cid, 3)
|
|
|
|
|
for i, v := range []string{
|
|
|
|
|
"zdpuAzx4sBrBCabrZZqXgvK3NDzh7Mf5mKbG11aBkkMCdLtCp",
|
|
|
|
|
"zdpuApTCXfoKh2sB1KaUaVSGofCBNPUnXoBb6WiCeitXEibZy",
|
|
|
|
|
"zdpuAoFdXRPw4n6TLcncoDhq1Mr6FGbpjAiEtqSBrTSaYMKkf",
|
|
|
|
|
} {
|
|
|
|
|
prf[i], err = cid.Parse(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
errs = errors.Join(errs, fmt.Errorf("failed to parse proof cid: %w", err))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-12 13:05:48 +01:00
|
|
|
meta = map[string]any{
|
2024-10-24 12:59:38 -04:00
|
|
|
"env": basicnode.NewString("development"),
|
2024-11-12 13:05:48 +01:00
|
|
|
"tags": []string{"blog", "post", "pr#123"},
|
2024-10-24 12:59:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return // WARNING: named return values
|
|
|
|
|
}
|