diff --git a/.github/workflows/workspace-test.yml b/.github/workflows/workspace-test.yml new file mode 100644 index 0000000..3777641 --- /dev/null +++ b/.github/workflows/workspace-test.yml @@ -0,0 +1,16 @@ +name: Workspace Test + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: workspace-test-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + workspace-test: + uses: fil-forge/libforge/.github/workflows/go-workspace-test.yml@v1 diff --git a/cmd/client/lib/client.go b/cmd/client/lib/client.go index f2e19fb..3a969c8 100644 --- a/cmd/client/lib/client.go +++ b/cmd/client/lib/client.go @@ -4,15 +4,15 @@ import ( "fmt" "net/url" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" "github.com/fil-forge/sprue/internal/fx" "github.com/fil-forge/sprue/pkg/client" - "github.com/fil-forge/sprue/pkg/identity" "github.com/spf13/cobra" "go.uber.org/zap" ) -func InitClient(cmd *cobra.Command) (*client.Client, *config.Config, *zap.Logger, *identity.Identity) { +func InitClient(cmd *cobra.Command) (*client.Client, *config.Config, *zap.Logger, identity.Identity) { var configFile string configFlag := cmd.InheritedFlags().Lookup("config") if configFlag != nil { @@ -29,7 +29,7 @@ func InitClient(cmd *cobra.Command) (*client.Client, *config.Config, *zap.Logger endpoint, err := url.Parse(fmt.Sprintf("http://%s:%d", cfg.Server.Host, cfg.Server.Port)) cobra.CheckErr(err) - c, err := client.New(id.Signer.DID(), endpoint, id.Signer, logger) + c, err := client.New(id.Issuer.DID(), endpoint, id.Issuer, logger) cobra.CheckErr(err) return c, cfg, logger, id } diff --git a/cmd/identity/parse.go b/cmd/identity/parse.go index 3d8eacf..1659b5a 100644 --- a/cmd/identity/parse.go +++ b/cmd/identity/parse.go @@ -8,8 +8,8 @@ import ( "io" "os" - signer "github.com/fil-forge/ucantone/principal/ed25519" - verifier "github.com/fil-forge/ucantone/principal/ed25519/verifier" + signer "github.com/fil-forge/ucantone/multikey/ed25519" + verifier "github.com/fil-forge/ucantone/multikey/ed25519/verifier" "github.com/spf13/cobra" ) @@ -49,7 +49,7 @@ var parseCmd = &cobra.Command{ if err != nil { return fmt.Errorf("decoding ed25519 public key: %w", err) } - fmt.Printf("%s\n", key.DID()) + fmt.Printf("%s\n", key.KeyDID()) case "PRIVATE KEY": sk, err := x509.ParsePKCS8PrivateKey(blk.Bytes) if err != nil { @@ -65,7 +65,7 @@ var parseCmd = &cobra.Command{ if err != nil { return fmt.Errorf("decoding ed25519 private key: %w", err) } - fmt.Printf("%s\n", key.DID()) + fmt.Printf("%s\n", key.KeyDID()) default: return fmt.Errorf("unsupported PEM block type: %s", blk.Type) } diff --git a/go.mod b/go.mod index 730c3a8..d3d9419 100644 --- a/go.mod +++ b/go.mod @@ -4,19 +4,19 @@ go 1.25.3 require ( github.com/alanshaw/dag-json-gen v0.0.6 - github.com/aws/aws-sdk-go-v2 v1.41.3 + github.com/aws/aws-sdk-go-v2 v1.41.7 github.com/aws/aws-sdk-go-v2/config v1.32.11 github.com/aws/aws-sdk-go-v2/credentials v1.19.11 github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.34 - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.57.3 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 github.com/docker/docker v28.5.2+incompatible - github.com/fil-forge/libforge v0.0.0-20260619084920-1753f2265c95 - github.com/fil-forge/ucantone v0.0.0-20260522152152-eda937bc2684 + github.com/fil-forge/libforge v0.0.0-20260619083649-eb26d871cda1 + github.com/fil-forge/ucantone v0.0.0-20260619013642-7985ec010b88 github.com/google/uuid v1.6.0 github.com/ipfs/go-cid v0.6.1 github.com/jackc/pgx/v5 v5.8.0 - github.com/labstack/echo/v4 v4.14.0 + github.com/labstack/echo/v4 v4.15.0 github.com/multiformats/go-multihash v0.2.3 github.com/olekukonko/tablewriter v0.0.5 github.com/pressly/goose/v3 v3.27.0 @@ -38,29 +38,29 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.32.12 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 // indirect - github.com/aws/smithy-go v1.24.2 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect + github.com/aws/smithy-go v1.25.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/uax29/v2 v2.6.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/platforms v1.0.0-rc.4 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect @@ -69,12 +69,11 @@ require ( github.com/ebitengine/purego v0.10.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/filecoin-project/go-data-segment v0.0.1 // indirect - github.com/filecoin-project/go-state-types v0.18.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -83,12 +82,14 @@ require ( github.com/klauspost/compress v1.18.5 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/lib/pq v1.11.1 // indirect + github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mfridman/interpolate v0.0.2 // indirect + github.com/minio/minio-go/v7 v7.0.94 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.2.0 // indirect @@ -100,10 +101,12 @@ require ( github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect + github.com/morikuni/aec v1.1.0 // indirect github.com/mr-tron/base58 v1.3.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multibase v0.3.0 // indirect + github.com/multiformats/go-multicodec v0.10.0 // indirect github.com/multiformats/go-varint v0.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect @@ -127,8 +130,6 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect - gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect go.opentelemetry.io/otel v1.43.0 // indirect @@ -146,7 +147,10 @@ require ( golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.36.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68 // indirect + google.golang.org/grpc v1.81.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.4.1 // indirect pitr.ca/jsontokenizer v0.3.0 // indirect diff --git a/go.sum b/go.sum index 32641db..d69f580 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/alanshaw/dag-json-gen v0.0.6 h1:MiscvWVOhs6/ux7OUdPz2nDRA7GwklZyaAy4XWexpr0= github.com/alanshaw/dag-json-gen v0.0.6/go.mod h1:rXxWw0SItP9QjxpRMpkju66h0KumF7TPCtvHdOKS5lY= -github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA= -github.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= +github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6 h1:N4lRUXZpZ1KVEUn6hxtco/1d2lgYhNn1fHkkl8WhlyQ= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.6/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI= github.com/aws/aws-sdk-go-v2/config v1.32.11 h1:ftxI5sgz8jZkckuUHXfC/wMUc8u3fG1vQS0plr2F2Zs= @@ -18,42 +18,42 @@ github.com/aws/aws-sdk-go-v2/credentials v1.19.11 h1:NdV8cwCcAXrCWyxArt58BrvZJ9p github.com/aws/aws-sdk-go-v2/credentials v1.19.11/go.mod h1:30yY2zqkMPdrvxBqzI9xQCM+WrlrZKSOpSJEsylVU+8= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.34 h1:gBoK/UF+CltS2dkNgpUwEROtNBtAsVCfWqIi+0qRDVA= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.34/go.mod h1:B4x2ogC2wSey/swvEainiBzLXiY89+xJaa85vcJFvD8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 h1:INUvJxmhdEbVulJYHI061k4TVuS3jzzthNvjqvVvTKM= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19/go.mod h1:FpZN2QISLdEBWkayloda+sZjVJL+e9Gl0k1SyTgcswU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 h1:/sECfyq2JTifMI2JPyZ4bdRN77zJmr6SrS1eL3augIA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19/go.mod h1:dMf8A5oAqr9/oxOfLkC/c2LU/uMcALP0Rgn2BD5LWn0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJe6qZoRSJo0WfUhsMdUKhoODXE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1 h1:EkW4NqA2mwCkL7YCDYh6OpA/bCMhKYbZgpRHt2FD2Ow= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.56.1/go.mod h1:OQp5333OH1IjmJmJpTU4IwoaOoCMnDrThg0zIx169rE= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.57.3 h1:XgjzLEE8CrNYnr4Xmi1W5PfKsKMjp4Pu1rWkJNO43JI= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.57.3/go.mod h1:r7sfLXEN8RUA89tAHy1E7lCtVOOWIkqVy/FbnUdxW1E= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.32.12 h1:EhZjf2GKn/V3yPfYmUGdYmrcbxaGu2LO0M6ZrOt/qu8= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.32.12/go.mod h1:KPi0H5VdX4011P0gF806TZt8EiP3FkeRkt6+lzMUvxQ= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11/go.mod h1:aEUS4WrNk/+FxkBZZa7tVgp4pGH+kFGW40Y8rCPqt5g= -github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19 h1:jdCj9vbCXwzTcIJX+MVd2UdssFhRJFTrWlPZwZB8Hpk= -github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.19/go.mod h1:Dgg2d5WGRr7YB8JJsELskBxLUhgwWppXPwlvmuQKhbc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7suZk9UCJHE1Iw9GMZJJl0dAnKXXP1NaSDHwmw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.23 h1:3Eo/PBBnjFi1+gYfaL286dpmFSW3mTfodBIybq36Qv4= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.23/go.mod h1:3oh+5xGSd1iuxonVb3Qbm+WJYlbhczT9kbzr6doJLzY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.12/go.mod h1:fEWYKTRGoZNl8tZ77i61/ccwOMJdGxwOhWCkp6TXAr0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 h1:EnUdUqRP1CNzt2DkV67tJx6XDN4xlfBFm+bzeNOQVb0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16/go.mod h1:Jic/xv0Rq/pFNCh3WwpH4BEqdbSAl+IyHro8LbibHD8= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nniYPZnO1D4Np761Oo= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI= -github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= -github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= +github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= +github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -68,8 +68,8 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= -github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/platforms v1.0.0-rc.4 h1:M42JrUT4zfZTqtkUwkr0GzmUWbfyO5VO0Q5b3op97T4= +github.com/containerd/platforms v1.0.0-rc.4/go.mod h1:lKlMXyLybmBedS/JJm11uDofzI8L2v0J2ZbYvNsbq1A= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -92,32 +92,35 @@ github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fil-forge/libforge v0.0.0-20260619084920-1753f2265c95 h1:GUnpBYLuWK3mzDsGVXt0CEIHIFeEd3B+Ne2FkqnBfJU= -github.com/fil-forge/libforge v0.0.0-20260619084920-1753f2265c95/go.mod h1:1ytnrneNEeJcskEbsRDtNZY/Jvgo2Yw5szIUI/9EWPk= -github.com/fil-forge/ucantone v0.0.0-20260522152152-eda937bc2684 h1:kWJLKVltJXPXO7tKS1z0GhzA+c59gwhediGyByEXE0o= -github.com/fil-forge/ucantone v0.0.0-20260522152152-eda937bc2684/go.mod h1:XAVqsZwYoZ9vncjZoRUAJ+mL/ApLMFn9HHX7ipohVdY= +github.com/fil-forge/libforge v0.0.0-20260619083649-eb26d871cda1 h1:BZUTgenH/AawsAzH8xOx2tFyGXIhSacGiir4PwojX2M= +github.com/fil-forge/libforge v0.0.0-20260619083649-eb26d871cda1/go.mod h1:0kXihIQ4L2uZ00nR5XrZ/Y8Db7Ht/qQNuiWslwMJ95M= +github.com/fil-forge/ucantone v0.0.0-20260619013642-7985ec010b88 h1:N0gbL3Ik+XBYk4y/5BxTVymwbRGlxRXwC5eNWzi1bGI= +github.com/fil-forge/ucantone v0.0.0-20260619013642-7985ec010b88/go.mod h1:rTIRXz4xErI4U+YlBU9ZvhlTbr4Hs5tJhVMwereVkSg= github.com/filecoin-project/go-data-segment v0.0.1 h1:1wmDxOG4ubWQm3ZC1XI5nCon5qgSq7Ra3Rb6Dbu10Gs= github.com/filecoin-project/go-data-segment v0.0.1/go.mod h1:H0/NKbsRxmRFBcLibmABv+yFNHdmtl5AyplYLnb0Zv4= github.com/filecoin-project/go-fil-commcid v0.3.1 h1:4EfxpHSlvtkOqa9weG2Yt5kxFmPib2xU7Uc9Lbqk7fs= github.com/filecoin-project/go-fil-commcid v0.3.1/go.mod h1:z7Ssf8d7kspF9QRAVHDbZ+43JK4mkhbGH5lyph1TnKY= -github.com/filecoin-project/go-state-types v0.18.0 h1:oDcjihXRlf2cM176atZzllp79Zc+kcbiuQM9DPL/1a4= -github.com/filecoin-project/go-state-types v0.18.0/go.mod h1:CcyG4ZQRDWW+QUY2WDf1KtVDRN7W4twjsfgnGbQfJVI= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -136,8 +139,6 @@ github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -146,14 +147,14 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.14.0 h1:+tiMrDLxwv6u0oKtD03mv+V1vXXB3wCqPHJqPuIe+7M= -github.com/labstack/echo/v4 v4.14.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c= +github.com/labstack/echo/v4 v4.15.0 h1:hoRTKWcnR5STXZFe9BmYun9AMTNeSbjHi2vtDuADJ24= +github.com/labstack/echo/v4 v4.15.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lib/pq v1.11.1 h1:wuChtj2hfsGmmx3nf1m7xC2XpK6OtelS2shMY+bGMtI= +github.com/lib/pq v1.11.1/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI= +github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= @@ -169,10 +170,12 @@ github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5L github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= +github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY= +github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.68 h1:hTqSIfLlpXaKuNy4baAp4Jjy2sqZEN9hRxD0M4aOfrQ= -github.com/minio/minio-go/v7 v7.0.68/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= +github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM= +github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -195,12 +198,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= github.com/mr-tron/base58 v1.3.0 h1:K6Y13R2h+dku0wOqKtecgRnBUBPrZzLZy5aIj8lCcJI= github.com/mr-tron/base58 v1.3.0/go.mod h1:2BuubE67DCSWwVfx37JWNG8emOC0sHEU4/HpcYgCLX8= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -227,6 +226,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -240,8 +241,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= @@ -283,6 +284,8 @@ github.com/testcontainers/testcontainers-go/modules/minio v0.40.0 h1:M+Ib1mIXq/h github.com/testcontainers/testcontainers-go/modules/minio v0.40.0/go.mod h1:ON0MxxS/pME0SJOKLImw/D9R1L7apYsxIZrM/uEqORA= github.com/testcontainers/testcontainers-go/modules/postgres v0.42.0 h1:GCbb1ndrF7OTDiIvxXyItaDab4qkzTFJ48LKFdM7EIo= github.com/testcontainers/testcontainers-go/modules/postgres v0.42.0/go.mod h1:IRPBaI8jXdrNfD0e4Zm7Fbcgaz5shKxOQv4axiL09xs= +github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= +github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= @@ -342,6 +345,7 @@ golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= @@ -349,24 +353,21 @@ golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68 h1:WVVw1Nl19li0fMX++FJ3ye1z9+S1N35QODDy5qpnaXw= +google.golang.org/genproto/googleapis/api v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:1dCETSCY2YKZNXQE3h4fun3TYwF5p8jejRKZgfWAgAY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68 h1:PvEgGJf9C/1u5CHkInMg7UFYYUoiaQmW2LbtH0pjB78= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/fx/app_test.go b/internal/fx/app_test.go index e53f168..553ca8f 100644 --- a/internal/fx/app_test.go +++ b/internal/fx/app_test.go @@ -7,7 +7,7 @@ import ( "github.com/fil-forge/sprue/internal/config" appfx "github.com/fil-forge/sprue/internal/fx" "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/ucantone/principal/signer" + "github.com/fil-forge/ucantone/multikey" "github.com/google/uuid" "go.uber.org/fx/fxtest" ) @@ -45,7 +45,7 @@ func TestWireApp(t *testing.T) { Port: 0, }, Identity: config.IdentityConfig{ - PrivateKey: signer.Format(testutil.WebService), + PrivateKey: multikey.FormatSigner(testutil.WebServiceSigner), ServiceDID: testutil.WebService.DID().String(), }, Indexer: config.IndexerConfig{ @@ -111,7 +111,7 @@ func TestWireApp(t *testing.T) { Port: 0, }, Identity: config.IdentityConfig{ - PrivateKey: signer.Format(testutil.WebService), + PrivateKey: multikey.FormatSigner(testutil.WebServiceSigner), ServiceDID: testutil.WebService.DID().String(), }, Indexer: config.IndexerConfig{ @@ -152,7 +152,7 @@ func TestWireApp(t *testing.T) { Port: 0, }, Identity: config.IdentityConfig{ - PrivateKey: signer.Format(testutil.WebService), + PrivateKey: multikey.FormatSigner(testutil.WebServiceSigner), ServiceDID: testutil.WebService.DID().String(), }, Indexer: config.IndexerConfig{ diff --git a/internal/fx/clients.go b/internal/fx/clients.go index e61bba3..2e87cbb 100644 --- a/internal/fx/clients.go +++ b/internal/fx/clients.go @@ -3,8 +3,9 @@ package fx import ( "net/url" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/sprue/pkg/indexerclient" "github.com/fil-forge/sprue/pkg/piriclient" "github.com/fil-forge/ucantone/did" @@ -18,8 +19,8 @@ var ClientsModule = fx.Module("clients", fx.Provide(NewPiriClientProvider), ) -func NewPiriClientProvider(id *identity.Identity, logger *zap.Logger) piriclient.Provider { - return piriclient.NewProvider(id.Signer, logger) +func NewPiriClientProvider(id identity.Identity, logger *zap.Logger) piriclient.Provider { + return piriclient.NewProvider(id.Issuer, logger) } // IndexerClientResult wraps the optional indexer client. @@ -34,7 +35,7 @@ type IndexerClientResult struct { // NewIndexerClient creates an indexer client if configured. func NewIndexerClient( cfg *config.Config, - id *identity.Identity, + id identity.Identity, logger *zap.Logger, ) IndexerClientResult { if cfg.Indexer.Endpoint == "" { @@ -75,7 +76,7 @@ func NewIndexerClient( } } - client, err := indexerclient.New(indexerURL, indexerDID, id.Signer, logger) + client, err := indexerclient.New(indexerURL, indexerDID, id.Issuer, logger) if err != nil { logger.Warn("failed to create indexer client", zap.Error(err), diff --git a/internal/fx/identity.go b/internal/fx/identity.go index cb2cb3d..ae7f2bc 100644 --- a/internal/fx/identity.go +++ b/internal/fx/identity.go @@ -6,8 +6,8 @@ import ( "go.uber.org/fx" "go.uber.org/zap" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" - "github.com/fil-forge/sprue/pkg/identity" ) // IdentityModule provides the service identity. @@ -16,22 +16,22 @@ var IdentityModule = fx.Module("identity", ) // NewIdentity creates an identity from the configured key file or generates one. -func NewIdentity(cfg *config.Config, logger *zap.Logger) (*identity.Identity, error) { +func NewIdentity(cfg *config.Config, logger *zap.Logger) (identity.Identity, error) { if cfg.Identity.KeyFile != "" { // Use PEM file with optional did:web wrapping id, err := identity.NewFromPEMFileWithDID(cfg.Identity.KeyFile, cfg.Identity.ServiceDID) if err != nil { - return nil, fmt.Errorf("identity from key file: %w", err) + return identity.Identity{}, fmt.Errorf("identity from key file: %w", err) } if cfg.Identity.ServiceDID != "" { logger.Info("service identity created from PEM file with did:web wrapping", - zap.String("did", id.DID()), + zap.String("did", id.DID().String()), zap.String("key_file", cfg.Identity.KeyFile), zap.String("service_did", cfg.Identity.ServiceDID), ) } else { logger.Info("service identity created from PEM file", - zap.String("did", id.DID()), + zap.String("did", id.DID().String()), zap.String("key_file", cfg.Identity.KeyFile), ) } @@ -39,10 +39,10 @@ func NewIdentity(cfg *config.Config, logger *zap.Logger) (*identity.Identity, er } // Generate or use base64-encoded key - id, err := identity.New(cfg.Identity.PrivateKey) + id, err := identity.New(cfg.Identity.PrivateKey, "") if err != nil { - return nil, fmt.Errorf("creating identity: %w", err) + return identity.Identity{}, fmt.Errorf("creating identity: %w", err) } - logger.Info("service identity created", zap.String("did", id.DID())) + logger.Info("service identity created", zap.String("did", id.DID().String())) return id, nil } diff --git a/internal/fx/server.go b/internal/fx/server.go index 435b4ae..2f4ea86 100644 --- a/internal/fx/server.go +++ b/internal/fx/server.go @@ -11,8 +11,8 @@ import ( "go.uber.org/fx" "go.uber.org/zap" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service" ) @@ -24,7 +24,7 @@ var ServerModule = fx.Module("server", // NewEchoServer creates and configures the Echo HTTP server. func NewEchoServer( - id *identity.Identity, + id identity.Identity, svc *service.Service, ) *echo.Echo { e := echo.New() @@ -54,14 +54,14 @@ func RegisterServerLifecycle( e *echo.Echo, cfg *config.Config, logger *zap.Logger, - id *identity.Identity, + id identity.Identity, ) { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port) logger.Info("starting sprue service", zap.String("address", addr), - zap.String("did", id.DID()), + zap.String("did", id.DID().String()), ) go func() { @@ -82,7 +82,7 @@ func RegisterServerLifecycle( } // infoHandler returns service information. -func infoHandler(id *identity.Identity) echo.HandlerFunc { +func infoHandler(id identity.Identity) echo.HandlerFunc { return func(c echo.Context) error { return c.JSON(http.StatusOK, map[string]interface{}{ "service": "sprue", @@ -100,8 +100,14 @@ func healthHandler(c echo.Context) error { } // didDocumentHandler returns the DID document for did:web resolution. -func didDocumentHandler(id *identity.Identity) echo.HandlerFunc { +func didDocumentHandler(id identity.Identity) echo.HandlerFunc { return func(c echo.Context) error { - return c.JSON(http.StatusOK, id.DIDDocument()) + doc, err := id.DIDDocument() + if err != nil { + return c.JSON(http.StatusInternalServerError, map[string]string{ + "error": "failed to get DID document", + }) + } + return c.JSON(http.StatusOK, doc) } } diff --git a/internal/fx/service/provider.go b/internal/fx/service/provider.go index 4c88ecd..506e658 100644 --- a/internal/fx/service/provider.go +++ b/internal/fx/service/provider.go @@ -1,8 +1,9 @@ package service import ( + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/sprue/pkg/service" "github.com/fil-forge/sprue/pkg/store/agent" "github.com/fil-forge/sprue/pkg/store/delegation" @@ -20,7 +21,7 @@ var Module = fx.Module("service", type ServiceParams struct { fx.In - Identity *identity.Identity + Identity identity.Identity DeploymentConfig config.DeploymentConfig AgentStore agent.Store DelegationStore delegation.Store diff --git a/internal/fx/services.go b/internal/fx/services.go index 1c49106..c09fb12 100644 --- a/internal/fx/services.go +++ b/internal/fx/services.go @@ -7,9 +7,9 @@ import ( "go.uber.org/fx" "go.uber.org/zap" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" "github.com/fil-forge/sprue/pkg/billing" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/mailer" "github.com/fil-forge/sprue/pkg/mailer/nop" "github.com/fil-forge/sprue/pkg/mailer/postmark" @@ -63,9 +63,9 @@ func NewMailingService(deploymentCfg config.DeploymentConfig, mailerCfg config.M } func NewProvisioningService( - id *identity.Identity, + id identity.Identity, consumerStore consumer.Store, subscriptionStore subscription.Store, ) *provisioning.Service { - return provisioning.NewService([]provisioning.ServiceDID{id.Signer.DID()}, consumerStore, subscriptionStore) + return provisioning.NewService([]provisioning.ServiceDID{id.Issuer.DID()}, consumerStore, subscriptionStore) } diff --git a/internal/testutil/alias.go b/internal/testutil/alias.go index 0507ba9..17f71b9 100644 --- a/internal/testutil/alias.go +++ b/internal/testutil/alias.go @@ -3,21 +3,24 @@ package testutil import ( "testing" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/libforge/testutil" "github.com/ipfs/go-cid" ) var ( - Alice = testutil.Alice - Bob = testutil.Bob - Carol = testutil.Carol - Mallory = testutil.Mallory - Service = testutil.Service - WebService = testutil.WebService - RandomBytes = testutil.RandomBytes - RandomDID = testutil.RandomDID - RandomMultihash = testutil.RandomMultihash - RandomSigner = testutil.RandomSigner + Alice = testutil.Alice + Bob = testutil.Bob + Carol = testutil.Carol + Mallory = testutil.Mallory + Service = testutil.Service + WebService = identity.Identity{Issuer: testutil.WebService} + WebServiceSigner = testutil.WebServiceSigner + RandomBytes = testutil.RandomBytes + RandomDID = testutil.RandomDID + RandomMultihash = testutil.RandomMultihash + RandomIssuer = testutil.RandomIssuer + RandomMultikeyIssuer = testutil.RandomMultikeyIssuer ) func RandomCID(t *testing.T) cid.Cid { diff --git a/pkg/billing/service_test.go b/pkg/billing/service_test.go index fec7e13..ad6240c 100644 --- a/pkg/billing/service_test.go +++ b/pkg/billing/service_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/attestation/didmailto" customermemory "github.com/fil-forge/sprue/pkg/store/customer/memory" "github.com/fil-forge/ucantone/did" "github.com/stretchr/testify/require" diff --git a/pkg/client/client.go b/pkg/client/client.go index 01baf71..7ba2430 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -20,30 +20,30 @@ import ( type Client struct { uploadServiceID did.DID client *client.HTTPClient - signer ucan.Signer + issuer ucan.Issuer logger *zap.Logger } -func New(uploadServiceID did.DID, endpoint *url.URL, signer ucan.Signer, logger *zap.Logger) (*Client, error) { +func New(uploadServiceID did.DID, endpoint *url.URL, issuer ucan.Issuer, logger *zap.Logger) (*Client, error) { client, err := client.NewHTTP(endpoint) if err != nil { return nil, fmt.Errorf("creating HTTP client: %w", err) } - return NewWithClient(uploadServiceID, client, signer, logger), nil + return NewWithClient(uploadServiceID, client, issuer, logger), nil } -func NewWithClient(uploadServiceID did.DID, client *client.HTTPClient, signer ucan.Signer, logger *zap.Logger) *Client { +func NewWithClient(uploadServiceID did.DID, client *client.HTTPClient, issuer ucan.Issuer, logger *zap.Logger) *Client { return &Client{ uploadServiceID: uploadServiceID, - signer: signer, + issuer: issuer, client: client, logger: logger, } } func (c *Client) AdminProviderRegister(ctx context.Context, providerID did.DID, endpoint string, proofs ucan.Container, options ...invocation.Option) (ucan.Receipt, error) { - if c.signer.DID() != c.uploadServiceID { - return nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.signer.DID(), c.uploadServiceID) + if c.issuer.DID() != c.uploadServiceID { + return nil, fmt.Errorf("admin operation not permitted: issuer DID %s does not match upload service ID %s", c.issuer.DID(), c.uploadServiceID) } if proofs == nil { @@ -62,7 +62,7 @@ func (c *Client) AdminProviderRegister(ctx context.Context, providerID did.DID, ) inv, err := providercap.Register.Invoke( - c.signer, + c.issuer, c.uploadServiceID, &providercap.RegisterArguments{ Provider: providerID, @@ -83,8 +83,8 @@ func (c *Client) AdminProviderRegister(ctx context.Context, providerID did.DID, } func (c *Client) AdminProviderDeregister(ctx context.Context, providerID did.DID, options ...invocation.Option) (ucan.Receipt, error) { - if c.signer.DID() != c.uploadServiceID { - return nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.signer.DID(), c.uploadServiceID) + if c.issuer.DID() != c.uploadServiceID { + return nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.issuer.DID(), c.uploadServiceID) } options = slices.Clone(options) @@ -94,7 +94,7 @@ func (c *Client) AdminProviderDeregister(ctx context.Context, providerID did.DID ) inv, err := providercap.Deregister.Invoke( - c.signer, + c.issuer, c.uploadServiceID, &providercap.DeregisterArguments{ Provider: providerID, @@ -113,8 +113,8 @@ func (c *Client) AdminProviderDeregister(ctx context.Context, providerID did.DID } func (c *Client) AdminProviderList(ctx context.Context, options ...invocation.Option) (*providercap.ListOK, ucan.Receipt, error) { - if c.signer.DID() != c.uploadServiceID { - return nil, nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.signer.DID(), c.uploadServiceID) + if c.issuer.DID() != c.uploadServiceID { + return nil, nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.issuer.DID(), c.uploadServiceID) } options = slices.Clone(options) @@ -124,7 +124,7 @@ func (c *Client) AdminProviderList(ctx context.Context, options ...invocation.Op ) inv, err := providercap.List.Invoke( - c.signer, + c.issuer, c.uploadServiceID, &providercap.ListArguments{}, options..., @@ -141,8 +141,8 @@ func (c *Client) AdminProviderList(ctx context.Context, options ...invocation.Op } func (c *Client) AdminProviderWeightSet(ctx context.Context, providerID did.DID, weight int, replicationWeight int, options ...invocation.Option) (ucan.Receipt, error) { - if c.signer.DID() != c.uploadServiceID { - return nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.signer.DID(), c.uploadServiceID) + if c.issuer.DID() != c.uploadServiceID { + return nil, fmt.Errorf("admin operation not permitted: signer DID %s does not match upload service ID %s", c.issuer.DID(), c.uploadServiceID) } options = slices.Clone(options) @@ -152,7 +152,7 @@ func (c *Client) AdminProviderWeightSet(ctx context.Context, providerID did.DID, ) inv, err := weightcap.Set.Invoke( - c.signer, + c.issuer, c.uploadServiceID, &weightcap.SetArguments{ Provider: providerID, diff --git a/pkg/identity/identity.go b/pkg/identity/identity.go deleted file mode 100644 index af3e832..0000000 --- a/pkg/identity/identity.go +++ /dev/null @@ -1,134 +0,0 @@ -package identity - -import ( - "fmt" - "os" - "strings" - - "github.com/fil-forge/libforge/identity" - "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" - "github.com/fil-forge/ucantone/principal/ed25519" - "github.com/fil-forge/ucantone/principal/signer" -) - -// Identity holds the service's cryptographic identity. -type Identity struct { - Signer principal.Signer -} - -// New creates a new identity. If privateKeyBase64 is empty, generates a new key. -func New(privateKeyBase64 string) (*Identity, error) { - var signer principal.Signer - var err error - - if privateKeyBase64 == "" { - // Generate ephemeral identity - signer, err = ed25519.Generate() - if err != nil { - return nil, fmt.Errorf("failed to generate signer: %w", err) - } - } else { - // Decode provided key - signer, err = ed25519.Parse(privateKeyBase64) - if err != nil { - return nil, fmt.Errorf("failed to create signer from key: %w", err) - } - } - - return &Identity{ - Signer: signer, - }, nil -} - -// DID returns the service's DID. -func (i *Identity) DID() string { - return i.Signer.DID().String() -} - -// UnderlyingKeyDID returns the underlying did:key for wrapped signers. -// For unwrapped signers, returns the same as DID(). -func (i *Identity) UnderlyingKeyDID() string { - // Try to unwrap if it's a wrapped signer - if wrapped, ok := i.Signer.(signer.Unwrapper); ok { - return wrapped.Unwrap().DID().String() - } - return i.Signer.DID().String() -} - -// DIDDocument returns a DID document for did:web resolution. -// This enables other services to verify signatures from this service. -func (i *Identity) DIDDocument() map[string]interface{} { - serviceDID := i.DID() - keyDID := i.UnderlyingKeyDID() - - // Extract the multibase public key from the did:key - // did:key format is "did:key:z6Mk..." where z6Mk... is the multibase-encoded public key - publicKeyMultibase := strings.TrimPrefix(keyDID, "did:key:") - - keyID := serviceDID + "#key-0" - - return map[string]interface{}{ - "@context": []string{ - "https://www.w3.org/ns/did/v1", - "https://w3id.org/security/suites/ed25519-2020/v1", - }, - "id": serviceDID, - "verificationMethod": []map[string]interface{}{ - { - "id": keyID, - "type": "Ed25519VerificationKey2020", - "controller": serviceDID, - "publicKeyMultibase": publicKeyMultibase, - }, - }, - "authentication": []string{keyID}, - "assertionMethod": []string{keyID}, - } -} - -// NewFromPEMFile creates a new identity from an Ed25519 PEM key file. -func NewFromPEMFile(keyFilePath string) (*Identity, error) { - pem, err := os.ReadFile(keyFilePath) - if err != nil { - return nil, fmt.Errorf("failed to read key file: %w", err) - } - keySigner, err := identity.DecodeEd25519SignerFromPEM(pem) - if err != nil { - return nil, fmt.Errorf("failed to decode key from PEM file: %w", err) - } - return &Identity{Signer: keySigner}, nil -} - -// NewFromPEMFileWithDID creates a new identity from an Ed25519 PEM key file, -// optionally wrapping it with a did:web identity. -// When serviceDID is provided (e.g., "did:web:upload"), the underlying did:key -// signer is wrapped so the service presents itself as the did:web identity -// and accepts UCANs addressed to that did:web. -func NewFromPEMFileWithDID(keyFilePath string, serviceDID string) (*Identity, error) { - pem, err := os.ReadFile(keyFilePath) - if err != nil { - return nil, fmt.Errorf("failed to read key file: %w", err) - } - keySigner, err := identity.DecodeEd25519SignerFromPEM(pem) - if err != nil { - return nil, fmt.Errorf("failed to decode key from PEM file: %w", err) - } - - // If serviceDID is provided, wrap the signer with the did:web identity - if serviceDID != "" { - d, err := did.Parse(serviceDID) - if err != nil { - return nil, fmt.Errorf("failed to parse service DID %q: %w", serviceDID, err) - } - - wrappedSigner, err := signer.Wrap(keySigner, d) - if err != nil { - return nil, fmt.Errorf("failed to wrap signer with DID %q: %w", serviceDID, err) - } - - return &Identity{Signer: wrappedSigner}, nil - } - - return &Identity{Signer: keySigner}, nil -} diff --git a/pkg/indexerclient/client.go b/pkg/indexerclient/client.go index e58b033..b262dea 100644 --- a/pkg/indexerclient/client.go +++ b/pkg/indexerclient/client.go @@ -23,13 +23,13 @@ import ( type Client struct { endpoint *url.URL indexerDID did.DID - signer ucan.Signer + issuer ucan.Issuer client *client.HTTPClient logger *zap.Logger } // New creates a new indexer client. -func New(endpoint *url.URL, indexerDID did.DID, signer ucan.Signer, logger *zap.Logger) (*Client, error) { +func New(endpoint *url.URL, indexerDID did.DID, issuer ucan.Issuer, logger *zap.Logger) (*Client, error) { client, err := client.NewHTTP(endpoint) if err != nil { return nil, fmt.Errorf("creating HTTP client: %w", err) @@ -37,7 +37,7 @@ func New(endpoint *url.URL, indexerDID did.DID, signer ucan.Signer, logger *zap. return &Client{ endpoint: endpoint, indexerDID: indexerDID, - signer: signer, + issuer: issuer, client: client, logger: logger, }, nil @@ -48,23 +48,19 @@ func New(endpoint *url.URL, indexerDID did.DID, signer ucan.Signer, logger *zap. // The proofStore parameter is used to build the delegation chain authorizing // the upload service to retrieve the index blob via `/content/retrieve` command. func (c *Client) PublishIndexClaim(ctx context.Context, space did.DID, index cid.Cid, proofStore ucanlib.ProofStore, options ...invocation.Option) (ucan.Receipt, error) { - prfs, prfLinks, err := proofStore.ProofChain(ctx, c.signer.DID(), contentcmds.Retrieve.Command, space) + prfs, prfLinks, err := proofStore.ProofChain(ctx, c.issuer.DID(), contentcmds.Retrieve.Command, space) if err != nil { return nil, fmt.Errorf("building proof chain: %w", err) } - attestations, err := proofStore.ProofAttestations(ctx, prfs, c.signer.DID()) - if err != nil { - return nil, fmt.Errorf("building attestations: %w", err) - } // Create a content retrieval delegation from upload service to indexer - indexerDelegation, err := contentcmds.Retrieve.Delegate(c.signer, c.indexerDID, space) + indexerDelegation, err := contentcmds.Retrieve.Delegate(c.issuer, c.indexerDID, space) if err != nil { return nil, fmt.Errorf("creating indexer delegation: %w", err) } inv, err := assertcmds.Index.Invoke( - c.signer, - c.signer.DID(), + c.issuer, + c.issuer.DID(), &assertcmds.IndexArguments{Index: index}, invocation.WithAudience(c.indexerDID), invocation.WithMetadata( @@ -82,7 +78,6 @@ func (c *Client) PublishIndexClaim(ctx context.Context, space did.DID, index cid inv, execution.WithDelegations(prfs...), execution.WithDelegations(indexerDelegation), - execution.WithInvocations(attestations...), ) if err != nil { return nil, fmt.Errorf("executing assert index invocation: %w", err) diff --git a/pkg/lib/ucan_server/email_auth.go b/pkg/lib/ucan_server/email_auth.go index ad95ac3..8d924c8 100644 --- a/pkg/lib/ucan_server/email_auth.go +++ b/pkg/lib/ucan_server/email_auth.go @@ -5,8 +5,8 @@ import ( "context" "fmt" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/ucantone/execution" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" diff --git a/pkg/lib/ucan_server/validation.go b/pkg/lib/ucan_server/validation.go deleted file mode 100644 index f7d96c9..0000000 --- a/pkg/lib/ucan_server/validation.go +++ /dev/null @@ -1,63 +0,0 @@ -package ucan_server - -import ( - "bytes" - "context" - "fmt" - - "github.com/fil-forge/libforge/commands/ucan/attest" - "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" - secp256k1_verifier "github.com/fil-forge/ucantone/principal/secp256k1/verifier" - "github.com/fil-forge/ucantone/principal/verifier" - "github.com/fil-forge/ucantone/ucan" - ucan_token "github.com/fil-forge/ucantone/ucan/token" - "github.com/fil-forge/ucantone/validator" -) - -func init() { - verifier.Register(secp256k1_verifier.Code, func(b []byte) (principal.Verifier, error) { - return secp256k1_verifier.Decode(b) - }) -} - -func ResolveDIDKey(ctx context.Context, did did.DID) (ucan.Verifier, error) { - return verifier.FromDIDKey(did) -} - -// NewAttestationVerifier creates a [validator.NonStandardSignatureVerifierFunc] -// that validates that a delegation is attested by the given authority. -func NewAttestationVerifier(authority principal.Verifier) validator.NonStandardSignatureVerifierFunc { - return func(ctx context.Context, token ucan.Token, meta ucan.Container) error { - // We only support attestations as delegations - attested delegation MUST - // delegate to an agent DID which is then used in the invocation. - dlg, ok := token.(ucan.Delegation) - if !ok { - return fmt.Errorf("token is not a delegation") - } - for _, inv := range meta.Invocations() { - if inv.Command() != attest.Proof.Command { - continue - } - // only trust attestations we issued - if inv.Issuer() != authority.DID() || inv.Subject() == did.Undef || inv.Subject() != authority.DID() { - continue - } - var args attest.ProofArguments - if err := args.UnmarshalCBOR(bytes.NewReader(inv.ArgumentsBytes())); err != nil { - continue - } - // make sure the attestation is for the delegation in question - if args.Proof != dlg.Link() { - continue - } - // finally, make sure the signature is valid - ok, err := ucan_token.VerifySignature(inv, authority) - if !ok || err != nil { - continue - } - return nil - } - return fmt.Errorf("no valid attestation found for delegation") - } -} diff --git a/pkg/lib/ucan_server/validation_test.go b/pkg/lib/ucan_server/validation_test.go deleted file mode 100644 index 4c89ce4..0000000 --- a/pkg/lib/ucan_server/validation_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package ucan_server - -import ( - "testing" - - "github.com/fil-forge/libforge/commands/ucan/attest" - "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/ipld/datamodel" - "github.com/fil-forge/ucantone/principal/absentee" - "github.com/fil-forge/ucantone/principal/ed25519" - "github.com/fil-forge/ucantone/ucan/command" - "github.com/fil-forge/ucantone/ucan/container" - "github.com/fil-forge/ucantone/ucan/delegation" - "github.com/fil-forge/ucantone/ucan/invocation" - "github.com/stretchr/testify/require" -) - -func TestNewAttestationVerifier(t *testing.T) { - authority := testutil.WebService - agent := testutil.Alice - space := testutil.Must(ed25519.Generate())(t) - other := testutil.Must(ed25519.Generate())(t) - - account := absentee.From(testutil.Must(did.Parse("did:mailto:web.mail:alice"))(t)) - - dlg, err := delegation.Delegate(account, agent.DID(), space.DID(), command.MustParse("/blob/add")) - require.NoError(t, err) - - verify := NewAttestationVerifier(authority.Verifier()) - - t.Run("token is not a delegation", func(t *testing.T) { - inv, err := invocation.Invoke(agent, space.DID(), command.MustParse("/blob/add"), datamodel.Map{}) - require.NoError(t, err) - - err = verify(t.Context(), inv, container.New()) - require.Error(t, err) - require.Contains(t, err.Error(), "not a delegation") - }) - - t.Run("no attestations in container", func(t *testing.T) { - err := verify(t.Context(), dlg, container.New()) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("invocation with non-attest command is ignored", func(t *testing.T) { - inv, err := invocation.Invoke(authority, authority.DID(), command.MustParse("/some/other"), datamodel.Map{}) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("attestation issued by non-authority is ignored", func(t *testing.T) { - inv, err := attest.Proof.Invoke(other, other.DID(), &attest.ProofArguments{Proof: dlg.Link()}) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("attestation with subject other than authority is ignored", func(t *testing.T) { - inv, err := attest.Proof.Invoke(authority, other.DID(), &attest.ProofArguments{Proof: dlg.Link()}) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("attestation proof for a different delegation is ignored", func(t *testing.T) { - otherDlg, err := delegation.Delegate(account, agent.DID(), space.DID(), command.MustParse("/blob/list")) - require.NoError(t, err) - - inv, err := attest.Proof.Invoke(authority, authority.DID(), &attest.ProofArguments{Proof: otherDlg.Link()}) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("attestation with malformed arguments is ignored", func(t *testing.T) { - inv, err := invocation.Invoke( - authority, - authority.DID(), - attest.Proof.Command, - datamodel.Map{"unrelated": "foo"}, - ) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.Error(t, err) - require.Contains(t, err.Error(), "no valid attestation") - }) - - t.Run("valid attestation passes verification", func(t *testing.T) { - inv, err := attest.Proof.Invoke(authority, authority.DID(), &attest.ProofArguments{Proof: dlg.Link()}) - require.NoError(t, err) - - err = verify(t.Context(), dlg, container.New(container.WithInvocations(inv))) - require.NoError(t, err) - }) - - t.Run("valid attestation found among invalid ones", func(t *testing.T) { - untrusted, err := attest.Proof.Invoke(other, other.DID(), &attest.ProofArguments{Proof: dlg.Link()}) - require.NoError(t, err) - wrongCmd, err := invocation.Invoke(authority, authority.DID(), command.MustParse("/some/other"), datamodel.Map{}) - require.NoError(t, err) - valid, err := attest.Proof.Invoke(authority, authority.DID(), &attest.ProofArguments{Proof: dlg.Link()}) - require.NoError(t, err) - - err = verify( - t.Context(), - dlg, - container.New(container.WithInvocations(untrusted, wrongCmd, valid)), - ) - require.NoError(t, err) - }) -} diff --git a/pkg/piriclient/client.go b/pkg/piriclient/client.go index a66a8be..e3c85db 100644 --- a/pkg/piriclient/client.go +++ b/pkg/piriclient/client.go @@ -31,25 +31,25 @@ const replicaAllocationTTL = time.Hour * 24 // Client is a UCAN client for communicating with Piri nodes. type Client struct { piriDID did.DID - signer ucan.Signer + issuer ucan.Issuer client *client.HTTPClient logger *zap.Logger } // New creates a new Piri client. // The delegationFetcher is used to fetch delegation proofs on-demand for each request. -func New(endpoint *url.URL, piriDID did.DID, signer ucan.Signer, logger *zap.Logger) (*Client, error) { +func New(endpoint *url.URL, piriDID did.DID, issuer ucan.Issuer, logger *zap.Logger) (*Client, error) { client, err := client.NewHTTP(endpoint) if err != nil { return nil, fmt.Errorf("creating HTTP client: %w", err) } - return NewWithClient(piriDID, signer, client, logger), nil + return NewWithClient(piriDID, issuer, client, logger), nil } -func NewWithClient(piriDID did.DID, signer ucan.Signer, client *client.HTTPClient, logger *zap.Logger) *Client { +func NewWithClient(piriDID did.DID, issuer ucan.Issuer, client *client.HTTPClient, logger *zap.Logger) *Client { return &Client{ piriDID: piriDID, - signer: signer, + issuer: issuer, client: client, logger: logger, } @@ -66,7 +66,7 @@ type AllocateRequest struct { // Allocate sends a /blob/allocate invocation to the piri node. // Returns the response data, the invocation that was sent, and the receipt from piri. func (c *Client) Allocate(ctx context.Context, req *AllocateRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (*blobcmds.AllocateOK, ucan.Invocation, ucan.Receipt, error) { - inv, prfs, attestations, err := c.AllocateInvocation(ctx, req, proofStore, options...) + inv, prfs, err := c.AllocateInvocation(ctx, req, proofStore, options...) if err != nil { return nil, nil, nil, fmt.Errorf("creating allocate invocation: %w", err) } @@ -75,7 +75,6 @@ func (c *Client) Allocate(ctx context.Context, req *AllocateRequest, proofStore zap.Stringer("issuer", inv.Issuer()), zap.Stringer("audience", inv.Audience()), zap.Int("proofs", len(prfs)), - zap.Int("attestations", len(attestations)), ) allocOK, rcpt, _, err := ucan_client.Execute[*blobcmds.AllocateOK]( @@ -84,7 +83,6 @@ func (c *Client) Allocate(ctx context.Context, req *AllocateRequest, proofStore c.logger, inv, execution.WithDelegations(prfs...), - execution.WithInvocations(attestations...), ) if err != nil { return nil, nil, nil, err @@ -93,18 +91,13 @@ func (c *Client) Allocate(ctx context.Context, req *AllocateRequest, proofStore } // AllocateInvocation returns the invocation for the allocate request (for use in effects). -func (c *Client) AllocateInvocation(ctx context.Context, req *AllocateRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (ucan.Invocation, []ucan.Delegation, []ucan.Invocation, error) { +func (c *Client) AllocateInvocation(ctx context.Context, req *AllocateRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (ucan.Invocation, []ucan.Delegation, error) { // The proof chain is rooted at the storage provider (the proofs the provider // granted the upload service at registration), so the subject is the provider // DID, not the space. The space rides in the invocation arguments instead. - prfs, prfLinks, err := proofStore.ProofChain(ctx, c.signer.DID(), blobcmds.Allocate.Command, c.piriDID) + prfs, prfLinks, err := proofStore.ProofChain(ctx, c.issuer.DID(), blobcmds.Allocate.Command, c.piriDID) if err != nil { - return nil, nil, nil, fmt.Errorf("building proof chain: %w", err) - } - - attestations, err := proofStore.ProofAttestations(ctx, prfs, c.signer.DID()) - if err != nil { - return nil, nil, nil, fmt.Errorf("getting proof attestations: %w", err) + return nil, nil, fmt.Errorf("building proof chain: %w", err) } options = slices.Clone(options) @@ -115,7 +108,7 @@ func (c *Client) AllocateInvocation(ctx context.Context, req *AllocateRequest, p ) inv, err := blobcmds.Allocate.Invoke( - c.signer, + c.issuer, c.piriDID, &blobcmds.AllocateArguments{ Space: req.Space, @@ -125,10 +118,10 @@ func (c *Client) AllocateInvocation(ctx context.Context, req *AllocateRequest, p options..., ) if err != nil { - return nil, nil, nil, fmt.Errorf("creating allocate invocation: %w", err) + return nil, nil, fmt.Errorf("creating allocate invocation: %w", err) } - return inv, prfs, attestations, nil + return inv, prfs, nil } // PiriDID returns the DID of the piri node. @@ -146,7 +139,7 @@ type AcceptRequest struct { // Accept sends a /blob/accept invocation to the piri node. func (c *Client) Accept(ctx context.Context, req *AcceptRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (*blobcmds.AcceptOK, ucan.Invocation, ucan.Receipt, ucan.Container, error) { - inv, prfs, attestations, err := c.AcceptInvocation(ctx, req, proofStore, options...) + inv, prfs, err := c.AcceptInvocation(ctx, req, proofStore, options...) if err != nil { return nil, nil, nil, nil, fmt.Errorf("creating accept invocation: %w", err) } @@ -155,7 +148,6 @@ func (c *Client) Accept(ctx context.Context, req *AcceptRequest, proofStore ucan zap.Stringer("issuer", inv.Issuer()), zap.Stringer("audience", inv.Audience()), zap.Int("proofs", len(prfs)), - zap.Int("attestations", len(attestations)), ) acceptOK, rcpt, meta, err := ucan_client.Execute[*blobcmds.AcceptOK]( @@ -164,7 +156,6 @@ func (c *Client) Accept(ctx context.Context, req *AcceptRequest, proofStore ucan c.logger, inv, execution.WithDelegations(prfs...), - execution.WithInvocations(attestations...), ) if err != nil { return nil, nil, nil, nil, err @@ -173,17 +164,12 @@ func (c *Client) Accept(ctx context.Context, req *AcceptRequest, proofStore ucan } // AcceptInvocation returns the invocation for the accept request (for use in effects). -func (c *Client) AcceptInvocation(ctx context.Context, req *AcceptRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (ucan.Invocation, []ucan.Delegation, []ucan.Invocation, error) { +func (c *Client) AcceptInvocation(ctx context.Context, req *AcceptRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (ucan.Invocation, []ucan.Delegation, error) { // As with allocate, the proof chain is rooted at the storage provider, so the // subject is the provider DID and the space travels in the arguments. - prfs, prfLinks, err := proofStore.ProofChain(ctx, c.signer.DID(), blobcmds.Accept.Command, c.piriDID) - if err != nil { - return nil, nil, nil, fmt.Errorf("building proof chain: %w", err) - } - - attestations, err := proofStore.ProofAttestations(ctx, prfs, c.signer.DID()) + prfs, prfLinks, err := proofStore.ProofChain(ctx, c.issuer.DID(), blobcmds.Accept.Command, c.piriDID) if err != nil { - return nil, nil, nil, fmt.Errorf("getting proof attestations: %w", err) + return nil, nil, fmt.Errorf("building proof chain: %w", err) } options = slices.Clone(options) @@ -194,7 +180,7 @@ func (c *Client) AcceptInvocation(ctx context.Context, req *AcceptRequest, proof ) inv, err := blobcmds.Accept.Invoke( - c.signer, + c.issuer, c.piriDID, &blobcmds.AcceptArguments{ Space: req.Space, @@ -204,10 +190,10 @@ func (c *Client) AcceptInvocation(ctx context.Context, req *AcceptRequest, proof options..., ) if err != nil { - return nil, nil, nil, fmt.Errorf("creating accept invocation: %w", err) + return nil, nil, fmt.Errorf("creating accept invocation: %w", err) } - return inv, prfs, attestations, nil + return inv, prfs, nil } // ReplicaAllocateRequest contains the parameters for a /blob/replica/allocate invocation. @@ -223,16 +209,11 @@ type ReplicaAllocateRequest struct { // Returns the response data, the invocation that was sent, the receipt from // piri, and any metadata. It returns an error if the receipt contains a failure result. func (c *Client) ReplicaAllocate(ctx context.Context, req *ReplicaAllocateRequest, proofStore ucanlib.ProofStore, options ...invocation.Option) (*blobreplicacmds.AllocateOK, ucan.Invocation, ucan.Receipt, ucan.Container, error) { - prfs, prfLinks, err := proofStore.ProofChain(ctx, c.signer.DID(), blobreplicacmds.Allocate.Command, req.Space) + prfs, prfLinks, err := proofStore.ProofChain(ctx, c.issuer.DID(), blobreplicacmds.Allocate.Command, req.Space) if err != nil { return nil, nil, nil, nil, fmt.Errorf("building proof chain: %w", err) } - attestations, err := proofStore.ProofAttestations(ctx, prfs, c.signer.DID()) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("getting proof attestations: %w", err) - } - options = slices.Clone(options) options = append( options, @@ -245,7 +226,7 @@ func (c *Client) ReplicaAllocate(ctx context.Context, req *ReplicaAllocateReques ) inv, err := blobreplicacmds.Allocate.Invoke( - c.signer, + c.issuer, req.Space, &blobreplicacmds.AllocateArguments{ Blob: blobcmds.Blob{Digest: req.Digest, Size: req.Size}, @@ -269,7 +250,6 @@ func (c *Client) ReplicaAllocate(ctx context.Context, req *ReplicaAllocateReques c.logger, inv, execution.WithDelegations(prfs...), - execution.WithInvocations(attestations...), ) if err != nil { return nil, nil, nil, nil, err diff --git a/pkg/piriclient/provider.go b/pkg/piriclient/provider.go index de5038b..fc7803f 100644 --- a/pkg/piriclient/provider.go +++ b/pkg/piriclient/provider.go @@ -15,18 +15,18 @@ type Provider interface { // PiriProvider is the default Provider that creates HTTP-connected piri clients. type PiriProvider struct { - signer ucan.Signer + issuer ucan.Issuer logger *zap.Logger } var _ Provider = (*PiriProvider)(nil) -func NewProvider(signer ucan.Signer, logger *zap.Logger) *PiriProvider { - return &PiriProvider{signer: signer, logger: logger} +func NewProvider(issuer ucan.Issuer, logger *zap.Logger) *PiriProvider { + return &PiriProvider{issuer: issuer, logger: logger} } // Client provides a client configured to communicate with the specified storage // node. func (p *PiriProvider) Client(id did.DID, endpoint url.URL) (*Client, error) { - return New(&endpoint, id, p.signer, p.logger) + return New(&endpoint, id, p.issuer, p.logger) } diff --git a/pkg/provisioning/service_test.go b/pkg/provisioning/service_test.go index 423ea0b..6df95d8 100644 --- a/pkg/provisioning/service_test.go +++ b/pkg/provisioning/service_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/store/consumer" diff --git a/pkg/routing/service_test.go b/pkg/routing/service_test.go index e7927b5..d362184 100644 --- a/pkg/routing/service_test.go +++ b/pkg/routing/service_test.go @@ -17,7 +17,7 @@ import ( func addProvider(t *testing.T, store *spmemory.Store, weight int, replicationWeight *int) storageprovider.Record { t.Helper() ctx := t.Context() - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) endpoint := testutil.Must(url.Parse("https://piri.example.com"))(t) err := store.Put(ctx, storageProvider.DID(), *endpoint, weight, replicationWeight, container.New()) require.NoError(t, err) @@ -44,7 +44,7 @@ func TestGetProviderInfo(t *testing.T) { t.Run("not found", func(t *testing.T) { store := spmemory.New() svc := routing.NewService(store, logger) - unknown := testutil.RandomSigner(t) + unknown := testutil.RandomIssuer(t) _, err := svc.GetProviderInfo(ctx, unknown.DID()) require.ErrorIs(t, err, storageprovider.ErrStorageProviderNotFound) diff --git a/pkg/service/handlers/access_claim.go b/pkg/service/handlers/access_claim.go index f54fa21..2b8ef44 100644 --- a/pkg/service/handlers/access_claim.go +++ b/pkg/service/handlers/access_claim.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/libforge/identity" delegation_store "github.com/fil-forge/sprue/pkg/store/delegation" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/server" @@ -14,7 +14,7 @@ import ( "go.uber.org/zap" ) -func NewAccessClaimHandler(id *identity.Identity, delegationStore delegation_store.Store, logger *zap.Logger) server.Route { +func NewAccessClaimHandler(id identity.Identity, delegationStore delegation_store.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", access.Claim)) return access.Claim.Route( func(req *binding.Request[*access.ClaimArguments], res *binding.Response[*access.ClaimOK]) error { diff --git a/pkg/service/handlers/access_claim_test.go b/pkg/service/handlers/access_claim_test.go index c69ff0e..3be0b53 100644 --- a/pkg/service/handlers/access_claim_test.go +++ b/pkg/service/handlers/access_claim_test.go @@ -24,19 +24,19 @@ func TestAccessClaimHandler(t *testing.T) { store := dlgmemory.New() handler := NewAccessClaimHandler(id, store, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) args := access.ClaimArguments{} inv, err := access.Claim.Invoke( agent, agent.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -52,7 +52,7 @@ func TestAccessClaimHandler(t *testing.T) { store := dlgmemory.New() handler := NewAccessClaimHandler(id, store, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) dlg, err := delegation.Delegate(testutil.Alice, agent.DID(), testutil.Alice.DID(), command.MustParse("/test/thing")) require.NoError(t, err) @@ -65,12 +65,12 @@ func TestAccessClaimHandler(t *testing.T) { agent, agent.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -86,7 +86,7 @@ func TestAccessClaimHandler(t *testing.T) { store := dlgmemory.New() handler := NewAccessClaimHandler(id, store, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) dlg1, err := delegation.Delegate(testutil.Alice, agent.DID(), testutil.Alice.DID(), command.MustParse("/test/one")) require.NoError(t, err) @@ -102,12 +102,12 @@ func TestAccessClaimHandler(t *testing.T) { agent, agent.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -124,8 +124,8 @@ func TestAccessClaimHandler(t *testing.T) { store := dlgmemory.New() handler := NewAccessClaimHandler(id, store, logger) - agent := testutil.RandomSigner(t) - otherAgent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) + otherAgent := testutil.RandomIssuer(t) // Delegation is for otherAgent, not agent. dlg, err := delegation.Delegate(testutil.Alice, otherAgent.DID(), testutil.Alice.DID(), command.MustParse("/test/thing")) @@ -139,12 +139,12 @@ func TestAccessClaimHandler(t *testing.T) { agent, agent.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/access_confirm.go b/pkg/service/handlers/access_confirm.go index 017bd40..b69c993 100644 --- a/pkg/service/handlers/access_confirm.go +++ b/pkg/service/handlers/access_confirm.go @@ -3,32 +3,31 @@ package handlers import ( "fmt" + "github.com/ipfs/go-cid" + "go.uber.org/zap" + + "github.com/fil-forge/libforge/attestation" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/libforge/commands/ucan/attest" - "github.com/fil-forge/libforge/didmailto" - "github.com/fil-forge/sprue/pkg/identity" - delegation_store "github.com/fil-forge/sprue/pkg/store/delegation" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/ipld" "github.com/fil-forge/ucantone/ipld/datamodel" - "github.com/fil-forge/ucantone/principal/absentee" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/command" "github.com/fil-forge/ucantone/ucan/container" "github.com/fil-forge/ucantone/ucan/delegation" - "github.com/fil-forge/ucantone/ucan/invocation" - "github.com/ipfs/go-cid" - "go.uber.org/zap" + + delegation_store "github.com/fil-forge/sprue/pkg/store/delegation" ) -func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_store.Store, logger *zap.Logger) server.Route { +func NewAccessConfirmHandler(id identity.Identity, delegationStore delegation_store.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", access.Confirm)) return access.Confirm.Route( func(req *binding.Request[*access.ConfirmArguments], res *binding.Response[*access.ConfirmOK]) error { args := req.Task().Arguments() - if req.Invocation().Subject() != id.Signer.DID() { + if req.Invocation().Subject() != id.DID() { log.Warn("not a valid invocation", zap.Stringer("subject", req.Invocation().Subject())) return res.SetFailure(access.ErrInvalidAccessConfirmSubject) } @@ -39,8 +38,7 @@ func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_s return res.SetFailure(access.ErrInvalidAccessConfirmIssuer) } - // Create a absentee signer for the account that authorized the delegation - account := absentee.From(accountDID) + account := attestation.Attest(req.Context(), accountDID, id) agent := args.Audience cmds := make([]string, 0, len(args.Attenuations)) @@ -50,15 +48,14 @@ func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_s log := log.With( zap.Stringer("agent", agent), - zap.Stringer("account", account.DID()), + zap.Stringer("account", account), zap.Stringer("cause", args.Cause), zap.Strings("commands", cmds), ) log.Debug("confirming access") // Create session proofs - delegations, attestations, err := createSessionProofs( - id.Signer, + delegations, _, err := createSessionProofs( account, agent, args.Attenuations, @@ -72,15 +69,11 @@ func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_s } links := make([]cid.Cid, 0, len(delegations)) - tokens := make([]ucan.Token, 0, len(delegations)+len(attestations)) + tokens := make([]ucan.Token, 0, len(delegations)) for _, d := range delegations { tokens = append(tokens, d) links = append(links, d.Link()) } - for _, a := range attestations { - tokens = append(tokens, a) - } - // Store the delegations so that they can be pulled during /access/claim. // Since there is no invocation that contains these delegations, don't pass // a `cause` parameter. @@ -92,10 +85,9 @@ func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_s return fmt.Errorf("storing delegations: %w", err) } - // Include the delegations and attestations in the response metadata. + // Include the delegations in the response metadata. res.SetMetadata(container.New( container.WithDelegations(delegations...), - container.WithInvocations(attestations...), )) return res.SetSuccess(&access.ConfirmOK{Delegations: links}) @@ -103,14 +95,12 @@ func NewAccessConfirmHandler(id *identity.Identity, delegationStore delegation_s ) } -// createSessionProofs creates delegations from the account to the agent, and -// attestations from the service to the agent referencing those delegations. +// createSessionProofs creates delegations from the account to the agent. func createSessionProofs( - service ucan.Signer, - account absentee.Signer, + account ucan.Issuer, agent did.DID, attenuations []access.CapabilityRequest, - meta ipld.Map, + meta datamodel.Map, ) ([]ucan.Delegation, []ucan.Invocation, error) { delegations := make([]ucan.Delegation, 0, len(attenuations)) attestations := make([]ucan.Invocation, 0, len(attenuations)) @@ -131,22 +121,6 @@ func createSessionProofs( } delegations = append(delegations, accountDlg) - // Need to attest as mailto DIDs cannot sign. - claimAttestation, err := attest.Proof.Invoke( - service, - service.DID(), - &attest.ProofArguments{ - Proof: accountDlg.Link(), - }, - invocation.WithAudience(agent), - invocation.WithMetadata(meta), - invocation.WithNoExpiration(), - ) - if err != nil { - return nil, nil, fmt.Errorf("creating attestation: %w", err) - } - attestations = append(attestations, claimAttestation) - for _, req := range attenuations { dlg, err := delegation.Delegate( account, @@ -164,21 +138,6 @@ func createSessionProofs( return nil, nil, fmt.Errorf("creating delegation: %w", err) } delegations = append(delegations, dlg) - - attestation, err := attest.Proof.Invoke( - service, - service.DID(), - &attest.ProofArguments{ - Proof: dlg.Link(), - }, - invocation.WithAudience(agent), - invocation.WithMetadata(meta), - invocation.WithNoExpiration(), - ) - if err != nil { - return nil, nil, fmt.Errorf("creating attestation: %w", err) - } - attestations = append(attestations, attestation) } return delegations, attestations, nil diff --git a/pkg/service/handlers/access_confirm_test.go b/pkg/service/handlers/access_confirm_test.go index cf65dea..a6ae919 100644 --- a/pkg/service/handlers/access_confirm_test.go +++ b/pkg/service/handlers/access_confirm_test.go @@ -3,28 +3,46 @@ package handlers import ( "testing" + "github.com/fil-forge/libforge/attestation" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" dlgmemory "github.com/fil-forge/sprue/pkg/store/delegation/memory" + "github.com/fil-forge/ucantone/did" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" "github.com/fil-forge/ucantone/execution" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/command" "github.com/fil-forge/ucantone/ucan/invocation" + "github.com/fil-forge/ucantone/validator" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) func TestAccessConfirmHandler(t *testing.T) { logger := zaptest.NewLogger(t) + id := newTestIdentity(t) + + resolver := resolver.ByMethod{ + "key": key.Resolver, + "mailto": didmailto.NewResolver(id.DID()), + } + factories := validator.DefaultFactories() + factories[attestation.Type] = attestation.NewVerifierFactory(resolver, factories) + validationOpts := []validator.Option{ + validator.WithDIDResolver(resolver), + validator.WithVerifierFactories(factories), + } + ctx := t.Context() t.Run("wrong subject", func(t *testing.T) { - id := newTestIdentity(t) store := dlgmemory.New() handler := NewAccessConfirmHandler(id, store, logger) account := testutil.Must(didmailto.New("alice@example.com"))(t) - agent := testutil.RandomSigner(t) - notService := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) + notService := testutil.RandomIssuer(t) args := access.ConfirmArguments{ Cause: testutil.RandomCID(t), @@ -37,15 +55,15 @@ func TestAccessConfirmHandler(t *testing.T) { // Subject is not id.Signer — handler should reject. inv, err := access.Confirm.Invoke( - id.Signer, + id.Issuer, notService.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) - req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + req := execution.NewRequest(ctx, inv) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -56,13 +74,12 @@ func TestAccessConfirmHandler(t *testing.T) { }) t.Run("invalid issuer DID", func(t *testing.T) { - id := newTestIdentity(t) store := dlgmemory.New() handler := NewAccessConfirmHandler(id, store, logger) // A did:key (not a did:mailto) — didmailto.Parse will reject it. - nonMailto := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + nonMailto := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) args := access.ConfirmArguments{ Cause: testutil.RandomCID(t), @@ -74,15 +91,15 @@ func TestAccessConfirmHandler(t *testing.T) { } inv, err := access.Confirm.Invoke( - id.Signer, - id.Signer.DID(), + id.Issuer, + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) - req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + req := execution.NewRequest(ctx, inv) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -93,12 +110,11 @@ func TestAccessConfirmHandler(t *testing.T) { }) t.Run("success", func(t *testing.T) { - id := newTestIdentity(t) store := dlgmemory.New() handler := NewAccessConfirmHandler(id, store, logger) account := testutil.Must(didmailto.New("bob@example.com"))(t) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) args := access.ConfirmArguments{ Cause: testutil.RandomCID(t), @@ -110,15 +126,15 @@ func TestAccessConfirmHandler(t *testing.T) { } inv, err := access.Confirm.Invoke( - id.Signer, - id.Signer.DID(), + id.Issuer, + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) - req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + req := execution.NewRequest(ctx, inv) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -127,23 +143,51 @@ func TestAccessConfirmHandler(t *testing.T) { ok, err := access.Confirm.Unpack(res.Receipt()) require.NoError(t, err) - // One delegation link per attenuation + one account delegation + // One account delegation + one delegation per attenuation require.Len(t, ok.Delegations, 2) - // Store holds the delegation and its attestation, the account delegation - // and it's attestation all keyed by the agent. - page, err := store.ListByAudience(t.Context(), agent.DID()) + page, err := store.ListByAudience(ctx, agent.DID()) + require.NoError(t, err) + require.Len(t, page.Results, 2) + + var accountDlg, powerlineDlg ucan.Delegation + for _, tok := range page.Results { + dlg, isDlg := tok.(ucan.Delegation) + require.True(t, isDlg, "stored token should be a delegation") + if dlg.Subject() == account { + accountDlg = dlg + } else { + powerlineDlg = dlg + } + } + require.NotNil(t, accountDlg, "should have an account delegation") + require.NotNil(t, powerlineDlg, "should have a powerline delegation") + + require.Equal(t, account, accountDlg.Issuer()) + require.Equal(t, agent.DID(), accountDlg.Audience()) + require.Equal(t, account, accountDlg.Subject()) + require.Equal(t, command.Top(), accountDlg.Command()) + + // The powerline delegation should be the one we expected + require.Equal(t, account, powerlineDlg.Issuer()) + require.Equal(t, agent.DID(), powerlineDlg.Audience()) + require.Equal(t, did.Undef, powerlineDlg.Subject()) + require.Equal(t, command.Top(), powerlineDlg.Command()) + require.Len(t, powerlineDlg.Policy().Statements(), 0) + + // Both delegations should be valid + err = validator.ValidateToken(ctx, accountDlg, validationOpts...) + require.NoError(t, err) + err = validator.ValidateToken(ctx, powerlineDlg, validationOpts...) require.NoError(t, err) - require.Len(t, page.Results, 4) }) t.Run("multiple capabilities", func(t *testing.T) { - id := newTestIdentity(t) store := dlgmemory.New() handler := NewAccessConfirmHandler(id, store, logger) account := testutil.Must(didmailto.New("carol@example.com"))(t) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) args := access.ConfirmArguments{ Cause: testutil.RandomCID(t), @@ -156,15 +200,15 @@ func TestAccessConfirmHandler(t *testing.T) { } inv, err := access.Confirm.Invoke( - id.Signer, - id.Signer.DID(), + id.Issuer, + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) - req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + req := execution.NewRequest(ctx, inv) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -173,13 +217,44 @@ func TestAccessConfirmHandler(t *testing.T) { ok, err := access.Confirm.Unpack(res.Receipt()) require.NoError(t, err) - // One delegation link per attenuation + one account delegation + // One account delegation + one delegation per attenuation require.Len(t, ok.Delegations, 3) - // Two attenuations → two delegations and two attestations, plus one account - // delegation and its attestation stored. - page, err := store.ListByAudience(t.Context(), agent.DID()) + page, err := store.ListByAudience(ctx, agent.DID()) + require.NoError(t, err) + require.Len(t, page.Results, 3) + + // Separate the account delegation from the powerline delegations. + var blobDlg, uploadDlg ucan.Delegation + for _, tok := range page.Results { + dlg, isDlg := tok.(ucan.Delegation) + require.True(t, isDlg, "stored token should be a delegation") + if dlg.Subject() == account { + continue // account delegation; skip detailed checks here + } + if dlg.Command() == command.MustParse("/blob/add") { + blobDlg = dlg + } else if dlg.Command() == command.MustParse("/upload/add") { + uploadDlg = dlg + } + } + require.NotNil(t, blobDlg, "should have a /blob/add delegation") + require.NotNil(t, uploadDlg, "should have an /upload/add delegation") + + require.Equal(t, account, blobDlg.Issuer()) + require.Equal(t, agent.DID(), blobDlg.Audience()) + require.Equal(t, did.Undef, blobDlg.Subject()) + require.Equal(t, command.MustParse("/blob/add"), blobDlg.Command()) + require.Len(t, blobDlg.Policy().Statements(), 0) + err = validator.ValidateToken(ctx, blobDlg, validationOpts...) + require.NoError(t, err) + + require.Equal(t, account, uploadDlg.Issuer()) + require.Equal(t, agent.DID(), uploadDlg.Audience()) + require.Equal(t, did.Undef, uploadDlg.Subject()) + require.Equal(t, command.MustParse("/upload/add"), uploadDlg.Command()) + require.Len(t, uploadDlg.Policy().Statements(), 0) + err = validator.ValidateToken(ctx, uploadDlg, validationOpts...) require.NoError(t, err) - require.Len(t, page.Results, 6) }) } diff --git a/pkg/service/handlers/access_delegate_test.go b/pkg/service/handlers/access_delegate_test.go index 97910c4..c644058 100644 --- a/pkg/service/handlers/access_delegate_test.go +++ b/pkg/service/handlers/access_delegate_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" accesscmds "github.com/fil-forge/libforge/commands/access" blobcmds "github.com/fil-forge/libforge/commands/blob" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/provisioning" consumermemory "github.com/fil-forge/sprue/pkg/store/consumer/memory" @@ -61,8 +61,8 @@ func TestAccessDelegateHandler(t *testing.T) { ps := newTestProvisioningService(t, nil) handler := NewAccessDelegateHandler(dlgStore, ps, logger) - agent := testutil.RandomSigner(t) - space := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) + space := testutil.RandomIssuer(t) args := accesscmds.DelegateArguments{Delegations: []cid.Cid{}} @@ -70,12 +70,12 @@ func TestAccessDelegateHandler(t *testing.T) { agent, space.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -91,12 +91,12 @@ func TestAccessDelegateHandler(t *testing.T) { id := newTestIdentity(t) dlgStore := dlgmemory.New() - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) - ps := newProvisionedService(t, id.Signer.DID(), space.DID()) + ps := newProvisionedService(t, id.Issuer.DID(), space.DID()) handler := NewAccessDelegateHandler(dlgStore, ps, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) // Create a delegation from the space to the agent for some capability. dlg, err := delegation.Delegate(space, agent.DID(), space.DID(), command.MustParse("/blob/add")) @@ -110,13 +110,13 @@ func TestAccessDelegateHandler(t *testing.T) { agent, space.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) // Attach the delegation to the request metadata so extractDelegations can find it. req := execution.NewRequest(t.Context(), inv, execution.WithDelegations(dlg)) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -134,12 +134,12 @@ func TestAccessDelegateHandler(t *testing.T) { id := newTestIdentity(t) dlgStore := dlgmemory.New() - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) - ps := newProvisionedService(t, id.Signer.DID(), space.DID()) + ps := newProvisionedService(t, id.Issuer.DID(), space.DID()) handler := NewAccessDelegateHandler(dlgStore, ps, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) args := accesscmds.DelegateArguments{Delegations: []cid.Cid{}} @@ -147,12 +147,12 @@ func TestAccessDelegateHandler(t *testing.T) { agent, space.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -165,12 +165,12 @@ func TestAccessDelegateHandler(t *testing.T) { id := newTestIdentity(t) dlgStore := dlgmemory.New() - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) - ps := newProvisionedService(t, id.Signer.DID(), space.DID()) + ps := newProvisionedService(t, id.Issuer.DID(), space.DID()) handler := NewAccessDelegateHandler(dlgStore, ps, logger) - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) // Reference a delegation by CID, but don't include it in the request metadata. // We still need at least one delegation in the request so req.Metadata() is non-nil. @@ -188,12 +188,12 @@ func TestAccessDelegateHandler(t *testing.T) { agent, space.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv, execution.WithDelegations(other)) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) // extractDelegations returns an error directly (not via SetFailure) when a diff --git a/pkg/service/handlers/access_request.go b/pkg/service/handlers/access_request.go index 5b3ae89..2b53dcc 100644 --- a/pkg/service/handlers/access_request.go +++ b/pkg/service/handlers/access_request.go @@ -8,10 +8,11 @@ import ( "go.uber.org/zap" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/sprue/pkg/mailer" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" @@ -33,7 +34,7 @@ var ( ErrInvalidAuthorizationAudience = errors.New(access.InvalidAuthorizationAudienceErrorName, "invalid authorization audience DID") ) -func NewAccessRequestHandler(serverCfg config.ServerConfig, id *identity.Identity, mailer mailer.Mailer, logger *zap.Logger) server.Route { +func NewAccessRequestHandler(serverCfg config.ServerConfig, id identity.Identity, mailer mailer.Mailer, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", access.Request)) return access.Request.Route( func(req *binding.Request[*access.RequestArguments], res *binding.Response[*access.RequestOK]) error { @@ -82,8 +83,8 @@ func NewAccessRequestHandler(serverCfg config.ServerConfig, id *identity.Identit // surface where an attacker could attempt concurrent authorization // requests in an attempt to confuse a user into clicking the wrong link. confirmation, err := access.Confirm.Invoke( - id.Signer, - id.Signer.DID(), + id.Issuer, + id.Issuer.DID(), // We link to the authorization request so that this invocation can // not be used to authorize a different request. &access.ConfirmArguments{ @@ -98,7 +99,7 @@ func NewAccessRequestHandler(serverCfg config.ServerConfig, id *identity.Identit // audience same as issuer because this is a service invocation // that will get handled by /access/confirm handler // but only if the receiver of this email wants it to be - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), invocation.WithExpiration(ucan.UnixTimestamp(exp)), // we copy the facts in so that information can be passed // from the invoker of this capability to the invoker of the confirm diff --git a/pkg/service/handlers/access_request_test.go b/pkg/service/handlers/access_request_test.go index f2db11a..560723c 100644 --- a/pkg/service/handlers/access_request_test.go +++ b/pkg/service/handlers/access_request_test.go @@ -6,11 +6,12 @@ import ( "net/url" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands/access" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/config" "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" "github.com/fil-forge/ucantone/ucan/command" @@ -31,9 +32,9 @@ func (m *mockMailer) SendValidation(ctx context.Context, to string, validationUR return m.err } -func newTestIdentity(t *testing.T) *identity.Identity { +func newTestIdentity(t *testing.T) identity.Identity { t.Helper() - id, err := identity.New("") + id, err := identity.New("", "") require.NoError(t, err) return id } @@ -61,18 +62,18 @@ func TestAccessRequestHandler(t *testing.T) { }, } - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) inv, err := access.Request.Invoke( agent, - id.Signer.DID(), + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -94,7 +95,7 @@ func TestAccessRequestHandler(t *testing.T) { handler := NewAccessRequestHandler(serverCfg, id, m, logger) // A did:key (not did:mailto) — didmailto.Parse will reject it. - nonMailtoSigner := testutil.RandomSigner(t) + nonMailtoSigner := testutil.RandomIssuer(t) args := access.RequestArguments{ Issuer: nonMailtoSigner.DID(), Attenuations: []access.CapabilityRequest{ @@ -102,18 +103,18 @@ func TestAccessRequestHandler(t *testing.T) { }, } - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) inv, err := access.Request.Invoke( agent, - id.Signer.DID(), + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -140,18 +141,18 @@ func TestAccessRequestHandler(t *testing.T) { }, } - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) inv, err := access.Request.Invoke( agent, - id.Signer.DID(), + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) @@ -178,18 +179,18 @@ func TestAccessRequestHandler(t *testing.T) { }, } - agent := testutil.RandomSigner(t) + agent := testutil.RandomIssuer(t) inv, err := access.Request.Invoke( agent, - id.Signer.DID(), + id.Issuer.DID(), &args, - invocation.WithAudience(id.Signer.DID()), + invocation.WithAudience(id.Issuer.DID()), ) require.NoError(t, err) req := execution.NewRequest(t.Context(), inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(id.Signer)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(id.Issuer)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/admin_provider_deregister.go b/pkg/service/handlers/admin_provider_deregister.go index 516ed82..4155a6c 100644 --- a/pkg/service/handlers/admin_provider_deregister.go +++ b/pkg/service/handlers/admin_provider_deregister.go @@ -1,8 +1,8 @@ package handlers import ( + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" @@ -10,13 +10,13 @@ import ( "go.uber.org/zap" ) -func NewAdminProviderDeregisterHandler(id *identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { +func NewAdminProviderDeregisterHandler(id identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", provider.Deregister)) return provider.Deregister.Route( func(req *binding.Request[*provider.DeregisterArguments], res *binding.Response[*provider.DeregisterOK]) error { args := req.Task().Arguments() - if req.Invocation().Issuer() != id.Signer.DID() { + if req.Invocation().Issuer() != id.Issuer.DID() { log.Warn("Unauthorized access attempt", zap.Stringer("issuer", req.Invocation().Issuer())) return res.SetFailure(errors.New("Unauthorized", "only the service identity can deregister a provider")) } diff --git a/pkg/service/handlers/admin_provider_deregister_test.go b/pkg/service/handlers/admin_provider_deregister_test.go index fd83bbb..4080bc9 100644 --- a/pkg/service/handlers/admin_provider_deregister_test.go +++ b/pkg/service/handlers/admin_provider_deregister_test.go @@ -5,9 +5,9 @@ import ( "testing" blobcmds "github.com/fil-forge/libforge/commands/blob" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service/handlers" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" storage_provider_store "github.com/fil-forge/sprue/pkg/store/storage_provider/memory" @@ -23,7 +23,7 @@ import ( func issueDeregisterInvocation( t *testing.T, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, args provider.DeregisterArguments, ) execution.Request { @@ -50,11 +50,11 @@ func TestAdminProviderDeregisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderDeregisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) - unauthorizedIssuer := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) + unauthorizedIssuer := testutil.RandomIssuer(t) // Pre-populate the store so we can verify the record is NOT removed. endpoint, err := url.Parse("https://piri.example.com") @@ -67,7 +67,7 @@ func TestAdminProviderDeregisterHandler(t *testing.T) { } req := issueDeregisterInvocation(t, unauthorizedIssuer, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -87,10 +87,10 @@ func TestAdminProviderDeregisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderDeregisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) endpoint, err := url.Parse("https://piri.example.com") require.NoError(t, err) @@ -102,7 +102,7 @@ func TestAdminProviderDeregisterHandler(t *testing.T) { } req := issueDeregisterInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -118,17 +118,17 @@ func TestAdminProviderDeregisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderDeregisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) args := provider.DeregisterArguments{ Provider: storageProvider.DID(), } req := issueDeregisterInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/admin_provider_list.go b/pkg/service/handlers/admin_provider_list.go index 5c6cfce..d89c25a 100644 --- a/pkg/service/handlers/admin_provider_list.go +++ b/pkg/service/handlers/admin_provider_list.go @@ -5,8 +5,8 @@ import ( "go.uber.org/zap" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/store" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" "github.com/fil-forge/ucantone/binding" @@ -14,11 +14,11 @@ import ( "github.com/fil-forge/ucantone/server" ) -func NewAdminProviderListHandler(id *identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { +func NewAdminProviderListHandler(id identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", provider.List)) return provider.List.Route( func(req *binding.Request[*provider.ListArguments], res *binding.Response[*provider.ListOK]) error { - if req.Invocation().Issuer() != id.Signer.DID() { + if req.Invocation().Issuer() != id.Issuer.DID() { log.Warn("Unauthorized access attempt", zap.Stringer("issuer", req.Invocation().Issuer())) return res.SetFailure(errors.New("Unauthorized", "only the service identity can list providers")) } diff --git a/pkg/service/handlers/admin_provider_list_test.go b/pkg/service/handlers/admin_provider_list_test.go index 8ac4b77..a4be43f 100644 --- a/pkg/service/handlers/admin_provider_list_test.go +++ b/pkg/service/handlers/admin_provider_list_test.go @@ -4,9 +4,9 @@ import ( "net/url" "testing" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service/handlers" storage_provider_store "github.com/fil-forge/sprue/pkg/store/storage_provider/memory" "github.com/fil-forge/ucantone/did" @@ -21,7 +21,7 @@ import ( func issueListInvocation( t *testing.T, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, ) execution.Request { t.Helper() @@ -48,13 +48,13 @@ func TestAdminProviderListHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderListHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - unauthorizedIssuer := testutil.RandomSigner(t) + unauthorizedIssuer := testutil.RandomIssuer(t) req := issueListInvocation(t, unauthorizedIssuer, uploadService.DID()) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -70,11 +70,11 @@ func TestAdminProviderListHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderListHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) req := issueListInvocation(t, uploadService, uploadService.DID()) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -89,11 +89,11 @@ func TestAdminProviderListHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderListHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - sp1 := testutil.RandomSigner(t) - sp2 := testutil.RandomSigner(t) + sp1 := testutil.RandomIssuer(t) + sp2 := testutil.RandomIssuer(t) endpoint1, err := url.Parse("https://piri-1.example.com") require.NoError(t, err) @@ -105,7 +105,7 @@ func TestAdminProviderListHandler(t *testing.T) { require.NoError(t, spStore.Put(ctx, sp2.DID(), *endpoint2, 200, nil, container.New())) req := issueListInvocation(t, uploadService, uploadService.DID()) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/admin_provider_register.go b/pkg/service/handlers/admin_provider_register.go index 3e6a165..886beb1 100644 --- a/pkg/service/handlers/admin_provider_register.go +++ b/pkg/service/handlers/admin_provider_register.go @@ -6,9 +6,9 @@ import ( blobcmds "github.com/fil-forge/libforge/commands/blob" replicacmds "github.com/fil-forge/libforge/commands/blob/replica" pdpcmds "github.com/fil-forge/libforge/commands/pdp" + "github.com/fil-forge/libforge/identity" ucanlib "github.com/fil-forge/libforge/ucan" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" @@ -32,12 +32,12 @@ var requiredProofs = []ucan.Command{ pdpcmds.Info.Command, } -func NewAdminProviderRegisterHandler(id *identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { +func NewAdminProviderRegisterHandler(id identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", provider.Register)) return provider.Register.Route( func(req *binding.Request[*provider.RegisterArguments], res *binding.Response[*provider.RegisterOK]) error { args := req.Task().Arguments() - if req.Invocation().Issuer() != id.Signer.DID() { + if req.Invocation().Issuer() != id.Issuer.DID() { log.Warn("Unauthorized access attempt", zap.Stringer("issuer", req.Invocation().Issuer())) return res.SetFailure(errors.New("Unauthorized", "only the service identity can register providers")) } @@ -58,7 +58,7 @@ func NewAdminProviderRegisterHandler(id *identity.Identity, providerStore storag // provider (subject) to the service (audience). proofStore := ucanlib.NewContainerProofStore(proofs) for _, cmd := range requiredProofs { - chain, _, err := proofStore.ProofChain(req.Context(), id.Signer.DID(), cmd, args.Provider) + chain, _, err := proofStore.ProofChain(req.Context(), id.Issuer.DID(), cmd, args.Provider) if err != nil { log.Error("Failed to build proof chain", zap.Stringer("command", cmd), zap.Error(err)) return res.SetFailure(errors.New("InvalidProofs", "building proof chain for %s: %s", cmd, err.Error())) diff --git a/pkg/service/handlers/admin_provider_register_test.go b/pkg/service/handlers/admin_provider_register_test.go index 17c53c9..2257c93 100644 --- a/pkg/service/handlers/admin_provider_register_test.go +++ b/pkg/service/handlers/admin_provider_register_test.go @@ -6,9 +6,9 @@ import ( blobcmds "github.com/fil-forge/libforge/commands/blob" replicacmds "github.com/fil-forge/libforge/commands/blob/replica" pdpcmds "github.com/fil-forge/libforge/commands/pdp" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/commands/admin/provider" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service/handlers" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" storage_provider_store "github.com/fil-forge/sprue/pkg/store/storage_provider/memory" @@ -36,11 +36,11 @@ var requiredProofCommands = []ucan.Command{ // registerProofs returns an encoded UCAN container delegating the required // allocation capabilities from the provider to the upload service, as expected // by the register handler. -func registerProofs(t *testing.T, providerSigner ucan.Signer, audience did.DID) []byte { +func registerProofs(t *testing.T, providerIssuer ucan.Issuer, audience did.DID) []byte { t.Helper() dlgs := make([]ucan.Delegation, 0, len(requiredProofCommands)) for _, cmd := range requiredProofCommands { - dlg, err := delegation.Delegate(providerSigner, audience, providerSigner.DID(), cmd) + dlg, err := delegation.Delegate(providerIssuer, audience, providerIssuer.DID(), cmd) require.NoError(t, err) dlgs = append(dlgs, dlg) } @@ -52,7 +52,7 @@ func registerProofs(t *testing.T, providerSigner ucan.Signer, audience did.DID) // issueRegisterInvocation creates an admin/provider/register invocation request func issueRegisterInvocation( t *testing.T, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, args provider.RegisterArguments, ) execution.Request { @@ -79,11 +79,11 @@ func TestAdminProviderRegisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderRegisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) - unauthorizedIssuer := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) + unauthorizedIssuer := testutil.RandomIssuer(t) args := provider.RegisterArguments{ Provider: storageProvider.DID(), @@ -92,7 +92,7 @@ func TestAdminProviderRegisterHandler(t *testing.T) { // Issuer is neither the service nor the provider req := issueRegisterInvocation(t, unauthorizedIssuer, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -108,10 +108,10 @@ func TestAdminProviderRegisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderRegisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) args := provider.RegisterArguments{ Provider: storageProvider.DID(), @@ -121,7 +121,7 @@ func TestAdminProviderRegisterHandler(t *testing.T) { // First registration by service identity (authorized) req := issueRegisterInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -131,7 +131,7 @@ func TestAdminProviderRegisterHandler(t *testing.T) { // Second registration should fail req2 := issueRegisterInvocation(t, uploadService, uploadService.DID(), args) - res2, err := execution.NewResponse(req2.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res2, err := execution.NewResponse(req2.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req2, res2) @@ -148,10 +148,10 @@ func TestAdminProviderRegisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderRegisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) // Delegate only /blob/allocate, omitting /blob/accept and // /blob/replica/allocate. @@ -167,7 +167,7 @@ func TestAdminProviderRegisterHandler(t *testing.T) { } req := issueRegisterInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -187,10 +187,10 @@ func TestAdminProviderRegisterHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderRegisterHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) args := provider.RegisterArguments{ Provider: storageProvider.DID(), @@ -199,7 +199,7 @@ func TestAdminProviderRegisterHandler(t *testing.T) { } req := issueRegisterInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/admin_provider_weight_set.go b/pkg/service/handlers/admin_provider_weight_set.go index cb043c7..9dd01a6 100644 --- a/pkg/service/handlers/admin_provider_weight_set.go +++ b/pkg/service/handlers/admin_provider_weight_set.go @@ -3,20 +3,20 @@ package handlers import ( "go.uber.org/zap" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/pkg/commands/admin/provider/weight" - "github.com/fil-forge/sprue/pkg/identity" storageprovider "github.com/fil-forge/sprue/pkg/store/storage_provider" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" "github.com/fil-forge/ucantone/server" ) -func NewAdminProviderWeightSetHandler(id *identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { +func NewAdminProviderWeightSetHandler(id identity.Identity, providerStore storageprovider.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", weight.Set)) return weight.Set.Route( func(req *binding.Request[*weight.SetArguments], res *binding.Response[*weight.SetOK]) error { args := req.Task().Arguments() - if req.Invocation().Issuer() != id.Signer.DID() { + if req.Invocation().Issuer() != id.Issuer.DID() { log.Warn("Unauthorized access attempt", zap.Stringer("issuer", req.Invocation().Issuer())) return res.SetFailure(errors.New("Unauthorized", "only the service identity can set provider weights")) } diff --git a/pkg/service/handlers/admin_provider_weight_set_test.go b/pkg/service/handlers/admin_provider_weight_set_test.go index 70407e5..37aeb1b 100644 --- a/pkg/service/handlers/admin_provider_weight_set_test.go +++ b/pkg/service/handlers/admin_provider_weight_set_test.go @@ -5,9 +5,9 @@ import ( "testing" blobcmds "github.com/fil-forge/libforge/commands/blob" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/commands/admin/provider/weight" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service/handlers" storage_provider_store "github.com/fil-forge/sprue/pkg/store/storage_provider/memory" "github.com/fil-forge/ucantone/did" @@ -22,7 +22,7 @@ import ( func issueWeightSetInvocation( t *testing.T, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, args weight.SetArguments, ) execution.Request { @@ -49,11 +49,11 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderWeightSetHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) - unauthorizedIssuer := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) + unauthorizedIssuer := testutil.RandomIssuer(t) args := weight.SetArguments{ Provider: storageProvider.DID(), @@ -62,7 +62,7 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { } req := issueWeightSetInvocation(t, unauthorizedIssuer, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -78,10 +78,10 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderWeightSetHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) args := weight.SetArguments{ Provider: storageProvider.DID(), @@ -90,7 +90,7 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { } req := issueWeightSetInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -106,10 +106,10 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { spStore := storage_provider_store.New() handler := handlers.NewAdminProviderWeightSetHandler( - &identity.Identity{Signer: uploadService}, spStore, logger, + identity.Identity{Issuer: uploadService}, spStore, logger, ) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) endpoint, err := url.Parse("https://piri.example.com") require.NoError(t, err) @@ -125,7 +125,7 @@ func TestAdminProviderWeightSetHandler(t *testing.T) { } req := issueWeightSetInvocation(t, uploadService, uploadService.DID(), args) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/blob_add.go b/pkg/service/handlers/blob_add.go index 901affe..11b3d80 100644 --- a/pkg/service/handlers/blob_add.go +++ b/pkg/service/handlers/blob_add.go @@ -10,8 +10,8 @@ import ( blobcmds "github.com/fil-forge/libforge/commands/blob" httpcmds "github.com/fil-forge/libforge/commands/http" "github.com/fil-forge/libforge/digestutil" + "github.com/fil-forge/libforge/identity" ucanlib "github.com/fil-forge/libforge/ucan" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/piriclient" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/routing" @@ -21,8 +21,8 @@ import ( "github.com/fil-forge/ucantone/did" "github.com/fil-forge/ucantone/errors" "github.com/fil-forge/ucantone/ipld/datamodel" - "github.com/fil-forge/ucantone/principal" - ed25519signer "github.com/fil-forge/ucantone/principal/ed25519" + "github.com/fil-forge/ucantone/multikey" + ed25519signer "github.com/fil-forge/ucantone/multikey/ed25519" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" @@ -34,7 +34,7 @@ import ( "go.uber.org/zap" ) -func NewBlobAddHandler(id *identity.Identity, provisioningSvc *provisioning.Service, router *routing.Service, nodeProvider piriclient.Provider, agentStore agent.Store, blobRegistry blobregistry.Store, logger *zap.Logger) server.Route { +func NewBlobAddHandler(id identity.Identity, provisioningSvc *provisioning.Service, router *routing.Service, nodeProvider piriclient.Provider, agentStore agent.Store, blobRegistry blobregistry.Store, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", blobcmds.Add)) return blobcmds.Add.Route( func(req *binding.Request[*blobcmds.AddArguments], res *binding.Response[*blobcmds.AddOK]) error { @@ -326,12 +326,16 @@ func genPut(blob blobcmds.Blob, allocInv ucan.Invocation, allocOK blobcmds.Alloc // Derives did:key principal from (blob) multihash that can be used to // sign ucan invocations/receipts for the the subject (blob) multihash. -func deriveDID(digest multihash.Multihash) (principal.Signer, error) { +func deriveDID(digest multihash.Multihash) (multikey.Issuer, error) { if len(digest) < ed25519.SeedSize { return nil, fmt.Errorf("expected []byte with length %d, got %d", ed25519.SeedSize, len(digest)) } seed := digest[len(digest)-ed25519.SeedSize:] - return ed25519signer.FromRaw(seed) + key, err := ed25519signer.FromRaw(seed) + if err != nil { + return nil, fmt.Errorf("failed to create ed25519 signer: %w", err) + } + return multikey.KeyIssuer(key), nil } // acceptExtras carries the additional invocations / receipts produced by @@ -380,7 +384,7 @@ func maybeAccept( Put: putInv.Task().Link(), } - accInv, _, _, err := c.AcceptInvocation(ctx, &accReq, proofStore, invocation.WithNoNonce()) + accInv, _, err := c.AcceptInvocation(ctx, &accReq, proofStore, invocation.WithNoNonce()) if err != nil { log.Error("failed to create accept invocation", zap.Error(err)) return nil, nil, acceptExtras{}, err diff --git a/pkg/service/handlers/blob_add_test.go b/pkg/service/handlers/blob_add_test.go index 3c1f226..762d55f 100644 --- a/pkg/service/handlers/blob_add_test.go +++ b/pkg/service/handlers/blob_add_test.go @@ -1,21 +1,19 @@ package handlers_test import ( - "context" "crypto/ed25519" - "fmt" "net/http/httptest" "net/url" "testing" "time" + "github.com/fil-forge/libforge/attestation/didmailto" "github.com/fil-forge/libforge/commands" accesscmds "github.com/fil-forge/libforge/commands/access" blobcmds "github.com/fil-forge/libforge/commands/blob" httpcmds "github.com/fil-forge/libforge/commands/http" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/piriclient" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/routing" @@ -30,11 +28,12 @@ import ( subscription_store "github.com/fil-forge/sprue/pkg/store/subscription/memory" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/did" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" - ed25519signer "github.com/fil-forge/ucantone/principal/ed25519" - "github.com/fil-forge/ucantone/principal/verifier" + "github.com/fil-forge/ucantone/multikey" + ed25519signer "github.com/fil-forge/ucantone/multikey/ed25519" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" @@ -42,7 +41,6 @@ import ( "github.com/fil-forge/ucantone/ucan/promise" "github.com/fil-forge/ucantone/ucan/receipt" "github.com/fil-forge/ucantone/validator" - "github.com/fil-forge/ucantone/validator/errors" "github.com/multiformats/go-multihash" "github.com/stretchr/testify/require" "go.uber.org/zap" @@ -58,7 +56,7 @@ type blobAddTestDeps struct { blobReg *blob_registry.Store } -func newBlobAddTestDeps(t *testing.T, uploadService principal.Signer, logger *zap.Logger) *blobAddTestDeps { +func newBlobAddTestDeps(t *testing.T, uploadService multikey.Issuer, logger *zap.Logger) *blobAddTestDeps { t.Helper() consumerStore := consumer_store.New() subscriptionStore := subscription_store.New() @@ -74,7 +72,7 @@ func newBlobAddTestDeps(t *testing.T, uploadService principal.Signer, logger *za ) nodeProvider := piriclient.NewProvider(uploadService, logger) handler := handlers.NewBlobAddHandler( - &identity.Identity{Signer: uploadService}, + identity.Identity{Issuer: uploadService}, provisioningSvc, router, nodeProvider, @@ -94,11 +92,11 @@ func newBlobAddTestDeps(t *testing.T, uploadService principal.Signer, logger *za // provisionSpace adds the consumer record so provisioningSvc.ListServiceProviders // returns the upload service for the space. -func provisionSpace(t *testing.T, deps *blobAddTestDeps, uploadService principal.Signer, space did.DID) { +func provisionSpace(t *testing.T, deps *blobAddTestDeps, uploadService ucan.Issuer, space did.DID) { t.Helper() account := testutil.Must(didmailto.New("alice@example.com"))(t) err := deps.consumerStore.Add( - context.Background(), + t.Context(), uploadService.DID(), space, account, @@ -113,26 +111,19 @@ func provisionSpace(t *testing.T, deps *blobAddTestDeps, uploadService principal // did:web identity so signatures verify against the underlying did:key. func newMockPiriServer( t *testing.T, - storageProvider principal.Signer, - uploadService principal.Signer, + storageProvider ucan.Issuer, + uploadService identity.Identity, allocateOK *blobcmds.AllocateOK, acceptOK *blobcmds.AcceptOK, ) *httptest.Server { t.Helper() - resolveDIDKey := func(ctx context.Context, d did.DID) (ucan.Verifier, error) { - if d == uploadService.DID() { - return uploadService.Verifier(), nil - } - if d.Method() == "key" { - return verifier.FromDIDKey(d) - } - return nil, errors.NewDIDKeyResolutionError(d, fmt.Errorf("unexpected DID to resolve")) - } - srv := server.NewHTTP( storageProvider, - server.WithValidationOptions(validator.WithDIDVerifierResolver(resolveDIDKey)), + server.WithValidationOptions(validator.WithDIDResolver(resolver.Tiered{ + resolver.WellKnown{uploadService.DID(): testutil.Must(uploadService.DIDDocument())(t)}, + key.Resolver, + })), ) srv.Handle(blobcmds.Allocate.Command, blobcmds.Allocate.Handler(func( @@ -157,7 +148,7 @@ func newMockPiriServer( // providerProofs builds the proof container a storage provider grants the // upload service at registration: self-issued delegations (subject = provider) // authorizing `/blob/allocate` and `/blob/accept`. -func providerProofs(t *testing.T, storageProvider, uploadService principal.Signer) ucan.Container { +func providerProofs(t *testing.T, storageProvider, uploadService ucan.Issuer) ucan.Container { t.Helper() allocProof := testutil.Must(blobcmds.Allocate.Delegate(storageProvider, uploadService.DID(), storageProvider.DID()))(t) acceptProof := testutil.Must(blobcmds.Accept.Delegate(storageProvider, uploadService.DID(), storageProvider.DID()))(t) @@ -173,7 +164,7 @@ func TestBlobAddHandler(t *testing.T) { t.Run("no providers for space", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) args := blobcmds.AddArguments{ Blob: blobcmds.Blob{Digest: testutil.RandomMultihash(t), Size: 1024}, } @@ -187,7 +178,7 @@ func TestBlobAddHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -202,7 +193,7 @@ func TestBlobAddHandler(t *testing.T) { t.Run("no candidates available", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionSpace(t, deps, uploadService, space.DID()) // No storage providers in spStore — the router will return ErrCandidateUnavailable. @@ -219,7 +210,7 @@ func TestBlobAddHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -232,11 +223,11 @@ func TestBlobAddHandler(t *testing.T) { t.Run("zero weight providers returns candidate unavailable", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionSpace(t, deps, uploadService, space.DID()) // Register a storage provider with weight 0 — it'll be filtered out. - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) endpoint := testutil.Must(url.Parse("https://piri.example.com"))(t) err := deps.spStore.Put(ctx, storageProvider.DID(), *endpoint, 0, nil, container.New()) require.NoError(t, err) @@ -254,7 +245,7 @@ func TestBlobAddHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -267,10 +258,10 @@ func TestBlobAddHandler(t *testing.T) { t.Run("successful allocation with address", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionSpace(t, deps, uploadService, space.DID()) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) putURL := testutil.Must(url.Parse("https://storage.example.com/put"))(t) allocateOK := &blobcmds.AllocateOK{ Size: 1024, @@ -309,7 +300,7 @@ func TestBlobAddHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -326,10 +317,10 @@ func TestBlobAddHandler(t *testing.T) { t.Run("successful allocation blob already stored", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionSpace(t, deps, uploadService, space.DID()) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) // No address signals the blob is already on the provider — the handler // then issues the put receipt itself and proceeds to Accept on piri. allocateOK := &blobcmds.AllocateOK{Size: 1024, Address: nil} @@ -357,7 +348,7 @@ func TestBlobAddHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -375,10 +366,10 @@ func TestBlobAddHandler(t *testing.T) { t.Run("blob already registered in space", func(t *testing.T) { deps := newBlobAddTestDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionSpace(t, deps, uploadService, space.DID()) - storageProvider := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) digest := testutil.RandomMultihash(t) blob := blobcmds.Blob{Digest: digest, Size: 1024} @@ -470,7 +461,7 @@ func TestBlobAddHandler(t *testing.T) { ))(t) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = deps.handler.Handler(req, res) @@ -492,11 +483,11 @@ func TestBlobAddHandler(t *testing.T) { // deriveBlobProvider mirrors the production handler's logic for deriving a // signer from a blob's digest, used to sign /http/put invocations and receipts. -func deriveBlobProvider(t *testing.T, digest multihash.Multihash) principal.Signer { +func deriveBlobProvider(t *testing.T, digest multihash.Multihash) ucan.Issuer { t.Helper() require.GreaterOrEqual(t, len(digest), ed25519.SeedSize) seed := digest[len(digest)-ed25519.SeedSize:] s, err := ed25519signer.FromRaw(seed) require.NoError(t, err) - return s + return multikey.KeyIssuer(s) } diff --git a/pkg/service/handlers/blob_list_test.go b/pkg/service/handlers/blob_list_test.go index c05e813..3f15172 100644 --- a/pkg/service/handlers/blob_list_test.go +++ b/pkg/service/handlers/blob_list_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" blobcmds "github.com/fil-forge/libforge/commands/blob" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/service/handlers" blob_registry "github.com/fil-forge/sprue/pkg/store/blob_registry/memory" @@ -13,7 +13,7 @@ import ( metrics_store "github.com/fil-forge/sprue/pkg/store/metrics/memory" spacediff_store "github.com/fil-forge/sprue/pkg/store/space_diff/memory" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -35,9 +35,9 @@ func newBlobRegistry(t *testing.T) (*blob_registry.Store, *consumer_store.Store) func invokeBlobList( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, - space principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, + space ucan.Principal, args *blobcmds.ListArguments, ) (execution.Request, *execution.ExecResponse) { t.Helper() @@ -49,7 +49,7 @@ func invokeBlobList( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -66,7 +66,7 @@ func TestBlobListHandler(t *testing.T) { blobReg, _ := newBlobRegistry(t) handler := handlers.NewBlobListHandler(blobReg, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) req, res := invokeBlobList(t, ctx, alice, uploadService, space, &blobcmds.ListArguments{}) @@ -82,7 +82,7 @@ func TestBlobListHandler(t *testing.T) { blobReg, consumerStore := newBlobRegistry(t) handler := handlers.NewBlobListHandler(blobReg, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) blob1 := blobcmds.Blob{Digest: testutil.RandomMultihash(t), Size: 100} @@ -104,7 +104,7 @@ func TestBlobListHandler(t *testing.T) { blobReg, consumerStore := newBlobRegistry(t) handler := handlers.NewBlobListHandler(blobReg, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) for i := range 3 { @@ -131,7 +131,7 @@ func TestBlobListHandler(t *testing.T) { blobReg, consumerStore := newBlobRegistry(t) handler := handlers.NewBlobListHandler(blobReg, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) for i := range 3 { @@ -166,8 +166,8 @@ func TestBlobListHandler(t *testing.T) { blobReg, consumerStore := newBlobRegistry(t) handler := handlers.NewBlobListHandler(blobReg, logger) - space1 := testutil.RandomSigner(t) - space2 := testutil.RandomSigner(t) + space1 := testutil.RandomIssuer(t) + space2 := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space1.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) require.NoError(t, blobReg.Register( diff --git a/pkg/service/handlers/blob_replicate.go b/pkg/service/handlers/blob_replicate.go index 0fae0fd..fd5dbcf 100644 --- a/pkg/service/handlers/blob_replicate.go +++ b/pkg/service/handlers/blob_replicate.go @@ -29,7 +29,7 @@ package handlers // "github.com/storacha/go-ucanto/ucan" // "github.com/storacha/go-ucanto/validator" // "github.com/fil-forge/sprue/internal/config" -// "github.com/fil-forge/sprue/pkg/identity" +// // "github.com/fil-forge/sprue/pkg/internal/ipldutil" // "github.com/fil-forge/sprue/pkg/piriclient" // "github.com/fil-forge/sprue/pkg/routing" @@ -59,7 +59,7 @@ package handlers // // WithSpaceBlobReplicateMethod registers the space/blob/replicate handler. // func WithSpaceBlobReplicateMethod( // cfg config.DeploymentConfig, -// id *identity.Identity, +// id identity.Identity, // router *routing.Service, // blobRegistry blobregistry.Store, // replicaStore replica.Store, @@ -78,7 +78,7 @@ package handlers // func BlobReplicateHandler( // cfg config.DeploymentConfig, -// id *identity.Identity, +// id identity.Identity, // router *routing.Service, // blobRegistry blobregistry.Store, // replicaStore replica.Store, diff --git a/pkg/service/handlers/blob_replicate_test.go b/pkg/service/handlers/blob_replicate_test.go index 6c6841a..13b261f 100644 --- a/pkg/service/handlers/blob_replicate_test.go +++ b/pkg/service/handlers/blob_replicate_test.go @@ -7,7 +7,7 @@ package handlers_test // "testing" // "time" -// "github.com/fil-forge/libforge/didmailto" +// "github.com/fil-forge/libforge/attestation/didmailto" // "github.com/fil-forge/ucantone/did" // cidlink "github.com/ipld/go-ipld-prime/linking/cid" // "github.com/storacha/go-libstoracha/capabilities/assert" @@ -28,7 +28,7 @@ package handlers_test // "github.com/storacha/go-ucanto/validator" // "github.com/fil-forge/sprue/internal/config" // "github.com/fil-forge/sprue/internal/testutil" -// "github.com/fil-forge/sprue/pkg/identity" +// // "github.com/fil-forge/sprue/pkg/piriclient" // "github.com/fil-forge/sprue/pkg/routing" // "github.com/fil-forge/sprue/pkg/service/handlers" @@ -60,7 +60,7 @@ package handlers_test // nodeProvider := piriclient.NewProvider(uploadService, logger) // handler := handlers.SpaceBlobReplicateHandler( -// defaultCfg, &identity.Identity{Signer: uploadService}, +// defaultCfg, identity.Identity{Signer: uploadService}, // router, blobReg, replicaStore, agentStore, nodeProvider, logger, // ) @@ -98,7 +98,7 @@ package handlers_test // cfg := config.DeploymentConfig{MaxReplicas: 2} // handler := handlers.SpaceBlobReplicateHandler( -// cfg, &identity.Identity{Signer: uploadService}, +// cfg, identity.Identity{Signer: uploadService}, // router, blobReg, replicaStore, agentStore, nodeProvider, logger, // ) @@ -136,7 +136,7 @@ package handlers_test // nodeProvider := piriclient.NewProvider(uploadService, logger) // handler := handlers.SpaceBlobReplicateHandler( -// defaultCfg, &identity.Identity{Signer: uploadService}, +// defaultCfg, identity.Identity{Signer: uploadService}, // router, blobReg, replicaStore, agentStore, nodeProvider, logger, // ) @@ -174,7 +174,7 @@ package handlers_test // nodeProvider := piriclient.NewProvider(uploadService, logger) // handler := handlers.SpaceBlobReplicateHandler( -// defaultCfg, &identity.Identity{Signer: uploadService}, +// defaultCfg, identity.Identity{Signer: uploadService}, // router, blobReg, replicaStore, agentStore, nodeProvider, logger, // ) @@ -279,7 +279,7 @@ package handlers_test // } // nodeProvider := newMultiMockReplicaNodeProvider(t, uploadService, -// []principal.Signer{replicaProviderA, replicaProviderB}, +// []ucan.Signer{replicaProviderA, replicaProviderB}, // replicaAllocHandler, logger, // ) @@ -386,7 +386,7 @@ package handlers_test // nodeProvider := piriclient.NewProvider(uploadService, logger) // handler := handlers.SpaceBlobReplicateHandler( -// defaultCfg, &identity.Identity{Signer: uploadService}, +// defaultCfg, identity.Identity{Signer: uploadService}, // router, blobReg, replicaStore, agentStore, nodeProvider, logger, // ) @@ -448,7 +448,7 @@ package handlers_test // func newMultiMockReplicaNodeProvider( // t *testing.T, // agentID ucan.Signer, -// serviceIDs []principal.Signer, +// serviceIDs []ucan.Signer, // allocHandler server.HandlerFunc[blobreplicacap.AllocateCaveats, blobreplicacap.AllocateOk, failure.IPLDBuilderFailure], // logger *zap.Logger, // ) *multiMockReplicaNodeProvider { @@ -479,7 +479,7 @@ package handlers_test // } // // delegateReplicaProviderProof delegates blob/replica/allocate capability. -// func delegateReplicaProviderProof(t *testing.T, issuer principal.Signer, audience ucan.Principal) delegation.Delegation { +// func delegateReplicaProviderProof(t *testing.T, issuer ucan.Signer, audience ucan.Principal) delegation.Delegation { // t.Helper() // proof, err := delegation.Delegate( // issuer, diff --git a/pkg/service/handlers/index_add.go b/pkg/service/handlers/index_add.go index 14491a6..afc2fff 100644 --- a/pkg/service/handlers/index_add.go +++ b/pkg/service/handlers/index_add.go @@ -7,8 +7,8 @@ import ( accesscmds "github.com/fil-forge/libforge/commands/access" indexcmds "github.com/fil-forge/libforge/commands/index" + "github.com/fil-forge/libforge/identity" ucanlib "github.com/fil-forge/libforge/ucan" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/indexerclient" "github.com/fil-forge/sprue/pkg/provisioning" blobregistry "github.com/fil-forge/sprue/pkg/store/blob_registry" @@ -17,7 +17,7 @@ import ( "github.com/fil-forge/ucantone/server" ) -func NewIndexAddHandler(id *identity.Identity, provisioningSvc *provisioning.Service, blobRegistry blobregistry.Store, indexerClient *indexerclient.Client, logger *zap.Logger) server.Route { +func NewIndexAddHandler(id identity.Identity, provisioningSvc *provisioning.Service, blobRegistry blobregistry.Store, indexerClient *indexerclient.Client, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", indexcmds.Add)) return indexcmds.Add.Route( func(req *binding.Request[*indexcmds.AddArguments], res *binding.Response[*indexcmds.AddOK]) error { diff --git a/pkg/service/handlers/index_add_test.go b/pkg/service/handlers/index_add_test.go index 12764f1..fd82d05 100644 --- a/pkg/service/handlers/index_add_test.go +++ b/pkg/service/handlers/index_add_test.go @@ -2,19 +2,18 @@ package handlers_test import ( "context" - "fmt" "net/http/httptest" "net/url" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" accesscmds "github.com/fil-forge/libforge/commands/access" assertcmds "github.com/fil-forge/libforge/commands/assert" blobcmds "github.com/fil-forge/libforge/commands/blob" contentcmds "github.com/fil-forge/libforge/commands/content" indexcmds "github.com/fil-forge/libforge/commands/index" - "github.com/fil-forge/libforge/didmailto" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/indexerclient" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/service/handlers" @@ -22,15 +21,14 @@ import ( subscription_store "github.com/fil-forge/sprue/pkg/store/subscription/memory" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/did" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" - "github.com/fil-forge/ucantone/principal/verifier" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/fil-forge/ucantone/validator" - "github.com/fil-forge/ucantone/validator/errors" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -41,28 +39,21 @@ import ( // so signatures verify against the underlying did:key. func newMockIndexerServer( t *testing.T, - indexerSigner principal.Signer, - uploadService principal.Signer, + indexerIdent identity.Identity, + uploadService identity.Identity, indexOK *assertcmds.IndexOK, ) *httptest.Server { t.Helper() - resolveDIDKey := func(ctx context.Context, d did.DID) (ucan.Verifier, error) { - if d == indexerSigner.DID() { - return indexerSigner.Verifier(), nil - } - if d == uploadService.DID() { - return uploadService.Verifier(), nil - } - if d.Method() == "key" { - verifier.FromDIDKey(d) - } - return nil, errors.NewDIDKeyResolutionError(d, fmt.Errorf("unexpected DID to resolve")) - } - srv := server.NewHTTP( - indexerSigner, - server.WithValidationOptions(validator.WithDIDVerifierResolver(resolveDIDKey)), + indexerIdent, + server.WithValidationOptions(validator.WithDIDResolver(resolver.Tiered{ + resolver.WellKnown{ + indexerIdent.DID(): testutil.Must(indexerIdent.DIDDocument())(t), + uploadService.DID(): testutil.Must(uploadService.DIDDocument())(t), + }, + key.Resolver, + })), ) srv.Handle(assertcmds.Index.Command, assertcmds.Index.Handler(func( @@ -82,9 +73,9 @@ func newMockIndexerServer( func invokeIndexAdd( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, - space principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, + space ucan.Principal, index cid.Cid, reqOpts ...execution.RequestOption, ) (execution.Request, *execution.ExecResponse) { @@ -97,7 +88,7 @@ func invokeIndexAdd( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv, reqOpts...) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -110,7 +101,7 @@ func TestIndexAddHandler(t *testing.T) { alice := testutil.Alice aliceAccount := testutil.Must(didmailto.New("alice@example.com"))(t) - id := &identity.Identity{Signer: uploadService} + id := identity.Identity{Issuer: uploadService} t.Run("no service providers", func(t *testing.T) { consumerStore := consumer_store.New() @@ -120,7 +111,7 @@ func TestIndexAddHandler(t *testing.T) { handler := handlers.NewIndexAddHandler(id, provisioningSvc, blobReg, nil, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) req, res := invokeIndexAdd(t, ctx, alice, uploadService, space, testutil.RandomCID(t)) err := handler.Handler(req, res) @@ -141,7 +132,7 @@ func TestIndexAddHandler(t *testing.T) { subscriptionStore, ) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) handler := handlers.NewIndexAddHandler(id, provisioningSvc, blobReg, nil, logger) @@ -165,7 +156,7 @@ func TestIndexAddHandler(t *testing.T) { subscriptionStore, ) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) indexCID := testutil.RandomCID(t) @@ -173,10 +164,10 @@ func TestIndexAddHandler(t *testing.T) { require.NoError(t, blobReg.Register(ctx, space.DID(), indexBlob, testutil.RandomCID(t))) // Stand up a mock indexer that returns success on /assert/index. - indexerSigner := testutil.RandomSigner(t) - indexerSrv := newMockIndexerServer(t, indexerSigner, uploadService, &assertcmds.IndexOK{}) + indexerIdent := identity.Identity{Issuer: testutil.RandomMultikeyIssuer(t)} + indexerSrv := newMockIndexerServer(t, indexerIdent, uploadService, &assertcmds.IndexOK{}) indexerURL := testutil.Must(url.Parse(indexerSrv.URL))(t) - indexerCli, err := indexerclient.New(indexerURL, indexerSigner.DID(), uploadService, logger) + indexerCli, err := indexerclient.New(indexerURL, indexerIdent.DID(), uploadService, logger) require.NoError(t, err) handler := handlers.NewIndexAddHandler(id, provisioningSvc, blobReg, indexerCli, logger) @@ -207,17 +198,17 @@ func TestIndexAddHandler(t *testing.T) { subscriptionStore, ) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) require.NoError(t, consumerStore.Add(ctx, uploadService.DID(), space.DID(), aliceAccount, "sub-1", testutil.RandomCID(t))) indexCID := testutil.RandomCID(t) indexBlob := blobcmds.Blob{Digest: indexCID.Hash(), Size: 512} require.NoError(t, blobReg.Register(ctx, space.DID(), indexBlob, testutil.RandomCID(t))) - indexerSigner := testutil.RandomSigner(t) - indexerSrv := newMockIndexerServer(t, indexerSigner, uploadService, &assertcmds.IndexOK{}) + indexerIdent := identity.Identity{Issuer: testutil.RandomMultikeyIssuer(t)} + indexerSrv := newMockIndexerServer(t, indexerIdent, uploadService, &assertcmds.IndexOK{}) indexerURL := testutil.Must(url.Parse(indexerSrv.URL))(t) - indexerCli, err := indexerclient.New(indexerURL, indexerSigner.DID(), uploadService, logger) + indexerCli, err := indexerclient.New(indexerURL, indexerIdent.DID(), uploadService, logger) require.NoError(t, err) handler := handlers.NewIndexAddHandler(id, provisioningSvc, blobReg, indexerCli, logger) diff --git a/pkg/service/handlers/provider_add.go b/pkg/service/handlers/provider_add.go index 82de394..fcde3aa 100644 --- a/pkg/service/handlers/provider_add.go +++ b/pkg/service/handlers/provider_add.go @@ -3,8 +3,8 @@ package handlers import ( "fmt" + "github.com/fil-forge/libforge/attestation/didmailto" providercmds "github.com/fil-forge/libforge/commands/provider" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/config" "github.com/fil-forge/sprue/pkg/billing" "github.com/fil-forge/sprue/pkg/provisioning" diff --git a/pkg/service/handlers/provider_add_test.go b/pkg/service/handlers/provider_add_test.go index ac7651d..c88d791 100644 --- a/pkg/service/handlers/provider_add_test.go +++ b/pkg/service/handlers/provider_add_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" providercmds "github.com/fil-forge/libforge/commands/provider" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/config" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/billing" @@ -17,7 +17,7 @@ import ( "github.com/fil-forge/ucantone/did" "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -50,8 +50,8 @@ func setupProviderAdd(t *testing.T, providerDID did.DID) *providerAddDeps { func invokeProviderAdd( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, account did.DID, args *providercmds.AddArguments, ) (execution.Request, *execution.ExecResponse) { @@ -64,7 +64,7 @@ func invokeProviderAdd( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -76,7 +76,7 @@ func TestProviderAddHandler(t *testing.T) { uploadService := testutil.WebService t.Run("success with payment plan", func(t *testing.T) { - serviceProvider := testutil.RandomSigner(t) + serviceProvider := testutil.RandomIssuer(t) deps := setupProviderAdd(t, serviceProvider.DID()) account := testutil.Must(didmailto.New("alice@example.com"))(t) @@ -88,8 +88,8 @@ func TestProviderAddHandler(t *testing.T) { deps.provisioningSvc, deps.billingSvc, logger, ) - space := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) req, res := invokeProviderAdd(t, ctx, agent, uploadService, account, &providercmds.AddArguments{ Provider: serviceProvider.DID(), @@ -106,7 +106,7 @@ func TestProviderAddHandler(t *testing.T) { }) t.Run("success skipping payment plan check", func(t *testing.T) { - serviceProvider := testutil.RandomSigner(t) + serviceProvider := testutil.RandomIssuer(t) deps := setupProviderAdd(t, serviceProvider.DID()) // No customer added — but payment plan check is skipped. @@ -116,8 +116,8 @@ func TestProviderAddHandler(t *testing.T) { ) account := testutil.Must(didmailto.New("alice@example.com"))(t) - space := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) req, res := invokeProviderAdd(t, ctx, agent, uploadService, account, &providercmds.AddArguments{ Provider: serviceProvider.DID(), @@ -134,7 +134,7 @@ func TestProviderAddHandler(t *testing.T) { }) t.Run("invalid account DID", func(t *testing.T) { - serviceProvider := testutil.RandomSigner(t) + serviceProvider := testutil.RandomIssuer(t) deps := setupProviderAdd(t, serviceProvider.DID()) handler := handlers.NewProviderAddHandler( @@ -143,9 +143,9 @@ func TestProviderAddHandler(t *testing.T) { ) // Subject is a did:key (not a did:mailto), so didmailto.Parse rejects it. - notAMailto := testutil.RandomSigner(t) - space := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + notAMailto := testutil.RandomIssuer(t) + space := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) req, res := invokeProviderAdd(t, ctx, agent, uploadService, notAMailto.DID(), &providercmds.AddArguments{ Provider: serviceProvider.DID(), @@ -163,7 +163,7 @@ func TestProviderAddHandler(t *testing.T) { }) t.Run("missing payment plan", func(t *testing.T) { - serviceProvider := testutil.RandomSigner(t) + serviceProvider := testutil.RandomIssuer(t) deps := setupProviderAdd(t, serviceProvider.DID()) // No customer added — payment plan check fails with ErrMissingPaymentPlan. @@ -173,8 +173,8 @@ func TestProviderAddHandler(t *testing.T) { ) account := testutil.Must(didmailto.New("alice@example.com"))(t) - space := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) req, res := invokeProviderAdd(t, ctx, agent, uploadService, account, &providercmds.AddArguments{ Provider: serviceProvider.DID(), @@ -190,7 +190,7 @@ func TestProviderAddHandler(t *testing.T) { }) t.Run("provider not allowed", func(t *testing.T) { - serviceProvider := testutil.RandomSigner(t) + serviceProvider := testutil.RandomIssuer(t) deps := setupProviderAdd(t, serviceProvider.DID()) handler := handlers.NewProviderAddHandler( @@ -199,10 +199,10 @@ func TestProviderAddHandler(t *testing.T) { ) // Args reference a different provider than the one allowed in setup. - otherProvider := testutil.RandomSigner(t) + otherProvider := testutil.RandomIssuer(t) account := testutil.Must(didmailto.New("alice@example.com"))(t) - space := testutil.RandomSigner(t) - agent := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) + agent := testutil.RandomIssuer(t) req, res := invokeProviderAdd(t, ctx, agent, uploadService, account, &providercmds.AddArguments{ Provider: otherProvider.DID(), diff --git a/pkg/service/handlers/space_info_test.go b/pkg/service/handlers/space_info_test.go index 9df8f8f..6907862 100644 --- a/pkg/service/handlers/space_info_test.go +++ b/pkg/service/handlers/space_info_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" spacecmds "github.com/fil-forge/libforge/commands/space" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/service/handlers" @@ -14,7 +14,7 @@ import ( "github.com/fil-forge/ucantone/did" "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -25,8 +25,8 @@ import ( func invokeSpaceInfo( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, space did.DID, ) (execution.Request, *execution.ExecResponse) { t.Helper() @@ -38,7 +38,7 @@ func invokeSpaceInfo( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -60,7 +60,7 @@ func TestSpaceInfoHandler(t *testing.T) { handler := handlers.NewSpaceInfoHandler(provisioningSvc, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) account := testutil.Must(didmailto.New("alice@example.com"))(t) _, err := provisioningSvc.Provision(ctx, account, space.DID(), uploadService.DID(), testutil.RandomCID(t)) @@ -86,7 +86,7 @@ func TestSpaceInfoHandler(t *testing.T) { handler := handlers.NewSpaceInfoHandler(provisioningSvc, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) req, res := invokeSpaceInfo(t, ctx, testutil.Alice, uploadService, space.DID()) diff --git a/pkg/service/handlers/ucan_conclude.go b/pkg/service/handlers/ucan_conclude.go index ba30b42..ca968c4 100644 --- a/pkg/service/handlers/ucan_conclude.go +++ b/pkg/service/handlers/ucan_conclude.go @@ -7,7 +7,7 @@ import ( "slices" ucancmds "github.com/fil-forge/libforge/commands/ucan" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/pkg/store/agent" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" @@ -32,7 +32,7 @@ type ConclusionHandler struct { // This handler processes receipt conclusions from clients. // When it receives an /http/put receipt, it calls /blob/accept on piri // and stores the accept receipt for later retrieval. -func NewUCANConcludeHandler(id *identity.Identity, agentStore agent.Store, handlers map[ucan.Command]ConclusionHandlerFunc, logger *zap.Logger) server.Route { +func NewUCANConcludeHandler(id identity.Identity, agentStore agent.Store, handlers map[ucan.Command]ConclusionHandlerFunc, logger *zap.Logger) server.Route { log := logger.With(zap.Stringer("handler", ucancmds.Conclude)) log.Info("registered conclude handlers", zap.Stringers("commands", slices.Collect(maps.Keys(handlers)))) return ucancmds.Conclude.Route( diff --git a/pkg/service/handlers/ucan_conclude_blob_replica_transfer.go b/pkg/service/handlers/ucan_conclude_blob_replica_transfer.go index aa1ed29..afc372a 100644 --- a/pkg/service/handlers/ucan_conclude_blob_replica_transfer.go +++ b/pkg/service/handlers/ucan_conclude_blob_replica_transfer.go @@ -20,7 +20,7 @@ package handlers // "github.com/storacha/go-ucanto/server" // "github.com/storacha/go-ucanto/ucan" // "github.com/storacha/go-ucanto/validator" -// "github.com/fil-forge/sprue/pkg/identity" +// // "github.com/fil-forge/sprue/pkg/internal/ipldutil" // "github.com/fil-forge/sprue/pkg/store/agent" // "github.com/fil-forge/sprue/pkg/store/replica" @@ -39,7 +39,7 @@ package handlers // var ErrInvalidTransferReceiptSignature = errors.New(InvalidTransferReceiptSignatureErrorName, "invalid transfer receipt signature") // func NewBlobReplicaTransferConcludeHandler( -// id *identity.Identity, +// id identity.Identity, // agentStore agent.Store, // replicaStore replica.Store, // logger *zap.Logger, diff --git a/pkg/service/handlers/ucan_conclude_blob_replica_transfer_test.go b/pkg/service/handlers/ucan_conclude_blob_replica_transfer_test.go index 0ea8f47..69c872a 100644 --- a/pkg/service/handlers/ucan_conclude_blob_replica_transfer_test.go +++ b/pkg/service/handlers/ucan_conclude_blob_replica_transfer_test.go @@ -19,7 +19,7 @@ package handlers_test // "github.com/storacha/go-ucanto/server" // "github.com/storacha/go-ucanto/ucan" // "github.com/fil-forge/sprue/internal/testutil" -// "github.com/fil-forge/sprue/pkg/identity" +// // "github.com/fil-forge/sprue/pkg/service/handlers" // "github.com/fil-forge/sprue/pkg/store/agent" // agent_store "github.com/fil-forge/sprue/pkg/store/agent/memory" @@ -68,7 +68,7 @@ package handlers_test // replicaStore := replica_store.New() // ch := handlers.NewBlobReplicaTransferConcludeHandler( -// &identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, +// identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, // ) // // Create an invocation with wrong capability (not blob/replica/transfer) @@ -97,7 +97,7 @@ package handlers_test // replicaStore := replica_store.New() // ch := handlers.NewBlobReplicaTransferConcludeHandler( -// &identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, +// identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, // ) // space := testutil.RandomSigner(t) @@ -137,7 +137,7 @@ package handlers_test // replicaStore := replica_store.New() // ch := handlers.NewBlobReplicaTransferConcludeHandler( -// &identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, +// identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, // ) // space := testutil.RandomSigner(t) @@ -202,7 +202,7 @@ package handlers_test // replicaStore := replica_store.New() // ch := handlers.NewBlobReplicaTransferConcludeHandler( -// &identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, +// identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, // ) // space := testutil.RandomSigner(t) @@ -288,7 +288,7 @@ package handlers_test // replicaStore := replica_store.New() // ch := handlers.NewBlobReplicaTransferConcludeHandler( -// &identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, +// identity.Identity{Signer: uploadService}, agentStore, replicaStore, logger, // ) // space := testutil.RandomSigner(t) diff --git a/pkg/service/handlers/ucan_conclude_http_put_test.go b/pkg/service/handlers/ucan_conclude_http_put_test.go index 0fb0eaf..18aa8f6 100644 --- a/pkg/service/handlers/ucan_conclude_http_put_test.go +++ b/pkg/service/handlers/ucan_conclude_http_put_test.go @@ -4,9 +4,9 @@ import ( "net/url" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" blobcmds "github.com/fil-forge/libforge/commands/blob" httpcmds "github.com/fil-forge/libforge/commands/http" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/piriclient" "github.com/fil-forge/sprue/pkg/routing" @@ -97,8 +97,8 @@ func TestHTTPPutConcludeHandler(t *testing.T) { t.Run("storage provider not found", func(t *testing.T) { deps := newHTTPPutDeps(t, piriclient.NewProvider(uploadService, logger), logger) - storageProvider := testutil.RandomSigner(t) - space := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) + space := testutil.RandomIssuer(t) digest := testutil.RandomMultihash(t) blob := blobcmds.Blob{Digest: digest, Size: 1024} @@ -147,8 +147,8 @@ func TestHTTPPutConcludeHandler(t *testing.T) { }) t.Run("success registers blob in space", func(t *testing.T) { - storageProvider := testutil.RandomSigner(t) - space := testutil.RandomSigner(t) + storageProvider := testutil.RandomIssuer(t) + space := testutil.RandomIssuer(t) digest := testutil.RandomMultihash(t) blob := blobcmds.Blob{Digest: digest, Size: 1024} blobAddTaskLink := testutil.RandomCID(t) diff --git a/pkg/service/handlers/ucan_conclude_test.go b/pkg/service/handlers/ucan_conclude_test.go index fb6a9ca..c85716d 100644 --- a/pkg/service/handlers/ucan_conclude_test.go +++ b/pkg/service/handlers/ucan_conclude_test.go @@ -6,8 +6,8 @@ import ( blobcmds "github.com/fil-forge/libforge/commands/blob" ucancmds "github.com/fil-forge/libforge/commands/ucan" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/internal/testutil" - "github.com/fil-forge/sprue/pkg/identity" "github.com/fil-forge/sprue/pkg/service/handlers" "github.com/fil-forge/sprue/pkg/store/agent" agent_store "github.com/fil-forge/sprue/pkg/store/agent/memory" @@ -47,7 +47,7 @@ func TestUCANConcludeHandler(t *testing.T) { handlerMap := map[ucan.Command]handlers.ConclusionHandlerFunc{} handler := handlers.NewUCANConcludeHandler( - &identity.Identity{Signer: uploadService}, agentStore, handlerMap, logger, + identity.Identity{Issuer: uploadService}, agentStore, handlerMap, logger, ) _, rcpt := newTaskAndReceipt(t, command.MustParse("/test/thing")) @@ -63,7 +63,7 @@ func TestUCANConcludeHandler(t *testing.T) { // The receipt is referenced in args but NOT attached to the request // metadata, so the handler can't find it. req := execution.NewRequest(ctx, concludeInv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -78,7 +78,7 @@ func TestUCANConcludeHandler(t *testing.T) { handlerMap := map[ucan.Command]handlers.ConclusionHandlerFunc{} handler := handlers.NewUCANConcludeHandler( - &identity.Identity{Signer: uploadService}, agentStore, handlerMap, logger, + identity.Identity{Issuer: uploadService}, agentStore, handlerMap, logger, ) // Receipt is supplied but the ran invocation is neither in the request @@ -94,7 +94,7 @@ func TestUCANConcludeHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, concludeInv, execution.WithReceipts(rcpt)) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -122,7 +122,7 @@ func TestUCANConcludeHandler(t *testing.T) { } handler := handlers.NewUCANConcludeHandler( - &identity.Identity{Signer: uploadService}, agentStore, handlerMap, logger, + identity.Identity{Issuer: uploadService}, agentStore, handlerMap, logger, ) taskInv, rcpt := newTaskAndReceipt(t, command.MustParse("/test/thing")) @@ -144,7 +144,7 @@ func TestUCANConcludeHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, concludeInv, execution.WithReceipts(rcpt)) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -164,7 +164,7 @@ func TestUCANConcludeHandler(t *testing.T) { handlerMap := map[ucan.Command]handlers.ConclusionHandlerFunc{} handler := handlers.NewUCANConcludeHandler( - &identity.Identity{Signer: uploadService}, agentStore, handlerMap, logger, + identity.Identity{Issuer: uploadService}, agentStore, handlerMap, logger, ) taskInv, rcpt := newTaskAndReceipt(t, command.MustParse("/test/unhandled")) @@ -184,7 +184,7 @@ func TestUCANConcludeHandler(t *testing.T) { require.NoError(t, err) req := execution.NewRequest(ctx, concludeInv, execution.WithReceipts(rcpt)) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) @@ -206,7 +206,7 @@ func TestUCANConcludeHandler(t *testing.T) { } handler := handlers.NewUCANConcludeHandler( - &identity.Identity{Signer: uploadService}, agentStore, handlerMap, logger, + identity.Identity{Issuer: uploadService}, agentStore, handlerMap, logger, ) taskInv, rcpt := newTaskAndReceipt(t, command.MustParse("/test/thing")) @@ -225,7 +225,7 @@ func TestUCANConcludeHandler(t *testing.T) { execution.WithReceipts(rcpt), execution.WithInvocations(taskInv), ) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) err = handler.Handler(req, res) diff --git a/pkg/service/handlers/upload_add_test.go b/pkg/service/handlers/upload_add_test.go index d4956fc..0affbbe 100644 --- a/pkg/service/handlers/upload_add_test.go +++ b/pkg/service/handlers/upload_add_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" + "github.com/fil-forge/libforge/attestation/didmailto" accesscmds "github.com/fil-forge/libforge/commands/access" blobcmds "github.com/fil-forge/libforge/commands/blob" uploadcmds "github.com/fil-forge/libforge/commands/upload" - "github.com/fil-forge/libforge/didmailto" "github.com/fil-forge/sprue/internal/testutil" "github.com/fil-forge/sprue/pkg/provisioning" "github.com/fil-forge/sprue/pkg/service/handlers" @@ -17,8 +17,8 @@ import ( "github.com/fil-forge/ucantone/did" "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/server" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" @@ -32,7 +32,7 @@ type uploadAddDeps struct { consumerStore *consumer_store.Store } -func newUploadAddDeps(t *testing.T, uploadService principal.Signer, logger *zap.Logger) *uploadAddDeps { +func newUploadAddDeps(t *testing.T, uploadService ucan.Principal, logger *zap.Logger) *uploadAddDeps { t.Helper() consumerStore := consumer_store.New() provisioningSvc := provisioning.NewService( @@ -50,9 +50,9 @@ func newUploadAddDeps(t *testing.T, uploadService principal.Signer, logger *zap. func invokeUploadAdd( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, - space principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, + space ucan.Principal, args *uploadcmds.AddArguments, ) (execution.Request, *execution.ExecResponse) { t.Helper() @@ -64,14 +64,14 @@ func invokeUploadAdd( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } // provisionUploadSpace adds a consumer record so the upload service shows up as // a provider for the space when the handler calls ListServiceProviders. -func provisionUploadSpace(t *testing.T, consumerStore *consumer_store.Store, uploadService principal.Signer, space principal.Signer) { +func provisionUploadSpace(t *testing.T, consumerStore *consumer_store.Store, uploadService ucan.Principal, space ucan.Principal) { t.Helper() account := testutil.Must(didmailto.New("alice@example.com"))(t) require.NoError(t, consumerStore.Add( @@ -94,7 +94,7 @@ func TestUploadAddHandler(t *testing.T) { t.Run("space not provisioned", func(t *testing.T) { deps := newUploadAddDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) req, res := invokeUploadAdd(t, ctx, alice, uploadService, space, &uploadcmds.AddArguments{Root: root}) @@ -115,7 +115,7 @@ func TestUploadAddHandler(t *testing.T) { t.Run("success with no shards", func(t *testing.T) { deps := newUploadAddDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionUploadSpace(t, deps.consumerStore, uploadService, space) root := testutil.RandomCID(t) @@ -141,7 +141,7 @@ func TestUploadAddHandler(t *testing.T) { t.Run("success with shards", func(t *testing.T) { deps := newUploadAddDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionUploadSpace(t, deps.consumerStore, uploadService, space) root := testutil.RandomCID(t) @@ -167,7 +167,7 @@ func TestUploadAddHandler(t *testing.T) { t.Run("success with index", func(t *testing.T) { deps := newUploadAddDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionUploadSpace(t, deps.consumerStore, uploadService, space) root := testutil.RandomCID(t) @@ -192,7 +192,7 @@ func TestUploadAddHandler(t *testing.T) { t.Run("upsert updates existing upload", func(t *testing.T) { deps := newUploadAddDeps(t, uploadService, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) provisionUploadSpace(t, deps.consumerStore, uploadService, space) root := testutil.RandomCID(t) diff --git a/pkg/service/handlers/upload_list_test.go b/pkg/service/handlers/upload_list_test.go index 866f81f..d53ffbe 100644 --- a/pkg/service/handlers/upload_list_test.go +++ b/pkg/service/handlers/upload_list_test.go @@ -9,7 +9,7 @@ import ( "github.com/fil-forge/sprue/pkg/service/handlers" upload_store "github.com/fil-forge/sprue/pkg/store/upload/memory" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" @@ -21,9 +21,9 @@ import ( func invokeUploadList( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, - space principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, + space ucan.Principal, args *uploadcmds.ListArguments, ) (execution.Request, *execution.ExecResponse) { t.Helper() @@ -35,7 +35,7 @@ func invokeUploadList( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -51,7 +51,7 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) req, res := invokeUploadList(t, ctx, alice, uploadService, space, &uploadcmds.ListArguments{}) err := handler.Handler(req, res) @@ -67,7 +67,7 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root1 := testutil.RandomCID(t) root2 := testutil.RandomCID(t) @@ -95,7 +95,7 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) for range 3 { require.NoError(t, store.Upsert(ctx, space.DID(), testutil.RandomCID(t), nil, nil, testutil.RandomCID(t))) } @@ -116,7 +116,7 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) for range 3 { require.NoError(t, store.Upsert(ctx, space.DID(), testutil.RandomCID(t), nil, nil, testutil.RandomCID(t))) } @@ -145,8 +145,8 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space1 := testutil.RandomSigner(t) - space2 := testutil.RandomSigner(t) + space1 := testutil.RandomIssuer(t) + space2 := testutil.RandomIssuer(t) require.NoError(t, store.Upsert(ctx, space1.DID(), testutil.RandomCID(t), nil, nil, testutil.RandomCID(t))) @@ -163,7 +163,7 @@ func TestUploadListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) index := testutil.RandomCID(t) require.NoError(t, store.Upsert(ctx, space.DID(), root, &index, nil, testutil.RandomCID(t))) diff --git a/pkg/service/handlers/upload_shard_list_test.go b/pkg/service/handlers/upload_shard_list_test.go index 189a0de..b5352bc 100644 --- a/pkg/service/handlers/upload_shard_list_test.go +++ b/pkg/service/handlers/upload_shard_list_test.go @@ -9,7 +9,7 @@ import ( "github.com/fil-forge/sprue/pkg/service/handlers" upload_store "github.com/fil-forge/sprue/pkg/store/upload/memory" "github.com/fil-forge/ucantone/execution" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" @@ -21,9 +21,9 @@ import ( func invokeUploadShardList( t *testing.T, ctx context.Context, - agent principal.Signer, - uploadService principal.Signer, - space principal.Signer, + agent ucan.Issuer, + uploadService ucan.Issuer, + space ucan.Principal, args *shardcmds.ListArguments, ) (execution.Request, *execution.ExecResponse) { t.Helper() @@ -35,7 +35,7 @@ func invokeUploadShardList( ) require.NoError(t, err) req := execution.NewRequest(ctx, inv) - res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithSigner(uploadService)) + res, err := execution.NewResponse(req.Invocation().Task().Link(), execution.WithIssuer(uploadService)) require.NoError(t, err) return req, res } @@ -51,7 +51,7 @@ func TestUploadShardListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadShardListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) // Upload exists with no shards. @@ -71,7 +71,7 @@ func TestUploadShardListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadShardListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) shard1 := testutil.RandomCID(t) shard2 := testutil.RandomCID(t) @@ -99,7 +99,7 @@ func TestUploadShardListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadShardListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) shard1 := testutil.RandomCID(t) shard2 := testutil.RandomCID(t) @@ -122,7 +122,7 @@ func TestUploadShardListHandler(t *testing.T) { store := upload_store.New() handler := handlers.NewUploadShardListHandler(store, logger) - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) root := testutil.RandomCID(t) shard1 := testutil.RandomCID(t) shard2 := testutil.RandomCID(t) diff --git a/pkg/service/service.go b/pkg/service/service.go index d99e5e2..e7f87dd 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -7,14 +7,18 @@ import ( "slices" "time" - "github.com/fil-forge/libforge/didresolver" - "github.com/fil-forge/sprue/pkg/identity" + "github.com/fil-forge/libforge/attestation" + "github.com/fil-forge/libforge/attestation/didmailto" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/sprue/pkg/lib/ucan_server" "github.com/fil-forge/sprue/pkg/service/ui" "github.com/fil-forge/sprue/pkg/store/agent" delegation_store "github.com/fil-forge/sprue/pkg/store/delegation" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" + "github.com/fil-forge/ucantone/did/web" "github.com/fil-forge/ucantone/ipld/codec/dagcbor" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" @@ -48,7 +52,7 @@ func WithInsecureDIDResolution(enabled bool) Option { // Service implements the sprue upload service logic. type Service struct { - identity *identity.Identity + identity identity.Identity agentStore agent.Store delegationStore delegation_store.Store logger *zap.Logger @@ -56,8 +60,8 @@ type Service struct { } // New creates a new Service instance. -func New(id *identity.Identity, agentStore agent.Store, delegationStore delegation_store.Store, handlers []server.Route, logger *zap.Logger, options ...Option) (*Service, error) { - server, err := createUCANServer(id.Signer, agentStore, handlers, logger, options...) +func New(id identity.Identity, agentStore agent.Store, delegationStore delegation_store.Store, handlers []server.Route, logger *zap.Logger, options ...Option) (*Service, error) { + server, err := createUCANServer(id.Issuer, agentStore, handlers, logger, options...) if err != nil { return nil, err } @@ -71,30 +75,38 @@ func New(id *identity.Identity, agentStore agent.Store, delegationStore delegati } // createUCANServer creates the UCAN RPC server with registered handlers. -func createUCANServer(id principal.Signer, agentStore agent.Store, handlers []server.Route, logger *zap.Logger, options ...Option) (*server.HTTPServer, error) { +func createUCANServer(id multikey.Issuer, agentStore agent.Store, handlers []server.Route, logger *zap.Logger, options ...Option) (*server.HTTPServer, error) { cfg := serviceConfig{} for _, opt := range options { opt(&cfg) } - httpResolverOpts := []didresolver.Option{} + webResolverOpts := []web.Option{} if cfg.insecureDIDResolution { logger.Warn("insecure DID resolution enabled: did:web will be resolved over HTTP instead of HTTPS; this should only be used for development purposes") - httpResolverOpts = append(httpResolverOpts, didresolver.InsecureResolution()) + webResolverOpts = append(webResolverOpts, web.WithInsecure(true)) } - httpResolver, err := didresolver.NewHTTPResolver(httpResolverOpts...) + webResolver, err := web.NewResolver(webResolverOpts...) if err != nil { return nil, err } - cacheResolver, err := didresolver.NewCachedResolver(httpResolver.Resolve, time.Hour*3) + + selfDoc, err := identity.Identity{Issuer: id}.DIDDocument() if err != nil { - return nil, err + return nil, fmt.Errorf("creating DID document for service identity: %w", err) } - selfResolver := didresolver.NewSelfResolver(id) - webResolver := didresolver.NewTieredResolver( - selfResolver.Resolve, - cacheResolver.Resolve, - ) + + resolver := resolver.ByMethod{ + "key": key.Resolver, + "web": resolver.Tiered{ + resolver.WellKnown{id.DID(): selfDoc}, + resolver.NewCached(webResolver, time.Hour*3), + }, + "mailto": didmailto.NewResolver(id.DID()), + } + + factories := validator.DefaultFactories() + factories[attestation.Type] = attestation.NewVerifierFactory(resolver, factories) serverOpts := append( slices.Clone(cfg.serverOptions), @@ -102,13 +114,8 @@ func createUCANServer(id principal.Signer, agentStore agent.Store, handlers []se server.WithEventListener(&ucan_server.AgentMessageLogger{Logger: logger, AgentStore: agentStore}), server.WithEventListener(&ucan_server.ErrorHandler{Logger: logger}), server.WithValidationOptions( - validator.WithDIDVerifierResolvers(map[string]validator.DIDVerifierResolverFunc{ - "key": ucan_server.ResolveDIDKey, - "web": webResolver.Resolve, - }), - validator.WithNonStandardSignatureVerifier( - ucan_server.NewAttestationVerifier(id.Verifier()), - ), + validator.WithDIDResolver(resolver), + validator.WithVerifierFactories(factories), ), )