diff --git a/.github/workflows/workspace-test.yml b/.github/workflows/workspace-test.yml new file mode 100644 index 00000000..37776415 --- /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/cli/identity/root.go b/cmd/cli/identity/root.go index 44126f1a..75a9414b 100644 --- a/cmd/cli/identity/root.go +++ b/cmd/cli/identity/root.go @@ -6,7 +6,7 @@ import ( "os" "github.com/fil-forge/libforge/identity" - "github.com/fil-forge/ucantone/principal/ed25519" + "github.com/fil-forge/ucantone/multikey/ed25519" "github.com/spf13/cobra" ) @@ -53,11 +53,11 @@ func init() { } func doGenerate(cmd *cobra.Command, _ []string) error { - signer, err := ed25519.Generate() + signer, err := ed25519.GenerateIssuer() if err != nil { return fmt.Errorf("generate key: %w", err) } - pem, err := identity.EncodeEd25519SignerToPEM(signer) + pem, err := identity.EncodeSignerToPEM(signer) if err != nil { return fmt.Errorf("encoding ed25519 private key to PEM: %w", err) } @@ -78,11 +78,11 @@ func doParse(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("reading pem file: %w", err) } - key, err := identity.DecodeEd25519SignerFromPEM(pemData) + key, err := identity.DecodeSignerFromPEM(pemData) if err != nil { return fmt.Errorf("decoding ed25519 private key: %w", err) } - cmd.Printf("# %s\n", key.DID().String()) + cmd.Printf("# %s\n", key.KeyDID().String()) return nil } diff --git a/cmd/cli/serve/full.go b/cmd/cli/serve/full.go index 9b5f9a14..7e9450e4 100644 --- a/cmd/cli/serve/full.go +++ b/cmd/cli/serve/full.go @@ -333,7 +333,7 @@ func fullServer(cmd *cobra.Command, _ []string) error { if err := initTelemetry( cmd.Context(), - appCfg.Identity.Signer.DID().String(), + appCfg.Identity.Issuer.DID().String(), userCfg.Network, appCfg.Storage.DataDir, appCfg.Telemetry, @@ -384,7 +384,7 @@ func fullServer(cmd *cobra.Command, _ []string) error { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { // Print server startup information - cliutil.PrintHero(cmd.OutOrStdout(), appCfg.Identity.Signer.DID()) + cliutil.PrintHero(cmd.OutOrStdout(), appCfg.Identity.Issuer.DID()) cmd.Println("Piri Running on: " + appCfg.Server.Host + ":" + strconv.Itoa(int(appCfg.Server.Port))) cmd.Println("Piri Public Endpoint: " + appCfg.Server.PublicURL.String()) @@ -393,7 +393,7 @@ func fullServer(cmd *cobra.Command, _ []string) error { "com/fil-forge/piri/cli/serve"), ctx, "full", - attribute.String("did", appCfg.Identity.Signer.DID().String()), + attribute.String("did", appCfg.Identity.Issuer.DID().String()), attribute.String("owner_address", appCfg.PDPService.OwnerAddress.String()), attribute.String("public_url", appCfg.Server.PublicURL.String()), attribute.Int64("proof_set", int64(appCfg.UCANService.ProofSetID)), diff --git a/cmd/cli/setup/register.go b/cmd/cli/setup/register.go index 526ecff7..0c5afc31 100644 --- a/cmd/cli/setup/register.go +++ b/cmd/cli/setup/register.go @@ -19,7 +19,6 @@ import ( replicacmds "github.com/fil-forge/libforge/commands/blob/replica" "github.com/fil-forge/libforge/commands/pdp" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" "github.com/fil-forge/ucantone/ucan/delegation" @@ -686,7 +685,7 @@ func walletKeyFromWalletFile(walletPath string) (*wallet.Key, error) { return wallet.NewKey(keystore.KeyInfo{PrivateKey: ki.PrivateKey}) } -func registerWithContract(ctx context.Context, cmd *cobra.Command, id principal.Signer, pdpSvc *service.PDPService) (uint64, error) { +func registerWithContract(ctx context.Context, cmd *cobra.Command, id ucan.Issuer, pdpSvc *service.PDPService) (uint64, error) { // check if the provider is already registered with the contract status, err := pdpSvc.GetProviderStatus(ctx) if err != nil { @@ -793,7 +792,7 @@ func registerWithDelegator(ctx context.Context, cmd *cobra.Command, cfg *appcfg. return "", "", fmt.Errorf("creating delegator client: %w", err) } - operatorDID := cfg.Identity.Signer.DID().String() + operatorDID := cfg.Identity.Issuer.DID().String() registered, err := c.IsRegistered(ctx, &delgclient.IsRegisteredRequest{DID: operatorDID}) if err != nil { @@ -808,7 +807,7 @@ func registerWithDelegator(ctx context.Context, cmd *cobra.Command, cfg *appcfg. if uploadDID == did.Undef { return "", "", fmt.Errorf("upload service DID is not configured") } - self := cfg.Identity.Signer + self := cfg.Identity.Issuer cmds := []ucan.Command{ blob.Allocate.Command, @@ -891,7 +890,7 @@ func encodeProofChain(wire []byte) (string, error) { return base64.StdEncoding.EncodeToString(wire), nil } -func requestContractApproval(ctx context.Context, id principal.Signer, flags *initFlags, ownerAddress common.Address) error { +func requestContractApproval(ctx context.Context, id ucan.Issuer, flags *initFlags, ownerAddress common.Address) error { // create a signature by signing our own did with the private key of our did signature := id.Sign([]byte(id.DID().String())) @@ -1026,12 +1025,12 @@ func doInit(cmd *cobra.Command, _ []string) error { return err } defer fxApp.Stop(ctx) - cmd.PrintErrf("✅ Node created with DID: %s\n", cfg.Identity.Signer.DID().String()) + cmd.PrintErrf("✅ Node created with DID: %s\n", cfg.Identity.Issuer.DID().String()) cmd.PrintErrln() // Step 3: Register with the smart contract cmd.PrintErrln("[3/7] Registering provider with contract...") - providerID, err := registerWithContract(ctx, cmd, cfg.Identity.Signer, pdpSvc) + providerID, err := registerWithContract(ctx, cmd, cfg.Identity.Issuer, pdpSvc) if err != nil { return err } @@ -1040,7 +1039,7 @@ func doInit(cmd *cobra.Command, _ []string) error { // Step 4: Request approval to join contract from storacha cmd.PrintErrln("[4/7] Requesting approval to join contract from Storacha...") - if err := requestContractApproval(ctx, cfg.Identity.Signer, flags, ownerAddress); err != nil { + if err := requestContractApproval(ctx, cfg.Identity.Issuer, flags, ownerAddress); err != nil { return err } cmd.PrintErrln("✅ Node approved to join contract by Storacha") diff --git a/go.mod b/go.mod index 918cdc32..ae3e9aea 100644 --- a/go.mod +++ b/go.mod @@ -15,9 +15,9 @@ require ( github.com/fil-forge/delegator v0.0.0-20260619085531-c96197bec34c github.com/fil-forge/filecoin-services/go v0.0.0-20260507172456-36ebe4467390 github.com/fil-forge/go-ipni-tools v0.0.0-20260519194815-545b9421aec0 - github.com/fil-forge/libforge v0.0.0-20260619084920-1753f2265c95 - github.com/fil-forge/piri-signing-service v0.0.0-20260527011208-918512802357 - github.com/fil-forge/ucantone v0.0.0-20260527115858-517b03bc3c72 + github.com/fil-forge/libforge v0.0.0-20260619083649-eb26d871cda1 + github.com/fil-forge/piri-signing-service v0.0.0-20260619151844-6c3d40a4bf54 + github.com/fil-forge/ucantone v0.0.0-20260619013642-7985ec010b88 github.com/filecoin-project/go-address v1.2.0 github.com/filecoin-project/go-commp-utils v0.1.4 github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20240802040721-2a04ffc8ffe8 @@ -303,7 +303,7 @@ require ( go.uber.org/mock v0.6.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect + golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/term v0.42.0 // indirect diff --git a/go.sum b/go.sum index b68c3923..ba065b9b 100644 --- a/go.sum +++ b/go.sum @@ -553,12 +553,12 @@ github.com/fil-forge/go-ipni-tools v0.0.0-20260519194815-545b9421aec0 h1:HAfXUPv github.com/fil-forge/go-ipni-tools v0.0.0-20260519194815-545b9421aec0/go.mod h1:3NRV/7wc4/0uzzrGdI7NoN/yeF1UvqKRwMyjBqGc5s0= github.com/fil-forge/go-ucanto v0.0.0-20260507172450-5cb5d073f8ab h1:2J2cDThqTKP6/0k3SfdlSxfyPa3aLqjTYnmvbEcryfg= github.com/fil-forge/go-ucanto v0.0.0-20260507172450-5cb5d073f8ab/go.mod h1:lZF3UXZ2hGLKYmXdquG50JqI9pRlUrV6lubGtgOYfwc= -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/piri-signing-service v0.0.0-20260527011208-918512802357 h1:sTK8Yc/kds7MkG0cpK5DGDtDCtU1ZwgQWc4OzRf3ZP4= -github.com/fil-forge/piri-signing-service v0.0.0-20260527011208-918512802357/go.mod h1:fgg5hE/BlnFlR5qXsT0POv6GWVu7cj526s7v2+mdJXo= -github.com/fil-forge/ucantone v0.0.0-20260527115858-517b03bc3c72 h1:FFK4CC7IfLfwa5ZQExdkZayPc6Tg0JgVK4jhn2hd2cY= -github.com/fil-forge/ucantone v0.0.0-20260527115858-517b03bc3c72/go.mod h1:xQ1oQ2UgA8xFpNxpyj2v+jiW2KVDAi90xjy1OjUkNXI= +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/piri-signing-service v0.0.0-20260619151844-6c3d40a4bf54 h1:KzQzCcEBBF6AfhZOwbQIPh5W2HwCgLS8VFTmch0oMgo= +github.com/fil-forge/piri-signing-service v0.0.0-20260619151844-6c3d40a4bf54/go.mod h1:O3GqUy+G7hb+oiGW6Wp77W2lRmZs7bewM9s/Vy4D6qo= +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/filecoin-ffi v1.34.0 h1:OvcsvsFUCwzLOGT949dsJEqSLyGx4d8TPPRrmrzlQbk= github.com/filecoin-project/filecoin-ffi v1.34.0/go.mod h1:AXLJk1PscWAwEa9CdqdiFwj1ttVJ+UIm8YQDPpTqBjg= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= @@ -1946,8 +1946,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= diff --git a/pkg/admin/httpapi/client/client.go b/pkg/admin/httpapi/client/client.go index 47aba619..78a51178 100644 --- a/pkg/admin/httpapi/client/client.go +++ b/pkg/admin/httpapi/client/client.go @@ -12,12 +12,12 @@ import ( "os" "time" - "github.com/fil-forge/ucantone/principal" "github.com/golang-jwt/jwt/v4" "github.com/fil-forge/libforge/identity" "github.com/fil-forge/piri/pkg/admin/httpapi" "github.com/fil-forge/piri/pkg/config" + "github.com/fil-forge/ucantone/multikey" ) type Client struct { @@ -39,12 +39,12 @@ func WithHTTPClient(client *http.Client) Option { } } -// WithBearerFromSigner configures the Authorization header using a JWT signed by the provided signer. -func WithBearerFromSigner(id principal.Signer) Option { +// WithBearerFromSigner configures the Authorization header using a JWT signed by the provided issuer. +func WithBearerFromSigner(id multikey.Signer) Option { return func(c *Client) error { authHeader, err := createAuthBearerTokenFromID(id) if err != nil { - return fmt.Errorf("creating auth header from signer: %w", err) + return fmt.Errorf("creating auth header from issuer: %w", err) } c.authHeader = authHeader return nil @@ -89,7 +89,7 @@ func NewFromConfig(cfg config.Client) (*Client, error) { return nil, fmt.Errorf("reading identity key file: %w", err) } - id, err := identity.DecodeEd25519SignerFromPEM(pem) + id, err := identity.DecodeSignerFromPEM(pem) if err != nil { return nil, fmt.Errorf("loading identity key file: %w", err) } @@ -327,7 +327,7 @@ func (c *Client) ReloadConfig(ctx context.Context) (*httpapi.ConfigResponse, err return &resp, nil } -func createAuthBearerTokenFromID(id principal.Signer) (string, error) { +func createAuthBearerTokenFromID(id multikey.Signer) (string, error) { claims := jwt.MapClaims{ "service_name": "storacha", } diff --git a/pkg/admin/httpapi/handlers/routes.go b/pkg/admin/httpapi/handlers/routes.go index c0cb607a..9a197744 100644 --- a/pkg/admin/httpapi/handlers/routes.go +++ b/pkg/admin/httpapi/handlers/routes.go @@ -1,7 +1,6 @@ package handlers import ( - "crypto/ed25519" "fmt" "github.com/golang-jwt/jwt/v4" @@ -31,12 +30,11 @@ type AdminRoutesParams struct { } func NewRoutes(params AdminRoutesParams) (echofx.RouteRegistrar, error) { - if params.Identity.Signer == nil { + if params.Identity.Issuer == nil { return nil, fmt.Errorf("missing identity signer for jwt auth") } - publicKey := ed25519.PublicKey(params.Identity.Signer.Verifier().Raw()) jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: publicKey, + SigningKey: params.Identity.Issuer.PublicKey(), SigningMethod: jwt.SigningMethodEdDSA.Alg(), }) diff --git a/pkg/config/app/identity.go b/pkg/config/app/identity.go index ca156e13..d3ecdad3 100644 --- a/pkg/config/app/identity.go +++ b/pkg/config/app/identity.go @@ -1,11 +1,9 @@ package app -import ( - "github.com/fil-forge/ucantone/principal" -) +import "github.com/fil-forge/ucantone/multikey" // IdentityConfig contains identity-related configuration type IdentityConfig struct { - // The principal signer for this service - Signer principal.Signer + // The principal issuer for this service + Issuer multikey.Issuer } diff --git a/pkg/config/identity.go b/pkg/config/identity.go index 6b200820..d2897d83 100644 --- a/pkg/config/identity.go +++ b/pkg/config/identity.go @@ -6,6 +6,7 @@ import ( "github.com/fil-forge/libforge/identity" "github.com/fil-forge/piri/pkg/config/app" + "github.com/fil-forge/ucantone/multikey" ) type IdentityConfig struct { @@ -21,11 +22,11 @@ func (i IdentityConfig) ToAppConfig() (app.IdentityConfig, error) { if err != nil { return app.IdentityConfig{}, fmt.Errorf("reading identity key file: %w", err) } - id, err := identity.DecodeEd25519SignerFromPEM(pem) + id, err := identity.DecodeSignerFromPEM(pem) if err != nil { return app.IdentityConfig{}, fmt.Errorf("decoding identity key file: %w", err) } return app.IdentityConfig{ - Signer: id, + Issuer: multikey.KeyIssuer(id), }, nil } diff --git a/pkg/fx/app/common.go b/pkg/fx/app/common.go index e64b5a8c..8fd91dbd 100644 --- a/pkg/fx/app/common.go +++ b/pkg/fx/app/common.go @@ -35,7 +35,7 @@ func CommonModules(cfg app.AppConfig) fx.Option { fx.Supply(cfg.PDPService.Aggregation.Manager), fx.Supply(cfg.PDPService.Gas), - identity.Module, // Provides principal.Signer + identity.Module, // Provides ucan.Signer proofs.Module, // Provides service for requesting service proofs echo.Module, // Provides Echo server with route registration database.Module, // Provides SQLite database for job queues diff --git a/pkg/fx/identity/provider.go b/pkg/fx/identity/provider.go index 59e4b844..57fb2765 100644 --- a/pkg/fx/identity/provider.go +++ b/pkg/fx/identity/provider.go @@ -1,9 +1,9 @@ package identity import ( - "github.com/fil-forge/ucantone/principal" "go.uber.org/fx" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/piri/pkg/config/app" ) @@ -11,7 +11,7 @@ var Module = fx.Module("identity", fx.Provide(ProvideIdentity), ) -// ProvideIdentity extracts the principal signer from the identity config. -func ProvideIdentity(cfg app.IdentityConfig) principal.Signer { - return cfg.Signer +// ProvideIdentity extracts the issuer from the identity config. +func ProvideIdentity(cfg app.IdentityConfig) identity.Identity { + return identity.Identity{Issuer: cfg.Issuer} } diff --git a/pkg/fx/pdp/provider.go b/pkg/fx/pdp/provider.go index 1b7beaa2..3f6f60af 100644 --- a/pkg/fx/pdp/provider.go +++ b/pkg/fx/pdp/provider.go @@ -82,7 +82,7 @@ type Params struct { func ProvidePDPService(params Params) (*service.PDPService, error) { return service.New( params.Config, - params.ID.Signer, + params.ID.Issuer, params.ServerConfig.PublicURL, params.DB, params.BlobStore, diff --git a/pkg/fx/root/provider.go b/pkg/fx/root/provider.go index dc9ab75e..d6353e2b 100644 --- a/pkg/fx/root/provider.go +++ b/pkg/fx/root/provider.go @@ -1,10 +1,10 @@ package root import ( - "github.com/fil-forge/ucantone/principal" "github.com/labstack/echo/v4" "go.uber.org/fx" + "github.com/fil-forge/libforge/identity" echofx "github.com/fil-forge/piri/pkg/fx/echo" "github.com/fil-forge/piri/pkg/server" ) @@ -24,11 +24,11 @@ var _ echofx.RouteRegistrar = (*Handler)(nil) // Handler provides the root route handler type Handler struct { - id principal.Signer + id identity.Identity } // NewRootHandler creates a new root handler -func NewRootHandler(id principal.Signer) *Handler { +func NewRootHandler(id identity.Identity) *Handler { return &Handler{id: id} } diff --git a/pkg/internal/testutil/config.go b/pkg/internal/testutil/config.go index b5af39ec..6c4cc3b6 100644 --- a/pkg/internal/testutil/config.go +++ b/pkg/internal/testutil/config.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" utestutil "github.com/fil-forge/ucantone/testutil" "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" @@ -30,7 +30,7 @@ func NewTestConfig(t *testing.T, opts ...TestConfigOption) app.AppConfig { // Start with sensible defaults for testing cfg := app.AppConfig{ Identity: app.IdentityConfig{ - Signer: utestutil.RandomSigner(t), // per-test random signer + Issuer: utestutil.RandomMultikeyIssuer(t), // per-test random signer }, Server: app.ServerConfig{ Host: "localhost", @@ -64,10 +64,10 @@ func NewTestConfig(t *testing.T, opts ...TestConfigOption) app.AppConfig { return cfg } -// WithSigner sets the identity signer -func WithSigner(signer principal.Signer) TestConfigOption { +// WithIssuer sets the identity signer +func WithIssuer(issuer multikey.Issuer) TestConfigOption { return func(_ *testing.T, cfg *app.AppConfig) { - cfg.Identity.Signer = signer + cfg.Identity.Issuer = issuer } } diff --git a/pkg/pdp/aggregation/manager/accepter.go b/pkg/pdp/aggregation/manager/accepter.go index 9a6d34b0..b7cfc9c6 100644 --- a/pkg/pdp/aggregation/manager/accepter.go +++ b/pkg/pdp/aggregation/manager/accepter.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/fil-forge/libforge/commands/pdp" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/fil-forge/ucantone/ucan/receipt" @@ -18,13 +17,13 @@ import ( ) type PieceAcceptor struct { - issuer principal.Signer + issuer ucan.Issuer aggregateStore ipldstore.KVStore[cid.Cid, types.Aggregate] receiptStore receiptstore.ReceiptStore resolver apitypes.PieceResolverAPI } -func NewPieceAccepter(issuer principal.Signer, aggregateStore types.Store, receiptStore receiptstore.ReceiptStore, resolver apitypes.PieceResolverAPI) *PieceAcceptor { +func NewPieceAccepter(issuer ucan.Issuer, aggregateStore types.Store, receiptStore receiptstore.ReceiptStore, resolver apitypes.PieceResolverAPI) *PieceAcceptor { return &PieceAcceptor{ issuer: issuer, aggregateStore: aggregateStore, @@ -55,7 +54,7 @@ func (pa *PieceAcceptor) AcceptPieces(ctx context.Context, aggregateLinks []cid. return nil } -func GenerateReceipts(ctx context.Context, issuer ucan.Signer, aggregate types.Aggregate, resolver apitypes.PieceResolverAPI) ([]*receipt.Receipt, error) { +func GenerateReceipts(ctx context.Context, issuer ucan.Issuer, aggregate types.Aggregate, resolver apitypes.PieceResolverAPI) ([]*receipt.Receipt, error) { receipts := make([]*receipt.Receipt, 0, len(aggregate.Pieces)) for _, aggregatePiece := range aggregate.Pieces { blob, found, err := resolver.ResolveToBlob(ctx, aggregatePiece.Link.Hash()) @@ -90,7 +89,7 @@ func GenerateReceipts(ctx context.Context, issuer ucan.Signer, aggregate types.A return receipts, nil } -func GenerateReceiptsForAggregates(ctx context.Context, issuer ucan.Signer, aggregates []types.Aggregate, resolver apitypes.PieceResolverAPI) ([]*receipt.Receipt, error) { +func GenerateReceiptsForAggregates(ctx context.Context, issuer ucan.Issuer, aggregates []types.Aggregate, resolver apitypes.PieceResolverAPI) ([]*receipt.Receipt, error) { size := 0 for _, aggregate := range aggregates { size += len(aggregate.Pieces) diff --git a/pkg/pdp/httpapi/client/client.go b/pkg/pdp/httpapi/client/client.go index 423fe592..abbf3cab 100644 --- a/pkg/pdp/httpapi/client/client.go +++ b/pkg/pdp/httpapi/client/client.go @@ -3,7 +3,6 @@ package client import ( "bytes" "context" - "crypto/ed25519" "encoding/json" "fmt" "io" @@ -16,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/fil-forge/libforge/identity" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/golang-jwt/jwt/v4" "github.com/google/uuid" "github.com/ipfs/go-cid" @@ -95,7 +94,7 @@ func WithHTTPClient(client *http.Client) Option { } } -func WithBearerFromSigner(id principal.Signer) Option { +func WithBearerFromSigner(id multikey.Signer) Option { return func(c *Client) error { authHeader, err := createAuthBearerTokenFromID(id) if err != nil { @@ -151,14 +150,14 @@ func NewFromConfig(cfg config.Client) (*Client, error) { if err != nil { return nil, fmt.Errorf("reading identity key file: %w", err) } - id, err := identity.DecodeEd25519SignerFromPEM(pem) + id, err := identity.DecodeSignerFromPEM(pem) if err != nil { return nil, fmt.Errorf("decoding identity key file: %w", err) } return New(endpoint, WithBearerFromSigner(id)) } -func createAuthBearerTokenFromID(id principal.Signer) (string, error) { +func createAuthBearerTokenFromID(id multikey.Signer) (string, error) { claims := jwt.MapClaims{ "service_name": "storacha", } @@ -169,7 +168,7 @@ func createAuthBearerTokenFromID(id principal.Signer) (string, error) { // Sign the token // ucantone signers expose Raw() as the 32-byte ed25519 seed; JWT // EdDSA needs the full 64-byte key derived from the seed. - tokenString, err := token.SignedString(ed25519.NewKeyFromSeed(id.Raw())) + tokenString, err := token.SignedString(id.PrivateKey()) if err != nil { return "", fmt.Errorf("failed to sign token: %v", err) } diff --git a/pkg/pdp/httpapi/client/client_test.go b/pkg/pdp/httpapi/client/client_test.go index 7082dc81..911aa80d 100644 --- a/pkg/pdp/httpapi/client/client_test.go +++ b/pkg/pdp/httpapi/client/client_test.go @@ -1,7 +1,6 @@ package client import ( - "crypto/ed25519" "strings" "testing" @@ -11,7 +10,7 @@ import ( ) func TestCreateAuthBearerTokenFromID(t *testing.T) { - signer := testutil.RandomSigner(t) + signer := testutil.RandomMultikeyIssuer(t) token, err := createAuthBearerTokenFromID(signer) require.NoError(t, err) @@ -19,7 +18,7 @@ func TestCreateAuthBearerTokenFromID(t *testing.T) { parsed, err := jwt.Parse(strings.TrimPrefix(token, "Bearer "), func(token *jwt.Token) (interface{}, error) { require.Equal(t, jwt.SigningMethodEdDSA.Alg(), token.Method.Alg()) - return ed25519.PublicKey(signer.Verifier().Raw()), nil + return signer.PublicKey(), nil }) require.NoError(t, err) require.True(t, parsed.Valid) @@ -30,7 +29,7 @@ func TestCreateAuthBearerTokenFromID(t *testing.T) { } func TestWithBearerFromSignerSetsHeader(t *testing.T) { - signer := testutil.RandomSigner(t) + signer := testutil.RandomMultikeySigner(t) client := &Client{} err := WithBearerFromSigner(signer)(client) diff --git a/pkg/pdp/httpapi/server/register.go b/pkg/pdp/httpapi/server/register.go index a9a24322..1846263f 100644 --- a/pkg/pdp/httpapi/server/register.go +++ b/pkg/pdp/httpapi/server/register.go @@ -1,7 +1,6 @@ package server import ( - "crypto/ed25519" "fmt" "path" @@ -28,12 +27,11 @@ type PDPHandler struct { } func NewPDPHandler(service *service.PDPService, identity app.IdentityConfig) (*PDPHandler, error) { - if identity.Signer == nil { + if identity.Issuer == nil { return nil, fmt.Errorf("missing identity signer for jwt auth") } - publicKey := ed25519.PublicKey(identity.Signer.Verifier().Raw()) jwtMiddleware := echojwt.WithConfig(echojwt.Config{ - SigningKey: publicKey, + SigningKey: identity.Issuer.PublicKey(), SigningMethod: jwt.SigningMethodEdDSA.Alg(), }) diff --git a/pkg/pdp/service/service.go b/pkg/pdp/service/service.go index 157e048c..4451967d 100644 --- a/pkg/pdp/service/service.go +++ b/pkg/pdp/service/service.go @@ -46,7 +46,7 @@ type EthClient interface { type PDPService struct { cfg appconfig.PDPServiceConfig - id ucan.Signer + id ucan.Issuer endpoint url.URL address common.Address blobstore blobstore.Blobstore @@ -77,7 +77,7 @@ type PDPService struct { func New( cfg appconfig.PDPServiceConfig, - id ucan.Signer, + id ucan.Issuer, endpoint url.URL, db *gorm.DB, bs blobstore.Blobstore, diff --git a/pkg/server/server.go b/pkg/server/server.go index d5a8e423..64efcf06 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -6,10 +6,10 @@ import ( "net/http" "strings" - "github.com/fil-forge/ucantone/principal" logging "github.com/ipfs/go-log/v2" "github.com/fil-forge/piri/pkg/build" + "github.com/fil-forge/ucantone/ucan" ) var log = logging.Logger("server") @@ -25,7 +25,7 @@ type BuildInfo struct { } // NewHandler displays version info. -func NewHandler(id principal.Signer) http.Handler { +func NewHandler(id ucan.Issuer) http.Handler { info := ServerInfo{ ID: id.DID().String(), Build: BuildInfo{ diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index 9d48e11b..0914d103 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -7,15 +7,14 @@ import ( "net/http/httptest" "testing" - "github.com/fil-forge/ucantone/principal/ed25519" + "github.com/fil-forge/ucantone/testutil" "github.com/stretchr/testify/require" "github.com/fil-forge/piri/pkg/build" ) func TestVersionInfoHandler(t *testing.T) { - id, err := ed25519.Generate() - require.NoError(t, err) + id := testutil.RandomIssuer(t) ts := httptest.NewServer(NewHandler(id)) defer ts.Close() diff --git a/pkg/service/egresstracker/fx.go b/pkg/service/egresstracker/fx.go index cf5bad67..f1d3281a 100644 --- a/pkg/service/egresstracker/fx.go +++ b/pkg/service/egresstracker/fx.go @@ -10,7 +10,7 @@ import ( "runtime" "time" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "go.uber.org/fx" @@ -92,7 +92,7 @@ func ProvideReceiptsClient(cfg app.EgressTrackerServiceConfig) *receipts.Client func NewEgressTrackerService( lc fx.Lifecycle, - id principal.Signer, + id ucan.Signer, journal retrievaljournal.Journal, consolidationStore consolidationstore.Store, queue EgressTrackerQueue, diff --git a/pkg/service/egresstracker/service.go b/pkg/service/egresstracker/service.go index 76074574..f5c1b137 100644 --- a/pkg/service/egresstracker/service.go +++ b/pkg/service/egresstracker/service.go @@ -18,7 +18,7 @@ import ( "github.com/fil-forge/libforge/commands" "github.com/fil-forge/libforge/commands/space/egress" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/ipfs/go-cid" @@ -37,7 +37,7 @@ const journalRotationPeriod = time.Hour * 12 // Service stores receipts from `space/content/retrieve` invocations, batches them and sends // them to an egress tracking service via `space/egress/track` invocations. type Service struct { - id principal.Signer + id ucan.Signer egressTrackerDID did.DID // egressTrackerProofs is the ordered chain (root → leaf) issued by the // delegator for the egress-tracker service. Every link must accompany @@ -57,7 +57,7 @@ type Service struct { } func New( - id principal.Signer, + id ucan.Signer, egressTrackerConn client.Connection, egressTrackerProofs []ucan.Delegation, batchEndpoint *url.URL, diff --git a/pkg/service/proofs/caching.go b/pkg/service/proofs/caching.go index affd5f8c..b74ea535 100644 --- a/pkg/service/proofs/caching.go +++ b/pkg/service/proofs/caching.go @@ -44,7 +44,7 @@ func NewCachingProofService() *CachingProofService { // command. A cached delegation may be returned if it's still valid. func (ps *CachingProofService) RequestAccess( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, command ucan.Command, cause ucan.Invocation, @@ -116,7 +116,7 @@ func (ps *CachingProofService) RequestAccess( func requestDelegation( ctx context.Context, httpClient *client.HTTPClient, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, command ucan.Command, cause ucan.Invocation, diff --git a/pkg/service/proofs/caching_test.go b/pkg/service/proofs/caching_test.go index eaa444c8..00324cf3 100644 --- a/pkg/service/proofs/caching_test.go +++ b/pkg/service/proofs/caching_test.go @@ -36,9 +36,9 @@ import ( // The grant handler issues a short-lived delegation per call with a random // nonce, so nonce equality across calls is a reliable cache-hit signal. func TestCachingProofsService(t *testing.T) { - webService := testutil.RandomSigner(t) - alice := testutil.RandomSigner(t) - bob := testutil.RandomSigner(t) + webService := testutil.RandomIssuer(t) + alice := testutil.RandomIssuer(t) + bob := testutil.RandomIssuer(t) // /access/grant is the bootstrap step in the access flow; the proofs // service self-issues the invocation (subject == issuer), which the diff --git a/pkg/service/proofs/interface.go b/pkg/service/proofs/interface.go index 32968f6b..832b6ab0 100644 --- a/pkg/service/proofs/interface.go +++ b/pkg/service/proofs/interface.go @@ -20,7 +20,7 @@ type ProofService interface { // context. RequestAccess( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, audience did.DID, command ucan.Command, cause ucan.Invocation, diff --git a/pkg/service/publisher/fx.go b/pkg/service/publisher/fx.go index 2907692e..d664ae5e 100644 --- a/pkg/service/publisher/fx.go +++ b/pkg/service/publisher/fx.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/fil-forge/go-ipni-tools/pkg/store" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/libforge/identity" "go.uber.org/fx" "github.com/fil-forge/piri/pkg/config/app" @@ -29,7 +29,7 @@ var Module = fx.Module("publisher", func NewFx( pubCfg app.PublisherServiceConfig, idxCfg app.IndexingServiceConfig, - id principal.Signer, + id identity.Identity, publisherStore store.PublisherStore, ) (*PublisherService, error) { if pubCfg.PublicMaddr.String() == "" { diff --git a/pkg/service/publisher/publisher.go b/pkg/service/publisher/publisher.go index 3bca6593..66a7ba02 100644 --- a/pkg/service/publisher/publisher.go +++ b/pkg/service/publisher/publisher.go @@ -12,6 +12,7 @@ import ( errdm "github.com/fil-forge/ucantone/errors/datamodel" "github.com/fil-forge/ucantone/execution" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/ucan" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" @@ -27,7 +28,6 @@ import ( "github.com/fil-forge/go-ipni-tools/pkg/store" "github.com/fil-forge/libforge/commands/assert" "github.com/fil-forge/libforge/commands/claim" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/fil-forge/piri/lib" @@ -49,7 +49,7 @@ func (p *threadSafeAsyncPublisher) Publish(ctx context.Context, pi peer.AddrInfo var log = logging.Logger("publisher") type PublisherService struct { - id principal.Signer + id ucan.Issuer asyncPublisher ipnipub.AsyncPublisher provider peer.AddrInfo indexingService app.IndexingServiceConfig @@ -134,7 +134,7 @@ func PublishLocationCommitment( func CacheClaim( ctx context.Context, - id principal.Signer, + id ucan.Issuer, indexingService app.IndexingServiceConfig, invocationProofs []ucan.Delegation, clm ucan.Invocation, @@ -209,7 +209,7 @@ var _ Publisher = (*PublisherService)(nil) // // Note: publicAddr address must be HTTP(S). func New( - id principal.Signer, + id multikey.Issuer, publisherStore store.PublisherStore, publicAddr multiaddr.Multiaddr, opts ...Option, diff --git a/pkg/service/replicator/fx.go b/pkg/service/replicator/fx.go index 7dcee38b..0e418dae 100644 --- a/pkg/service/replicator/fx.go +++ b/pkg/service/replicator/fx.go @@ -8,7 +8,7 @@ import ( "database/sql" "fmt" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" logging "github.com/ipfs/go-log/v2" "go.uber.org/fx" @@ -84,7 +84,7 @@ func ProvideReplicationQueue(lc fx.Lifecycle, params QueueParams) (*jobqueue.Job type Params struct { fx.In - ID principal.Signer + ID ucan.Signer Upload app.UploadServiceConfig Pieces pdptypes.PieceAPI Commp commp.Calculator diff --git a/pkg/service/signer/proofservicesigner.go b/pkg/service/signer/proofservicesigner.go index 222591a0..81601eaa 100644 --- a/pkg/service/signer/proofservicesigner.go +++ b/pkg/service/signer/proofservicesigner.go @@ -45,7 +45,7 @@ func NewProofServiceSigner( } } -func (s *proofServiceSigner) grant(ctx context.Context, issuer ucan.Signer, cmd ucan.Command) (ucan.Delegation, error) { +func (s *proofServiceSigner) grant(ctx context.Context, issuer ucan.Issuer, cmd ucan.Command) (ucan.Delegation, error) { d, err := s.proofService.RequestAccess( ctx, issuer, @@ -62,7 +62,7 @@ func (s *proofServiceSigner) grant(ctx context.Context, issuer ucan.Signer, cmd func (s *proofServiceSigner) SignCreateDataSet( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, dataSet *big.Int, payee common.Address, metadata []eip712.MetadataEntry, @@ -80,7 +80,7 @@ func (s *proofServiceSigner) SignCreateDataSet( func (s *proofServiceSigner) SignAddPieces( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, dataSet *big.Int, nonce *big.Int, pieceData [][]byte, @@ -101,7 +101,7 @@ func (s *proofServiceSigner) SignAddPieces( func (s *proofServiceSigner) SignSchedulePieceRemovals( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, dataSet *big.Int, pieceIds []*big.Int, proofsIn []ucan.Delegation, @@ -118,7 +118,7 @@ func (s *proofServiceSigner) SignSchedulePieceRemovals( func (s *proofServiceSigner) SignDeleteDataSet( ctx context.Context, - issuer ucan.Signer, + issuer ucan.Issuer, dataSet *big.Int, proofsIn []ucan.Delegation, options ...invocation.Option, diff --git a/pkg/service/signer/proofservicesigner_test.go b/pkg/service/signer/proofservicesigner_test.go index 9459c8fc..85f38bc0 100644 --- a/pkg/service/signer/proofservicesigner_test.go +++ b/pkg/service/signer/proofservicesigner_test.go @@ -15,7 +15,6 @@ import ( signerclient "github.com/fil-forge/piri-signing-service/pkg/client" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/client" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/testutil" "github.com/fil-forge/ucantone/ucan" @@ -29,7 +28,7 @@ import ( ) func TestProofServiceSigner(t *testing.T) { - signerServiceID := testutil.RandomSigner(t) + signerServiceID := testutil.RandomIssuer(t) srv := mockSigningServiceServer(t, signerServiceID) endpoint, err := url.Parse("http://test") @@ -41,7 +40,7 @@ func TestProofServiceSigner(t *testing.T) { proofService := proofs.NewCachingProofService() signingService := piriSigner.NewProofServiceSigner(sc, signerServiceID.DID(), httpClient, proofService) - alice := testutil.RandomSigner(t) + alice := testutil.RandomIssuer(t) t.Run("pdp/sign/dataset/create", func(t *testing.T) { payee := common.HexToAddress("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb") @@ -97,7 +96,7 @@ func TestProofServiceSigner(t *testing.T) { }) } -func mockSigningServiceServer(t *testing.T, id principal.Signer) *server.HTTPServer { +func mockSigningServiceServer(t *testing.T, id ucan.Issuer) *server.HTTPServer { mock := mockLibforgeSignature() srv := server.NewHTTP( id, diff --git a/pkg/store/acceptancestore/store.go b/pkg/store/acceptancestore/store.go index 71c26c9b..89e12cee 100644 --- a/pkg/store/acceptancestore/store.go +++ b/pkg/store/acceptancestore/store.go @@ -48,7 +48,7 @@ var _ AcceptanceStore = (*Store)(nil) // New creates an AcceptanceStore with the given backend and key encoder. func New(backend objectstore.ListableStore, encoder KeyEncoder) *Store { return &Store{ - store: genericstore.New[acceptance.Acceptance](backend, acceptance.Codec{}), + store: genericstore.New(backend, acceptance.Codec{}), encoder: encoder, } } diff --git a/pkg/store/consolidationstore/consolidation/consolidation_test.go b/pkg/store/consolidationstore/consolidation/consolidation_test.go index 861b3b73..632a5798 100644 --- a/pkg/store/consolidationstore/consolidation/consolidation_test.go +++ b/pkg/store/consolidationstore/consolidation/consolidation_test.go @@ -55,7 +55,7 @@ func TestConsolidation(t *testing.T) { func createTestConsolidation(t *testing.T) consolidation.Consolidation { t.Helper() - signer := testutil.RandomSigner(t) + signer := testutil.RandomIssuer(t) audience := testutil.RandomDID(t) inv, err := egress.Track.Invoke( diff --git a/pkg/store/consolidationstore/store_test.go b/pkg/store/consolidationstore/store_test.go index 5fa07357..5d07d151 100644 --- a/pkg/store/consolidationstore/store_test.go +++ b/pkg/store/consolidationstore/store_test.go @@ -102,11 +102,11 @@ func TestDatastoreConsolidationStore(t *testing.T) { func createTestConsolidation(t *testing.T) consolidation.Consolidation { t.Helper() - signer := testutil.RandomSigner(t) + issuer := testutil.RandomIssuer(t) audience := testutil.RandomDID(t) inv, err := egress.Track.Invoke( - signer, + issuer, audience, &egress.TrackArguments{ Receipts: testutil.RandomCID(t), diff --git a/pkg/store/invocationstore/store.go b/pkg/store/invocationstore/store.go index 385e0924..9b03d45e 100644 --- a/pkg/store/invocationstore/store.go +++ b/pkg/store/invocationstore/store.go @@ -40,7 +40,7 @@ var _ InvocationStore = (*Store)(nil) // New creates a InvocationStore with the given backend and key encoder. func New(backend objectstore.ListableStore, encoder KeyEncoder) *Store { return &Store{ - store: genericstore.New[ucan.Invocation](backend, Codec{}), + store: genericstore.New(backend, Codec{}), encoder: encoder, } } diff --git a/pkg/store/invocationstore/store_test.go b/pkg/store/invocationstore/store_test.go index 02520a7d..ad937bbf 100644 --- a/pkg/store/invocationstore/store_test.go +++ b/pkg/store/invocationstore/store_test.go @@ -16,7 +16,7 @@ func TestInvocationStore(t *testing.T) { store := NewDatastoreStore(datastore.NewMapDatastore()) inv, err := invocation.Invoke( - testutil.RandomSigner(t), + testutil.RandomIssuer(t), testutil.RandomDID(t), command.New("/whatever"), &commands.Unit{}, diff --git a/pkg/ucanhandlers/access/grant.go b/pkg/ucanhandlers/access/grant.go index fa5a6d26..7fa384e1 100644 --- a/pkg/ucanhandlers/access/grant.go +++ b/pkg/ucanhandlers/access/grant.go @@ -19,9 +19,9 @@ import ( "github.com/fil-forge/libforge/commands/assert" "github.com/fil-forge/libforge/commands/blob" "github.com/fil-forge/libforge/commands/blob/replica" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/ucantone/did" "github.com/fil-forge/ucantone/errors" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" "github.com/fil-forge/ucantone/ucan/delegation" @@ -36,9 +36,9 @@ const validity = time.Hour // UCAN method. type GrantDeps struct { fxlib.In - ID principal.Signer - Upload app.UploadServiceConfig - Resolvers validator.VerifierResolverMap + ID identity.Identity + Upload app.UploadServiceConfig + Resolver did.Resolver } func NewGrantHandler(deps GrantDeps) server.Route { @@ -83,7 +83,7 @@ func NewGrantHandler(deps GrantDeps) server.Route { // identities (e.g. the upload service) resolve correctly. validateOpts := []validator.Option{ validator.WithProofResolver(proofResolverFromMetadata(req.Metadata())), - validator.WithDIDVerifierResolvers(deps.Resolvers), + validator.WithDIDResolver(deps.Resolver), } grantedDlgs := make([]ucan.Delegation, 0, len(args.Attenuations)) diff --git a/pkg/ucanhandlers/blob/accept.go b/pkg/ucanhandlers/blob/accept.go index 31cc6b44..74307636 100644 --- a/pkg/ucanhandlers/blob/accept.go +++ b/pkg/ucanhandlers/blob/accept.go @@ -7,6 +7,7 @@ import ( "time" "github.com/fil-forge/libforge/commands" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan/container" @@ -20,7 +21,6 @@ import ( "github.com/fil-forge/libforge/commands/blob" "github.com/fil-forge/libforge/commands/pdp" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/invocation" "github.com/fil-forge/ucantone/ucan/promise" @@ -42,7 +42,7 @@ const InternalErrorName = "InternalError" // AcceptDeps is the dependency set populated by fx for the Accept handler. type AcceptDeps struct { fx.In - ID principal.Signer + ID identity.Identity Acceptances AcceptanceStore Pieces PieceReader Commp commp.Calculator diff --git a/pkg/ucanhandlers/blob/accept_test.go b/pkg/ucanhandlers/blob/accept_test.go index 33cecdee..f9c93cd2 100644 --- a/pkg/ucanhandlers/blob/accept_test.go +++ b/pkg/ucanhandlers/blob/accept_test.go @@ -6,6 +6,7 @@ import ( "github.com/fil-forge/libforge/commands/assert" "github.com/fil-forge/libforge/commands/blob" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/libforge/testutil" "github.com/fil-forge/ucantone/ucan" "github.com/ipfs/go-datastore" @@ -35,7 +36,7 @@ func newAcceptDeps(t *testing.T) (AcceptDeps, *pdpfake.Pieces, *acceptancestore. pub := &stubPublisher{} pieces := pdpfake.NewPieces() return AcceptDeps{ - ID: testutil.Alice, + ID: identity.Identity{Issuer: testutil.WebService}, Acceptances: accepts, Pieces: pieces, Commp: pdpfake.NewCommp(), diff --git a/pkg/ucanhandlers/blob/allocate.go b/pkg/ucanhandlers/blob/allocate.go index 59aa63c5..9ab02300 100644 --- a/pkg/ucanhandlers/blob/allocate.go +++ b/pkg/ucanhandlers/blob/allocate.go @@ -79,7 +79,7 @@ func NewBlobAllocateHandler(deps AllocateDeps) server.Route { // allocated into travels in the arguments. Authorization that the upload // service may invoke /blob/allocate is enforced by the validator's proof // chain (rooted at the provider). - if err := ucanhandlers.RequireSubject(req, deps.ID.Signer.DID()); err != nil { + if err := ucanhandlers.RequireSubject(req, deps.ID.Issuer.DID()); err != nil { return rsp.SetFailure(err) } diff --git a/pkg/ucanhandlers/blob/replica/allocate.go b/pkg/ucanhandlers/blob/replica/allocate.go index 37946e69..e60304b3 100644 --- a/pkg/ucanhandlers/blob/replica/allocate.go +++ b/pkg/ucanhandlers/blob/replica/allocate.go @@ -14,7 +14,7 @@ import ( "github.com/fil-forge/libforge/commands/blob/replica" "github.com/fil-forge/ucantone/errors" "github.com/fil-forge/ucantone/binding" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/container" "github.com/fil-forge/ucantone/ucan/invocation" @@ -42,7 +42,7 @@ const ( type ReplicaAllocateDeps struct { fxlib.In blob2.AllocateDeps - ID principal.Signer + ID ucan.Signer Replicator replicator.Replicator } diff --git a/pkg/ucanhandlers/blob/replica/transfer.go b/pkg/ucanhandlers/blob/replica/transfer.go index cf69d5e6..682a68f8 100644 --- a/pkg/ucanhandlers/blob/replica/transfer.go +++ b/pkg/ucanhandlers/blob/replica/transfer.go @@ -36,7 +36,7 @@ import ( ucancap "github.com/fil-forge/libforge/commands/ucan" "github.com/fil-forge/ucantone/client" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/ucan" "github.com/fil-forge/ucantone/ucan/delegation" "github.com/fil-forge/ucantone/ucan/invocation" @@ -56,7 +56,7 @@ var log = logging.Logger("storage/handlers/replica") // handler. type TransferDeps struct { fxlib.In - ID principal.Signer + ID ucan.Signer Acceptances blobhandler.AcceptanceStore Pieces blobhandler.PieceReader Commp commp.Calculator diff --git a/pkg/ucanhandlers/blob/retrieve.go b/pkg/ucanhandlers/blob/retrieve.go index da424efc..bfed4f31 100644 --- a/pkg/ucanhandlers/blob/retrieve.go +++ b/pkg/ucanhandlers/blob/retrieve.go @@ -12,7 +12,6 @@ import ( "github.com/fil-forge/libforge/ucan/retrieval" "github.com/fil-forge/ucantone/binding" "github.com/fil-forge/ucantone/errors" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/server" "github.com/fil-forge/ucantone/ucan/container" "github.com/multiformats/go-multihash" @@ -45,7 +44,6 @@ const ( // blob/retrieve UCAN method. type BlobRetrieveDeps struct { fxlib.In - ID principal.Signer Pieces types.PieceReaderAPI } diff --git a/pkg/ucanhandlers/content/retrieve.go b/pkg/ucanhandlers/content/retrieve.go index 163820bb..75bd6938 100644 --- a/pkg/ucanhandlers/content/retrieve.go +++ b/pkg/ucanhandlers/content/retrieve.go @@ -8,7 +8,6 @@ import ( "github.com/fil-forge/libforge/commands/content" "github.com/fil-forge/ucantone/binding" - "github.com/fil-forge/ucantone/principal" "github.com/fil-forge/ucantone/server" logging "github.com/ipfs/go-log/v2" fxlib "go.uber.org/fx" @@ -31,7 +30,6 @@ const NotAllocatedErrorName = "NotAllocated" type RetrieveDeps struct { fxlib.In - ID principal.Signer Allocations allocationstore.AllocationStore Pieces types.PieceReaderAPI } diff --git a/pkg/ucanhandlers/handler.go b/pkg/ucanhandlers/handler.go index cccd151d..af477c93 100644 --- a/pkg/ucanhandlers/handler.go +++ b/pkg/ucanhandlers/handler.go @@ -3,9 +3,9 @@ package ucanhandlers import ( "fmt" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/libforge/ucan/retrieval" "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/labstack/echo/v4" @@ -68,7 +68,7 @@ func ProvideRetrievalOption(ctor any) any { type RPCParams struct { fx.In - ID principal.Signer + ID identity.Identity Handlers []server.Route `group:"ucan_rpc_handlers"` Options []server.HTTPOption `group:"ucan_rpc_options"` } @@ -79,7 +79,7 @@ type RPCParams struct { type RetrievalParams struct { fx.In - ID principal.Signer + ID identity.Identity Handlers []server.Route `group:"ucan_retrieval_handlers"` Options []server.HTTPOption `group:"ucan_retrieval_options"` } diff --git a/pkg/ucanhandlers/pdp/info.go b/pkg/ucanhandlers/pdp/info.go index 1b16183a..95c43c62 100644 --- a/pkg/ucanhandlers/pdp/info.go +++ b/pkg/ucanhandlers/pdp/info.go @@ -12,8 +12,8 @@ import ( fxlib "go.uber.org/fx" "github.com/fil-forge/libforge/commands/pdp" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/ucantone/errors" - "github.com/fil-forge/ucantone/principal" libpiece "github.com/fil-forge/libforge/piece" pdptypes "github.com/fil-forge/piri/pkg/pdp/types" @@ -32,7 +32,7 @@ type PieceResolver interface { // PDPInfoDeps is the dependency set for the pdp/info UCAN method. type PDPInfoDeps struct { fxlib.In - ID principal.Signer + ID identity.Identity Receipts receiptstore.ReceiptStore Pieces PieceResolver } diff --git a/pkg/ucanhandlers/ucanfx/fx.go b/pkg/ucanhandlers/ucanfx/fx.go index b78fdb8a..bc13fadf 100644 --- a/pkg/ucanhandlers/ucanfx/fx.go +++ b/pkg/ucanhandlers/ucanfx/fx.go @@ -1,21 +1,17 @@ package ucanfx import ( - "bytes" - "context" "fmt" "time" - "github.com/fil-forge/libforge/commands/ucan/attest" - "github.com/fil-forge/libforge/didresolver" - "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal/verifier" - "github.com/fil-forge/ucantone/ucan" - ucantoken "github.com/fil-forge/ucantone/ucan/token" - "github.com/fil-forge/ucantone/validator" "go.uber.org/fx" + "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/did/web" "github.com/fil-forge/ucantone/server" + "github.com/fil-forge/ucantone/validator" "github.com/fil-forge/piri/pkg/config/app" echofx "github.com/fil-forge/piri/pkg/fx/echo" @@ -43,41 +39,26 @@ var Module = fx.Module("ucan", fx.ResultTags(`group:"route_registrar"`), ), - func(cfg app.UCANServiceConfig) (validator.VerifierResolverMap, error) { + func(cfg app.UCANServiceConfig) (did.Resolver, error) { var ( - httpResolver *didresolver.HTTPResolver + httpResolver did.Resolver err error ) if cfg.InsecureDIDResolution { - httpResolver, err = didresolver.NewHTTPResolver(didresolver.InsecureResolution()) + httpResolver, err = web.NewResolver(web.WithInsecure(true)) } else { - httpResolver, err = didresolver.NewHTTPResolver() + httpResolver, err = web.NewResolver() } if err != nil { return nil, fmt.Errorf("could not create http resolver: %w", err) } - cachedRes, err := didresolver.NewCachedResolver(httpResolver.Resolve, 24*time.Hour) - if err != nil { - return nil, fmt.Errorf("could not create cached resolver: %w", err) - } - - // did:key is self-describing — resolve it locally rather than - // over HTTP, which only makes sense for did:web. - resolveDIDKey := func(ctx context.Context, did did.DID) (ucan.Verifier, error) { - return verifier.FromDIDKey(did) - } - return validator.VerifierResolverMap{ - "key": resolveDIDKey, - "web": cachedRes.Resolve, + return resolver.ByMethod{ + "key": key.Resolver, + "web": resolver.NewCached(httpResolver, 24*time.Hour), }, nil }, - // Trust attestations issued by the Forge upload service - func(cfg app.UCANServiceConfig, resolvers validator.VerifierResolverMap) validator.NonStandardSignatureVerifierFunc { - return newAttestationVerifier(cfg.Services.Upload.DID, resolvers) - }, - // Server-wide options. Both transports need the DID verifier // resolvers so they can validate UCANs signed by did:web identities // (e.g. did:web:indexer, did:web:upload). Without the retrieval @@ -89,16 +70,14 @@ var Module = fx.Module("ucan", // hidden in the X-UCAN-Container header — which downstream // clients (the indexer's blobindexlookup) mis-read as // success-with-empty-body and then choke on CAR decode EOF. - ucanhandlers.ProvideRPCOption(func(resolver validator.VerifierResolverMap, verifyNonStandardSig validator.NonStandardSignatureVerifierFunc) server.HTTPOption { + ucanhandlers.ProvideRPCOption(func(resolver did.Resolver) server.HTTPOption { return server.WithValidationOptions( - validator.WithDIDVerifierResolvers(resolver), - validator.WithNonStandardSignatureVerifier(verifyNonStandardSig), + validator.WithDIDResolver(resolver), ) }), - ucanhandlers.ProvideRetrievalOption(func(resolver validator.VerifierResolverMap, verifyNonStandardSig validator.NonStandardSignatureVerifierFunc) server.HTTPOption { + ucanhandlers.ProvideRetrievalOption(func(resolver did.Resolver) server.HTTPOption { return server.WithValidationOptions( - validator.WithDIDVerifierResolvers(resolver), - validator.WithNonStandardSignatureVerifier(verifyNonStandardSig), + validator.WithDIDResolver(resolver), ) }), ), @@ -109,48 +88,3 @@ var Module = fx.Module("ucan", content.Module, pdp.Module, ) - -// newAttestationVerifier creates a [validator.NonStandardSignatureVerifierFunc] -// that validates that a delegation is attested by the given authority. -func newAttestationVerifier(authority did.DID, resolvers validator.VerifierResolverMap) validator.NonStandardSignatureVerifierFunc { - return func(ctx context.Context, token ucan.Token, meta ucan.Container) error { - resolver, ok := resolvers[authority.Method()] - if !ok { - return fmt.Errorf("no resolver for DID method: %s", authority.Method()) - } - verifier, err := resolver(ctx, authority) - if err != nil { - return fmt.Errorf("could not resolve DID: %w", err) - } - // 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 authority issued - if inv.Issuer() != authority || inv.Subject() == did.Undef || inv.Subject() != authority { - 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 := ucantoken.VerifySignature(inv, verifier) - if !ok || err != nil { - continue - } - return nil - } - return fmt.Errorf("no valid attestation found for delegation") - } -} diff --git a/pkg/ucanhandlers/ucanfxtest/base/suite.go b/pkg/ucanhandlers/ucanfxtest/base/suite.go index 6d17d061..65717250 100644 --- a/pkg/ucanhandlers/ucanfxtest/base/suite.go +++ b/pkg/ucanhandlers/ucanfxtest/base/suite.go @@ -19,7 +19,7 @@ import ( "net/url" "time" - "github.com/fil-forge/ucantone/principal" + "github.com/fil-forge/ucantone/multikey" "github.com/fil-forge/ucantone/testutil" "github.com/labstack/echo/v4" "github.com/stretchr/testify/require" @@ -41,7 +41,7 @@ type BaseSuite struct { App *fxtest.App Echo *echo.Echo ServiceURL *url.URL - ServiceID principal.Signer + ServiceID multikey.Issuer // ExtraOptions are appended to the fx options before the app is // constructed. Subclasses populate this in their own SetupSuite @@ -59,11 +59,11 @@ type BaseSuite struct { func (s *BaseSuite) SetupSuite() { if s.ServiceID == nil { - s.ServiceID = testutil.RandomSigner(s.T()) + s.ServiceID = testutil.RandomMultikeyIssuer(s.T()) } cfgOpts := append( - []piritestutil.TestConfigOption{piritestutil.WithSigner(s.ServiceID)}, + []piritestutil.TestConfigOption{piritestutil.WithIssuer(s.ServiceID)}, s.ConfigOptions..., ) cfg := piritestutil.NewTestConfig(s.T(), cfgOpts...) diff --git a/pkg/ucanhandlers/ucanfxtest/retrieval/content_test.go b/pkg/ucanhandlers/ucanfxtest/retrieval/content_test.go index 93c4b264..f3e302f4 100644 --- a/pkg/ucanhandlers/ucanfxtest/retrieval/content_test.go +++ b/pkg/ucanhandlers/ucanfxtest/retrieval/content_test.go @@ -32,7 +32,7 @@ import ( func (s *RetrievalSuite) TestContentRetrieve_Basic() { t := s.T() - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) data := testutil.RandomBytes(t, 256) digest, err := mh.Sum(data, mh.SHA2_256, -1) require.NoError(t, err) @@ -86,7 +86,7 @@ func (s *RetrievalSuite) TestContentRetrieve_Basic() { func (s *RetrievalSuite) TestContentRetrieve_NotAllocated() { t := s.T() - space := testutil.RandomSigner(t) + space := testutil.RandomIssuer(t) digest := testutil.RandomMultihash(t) // intentionally no allocation in s.Allocations and no bytes in s.Pieces diff --git a/pkg/ucanhandlers/ucanfxtest/retrieval/suite_test.go b/pkg/ucanhandlers/ucanfxtest/retrieval/suite_test.go index 6f360352..14dbfadb 100644 --- a/pkg/ucanhandlers/ucanfxtest/retrieval/suite_test.go +++ b/pkg/ucanhandlers/ucanfxtest/retrieval/suite_test.go @@ -1,17 +1,14 @@ package retrieval_test import ( - "context" "net/url" "testing" - "github.com/fil-forge/libforge/didresolver" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/libforge/testutil" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" - "github.com/fil-forge/ucantone/principal/verifier" - "github.com/fil-forge/ucantone/ucan" - "github.com/fil-forge/ucantone/validator" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" "github.com/stretchr/testify/suite" "go.uber.org/fx" @@ -34,7 +31,7 @@ type RetrievalSuite struct { Allocations allocationstore.AllocationStore Pieces *pdpfake.Pieces - UploadServiceIdentity principal.Signer + UploadServiceIdentity identity.Identity UploadServiceURL *url.URL } @@ -44,37 +41,27 @@ func TestRetrievalSuite(t *testing.T) { func (s *RetrievalSuite) SetupSuite() { s.ServiceID = testutil.Alice - s.UploadServiceIdentity = testutil.WebService + s.UploadServiceIdentity = identity.Identity{Issuer: testutil.WebService} s.UploadServiceURL = testutil.TestURL s.ConfigOptions = []piritestutil.TestConfigOption{ piritestutil.WithUploadServiceConfig(s.UploadServiceIdentity.DID(), s.UploadServiceURL), } - // Map resolver handles did:web → did:key indirection for the upload - // service identity (testutil.WebService wraps testutil.Service). - webResolver, err := didresolver.NewMapResolver(map[string]string{ - s.UploadServiceIdentity.DID().String(): testutil.Service.DID().String(), - }) + // We support resolving exactly one "did:web": the upload service + uploadServiceDoc, err := identity.Identity{Issuer: s.UploadServiceIdentity}.DIDDocument() s.Require().NoError(err) s.ExtraOptions = []fx.Option{ - // did:key resolves in-process (the DID itself encodes the public - // key); did:web goes through the static map for WebService. - fx.Decorate(func(validator.VerifierResolverMap) validator.VerifierResolverMap { - return validator.VerifierResolverMap{ - "key": resolveDIDKey, - "web": webResolver.Resolve, + fx.Decorate(func(did.Resolver) did.Resolver { + return resolver.ByMethod{ + "key": key.Resolver, + "web": resolver.WellKnown{ + s.UploadServiceIdentity.DID(): uploadServiceDoc, + }, } }), fx.Populate(&s.Allocations, &s.Pieces), } s.BaseSuite.SetupSuite() } - -// resolveDIDKey decodes a did:key DID into a Verifier in process. The DID -// itself encodes the public key bytes, so no network or static map is -// needed — works for any test signer the suite mints. -func resolveDIDKey(_ context.Context, d did.DID) (ucan.Verifier, error) { - return verifier.FromDIDKey(d) -} diff --git a/pkg/ucanhandlers/ucanfxtest/rpc/helpers_test.go b/pkg/ucanhandlers/ucanfxtest/rpc/helpers_test.go index 30b19f61..be9e1bc5 100644 --- a/pkg/ucanhandlers/ucanfxtest/rpc/helpers_test.go +++ b/pkg/ucanhandlers/ucanfxtest/rpc/helpers_test.go @@ -78,7 +78,7 @@ func assertReceiptFailure(t *testing.T, rcpt ucan.Receipt, expectedName string) // need to attach a proof chain for the cause invocation. func (s *RPCSuite) sendGrant( t *testing.T, - grantee ucan.Signer, + grantee ucan.Issuer, ability ucan.Command, cause ucan.Invocation, ) ucan.Receipt { @@ -107,7 +107,7 @@ func (s *RPCSuite) sendGrant( // exercise the no-cause failure path. func (s *RPCSuite) sendGrantWithProofs( t *testing.T, - grantee ucan.Signer, + grantee ucan.Issuer, ability ucan.Command, cause ucan.Invocation, extraProofs ...ucan.Delegation, diff --git a/pkg/ucanhandlers/ucanfxtest/rpc/suite_test.go b/pkg/ucanhandlers/ucanfxtest/rpc/suite_test.go index d69db65a..f3cd6cc5 100644 --- a/pkg/ucanhandlers/ucanfxtest/rpc/suite_test.go +++ b/pkg/ucanhandlers/ucanfxtest/rpc/suite_test.go @@ -1,17 +1,14 @@ package rpc_test import ( - "context" "net/url" "testing" - "github.com/fil-forge/libforge/didresolver" + "github.com/fil-forge/libforge/identity" "github.com/fil-forge/libforge/testutil" "github.com/fil-forge/ucantone/did" - "github.com/fil-forge/ucantone/principal" - "github.com/fil-forge/ucantone/principal/verifier" - "github.com/fil-forge/ucantone/ucan" - "github.com/fil-forge/ucantone/validator" + "github.com/fil-forge/ucantone/did/key" + "github.com/fil-forge/ucantone/did/resolver" "github.com/stretchr/testify/suite" "go.uber.org/fx" @@ -34,7 +31,7 @@ import ( type RPCSuite struct { base.BaseSuite - UploadServiceIdentity principal.Signer + UploadServiceIdentity identity.Identity UploadServiceURL *url.URL // Stores + side-effect surfaces tests inspect. @@ -47,28 +44,28 @@ type RPCSuite struct { func (s *RPCSuite) SetupSuite() { s.ServiceID = testutil.Alice - s.UploadServiceIdentity = testutil.WebService + s.UploadServiceIdentity = identity.Identity{Issuer: testutil.WebService} s.UploadServiceURL = testutil.TestURL s.ConfigOptions = []piritestutil.TestConfigOption{ piritestutil.WithUploadServiceConfig(s.UploadServiceIdentity.DID(), s.UploadServiceURL), } - // Map resolver handles did:web → did:key indirection for the upload - // service identity (testutil.WebService wraps testutil.Service). - webResolver, err := didresolver.NewMapResolver(map[string]string{ - s.UploadServiceIdentity.DID().String(): testutil.Service.DID().String(), - }) + // We support resolving exactly one "did:web": the upload service + uploadServiceDoc, err := identity.Identity{Issuer: s.UploadServiceIdentity}.DIDDocument() s.Require().NoError(err) + s.ExtraOptions = []fx.Option{ // Swap the production HTTP/cached resolver for local resolution. // did:key DIDs encode their public key directly so we decode in // process — no network, works for any test signer (Alice, Bob, // Mallory, etc.). did:web still needs the map for WebService. - fx.Decorate(func(validator.VerifierResolverMap) validator.VerifierResolverMap { - return validator.VerifierResolverMap{ - "key": resolveDIDKey, - "web": wrapWebResolver(webResolver), + fx.Decorate(func(did.Resolver) did.Resolver { + return resolver.ByMethod{ + "key": key.Resolver, + "web": resolver.WellKnown{ + s.UploadServiceIdentity.DID(): uploadServiceDoc, + }, } }), fx.Populate( @@ -85,47 +82,3 @@ func (s *RPCSuite) SetupSuite() { func TestRPCSuite(t *testing.T) { suite.Run(t, new(RPCSuite)) } - -// resolveDIDKey decodes a did:key DID into a Verifier in process. The DID -// itself encodes the public key bytes, so no network or static map is -// needed — works for any test signer the suite mints. -func resolveDIDKey(_ context.Context, d did.DID) (ucan.Verifier, error) { - return verifier.FromDIDKey(d) -} - -// wrapWebResolver wraps a did:web resolver so the returned verifier's -// DID() matches the input did:web (not the underlying did:key). -// -// TODO(file an issue): libforge's didresolver.NewMapResolver stores the -// unwrapped did:key verifier in its map, so MapResolver.Resolve returns -// a verifier whose DID() is the did:key, not the did:web that was -// looked up. ucantone's token.VerifySignature (token/token.go:12) then -// rejects with an issuer/verifier DID mismatch BEFORE the signature is -// even checked, producing a confusing "InvalidSignature" failure that -// reads like a signing key problem. Until libforge wraps in -// NewMapResolver (or until something else exposes a did:web-preserving -// helper), the suite wraps in test code so tok.Issuer() (did:web) == -// verifier.DID() (did:web) and the signature check actually runs. -// -// Repro details: -// - libforge/didresolver/mapresolver.go:36 → verifier.Parse(v) drops the requested DID -// - ucantone/ucan/token/token.go:12 → tok.Issuer() != verifier.DID() rejects without verifying -func wrapWebResolver(r *didresolver.MapResolver) validator.DIDVerifierResolverFunc { - return func(ctx context.Context, d did.DID) (ucan.Verifier, error) { - plain, err := r.Resolve(ctx, d) - if err != nil { - return nil, err - } - return &didWrappedVerifier{did: d, inner: plain}, nil - } -} - -// didWrappedVerifier overrides the wrapped verifier's DID() with the -// resolver's input DID, preserving the underlying signature check. -type didWrappedVerifier struct { - did did.DID - inner ucan.Verifier -} - -func (w *didWrappedVerifier) DID() did.DID { return w.did } -func (w *didWrappedVerifier) Verify(msg, sig []byte) bool { return w.inner.Verify(msg, sig) }