From 71cbeb718d0a5132b97efa1173a5aaf9c75cbe80 Mon Sep 17 00:00:00 2001 From: Benjamin Goering <171782+gobengo@users.noreply.github.com> Date: Mon, 30 Jan 2023 14:33:48 -0800 Subject: [PATCH] feat: update access-api ucanto proxy to not need a signer (#390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and not sign proxyInvocation. using features coming in ucanto 4.2.0 Motivation: * https://github.com/web3-storage/w3protocol/issues/325 * simplify access-api ucanto proxy using features added to ucanto in https://github.com/web3-storage/ucanto/pull/199 * previously, the technique used to proxy the invocation was to issue a new invocation (i.e. `proxyInvocation`) in the proxy server, and then send that to the upstream. This had at least two limitations: 1. required the proxy server to be configured with a `options.signer` to sign the `proxyInvocation` 2. for functional use in access-api and proxying upload-api, this proxy `options.signer` also had to be configured pretty much identically to the ucanto verifier with same did on the upstream, including requiring both to have the same private key * now * you don't need an `options.signer` at all! so you definitely don't need one creating signatures with the same private key as the upstream Steps * [x] release ucanto 4.2.0 https://github.com/web3-storage/ucanto/pull/200 * [x] update this source branch package.json + pnpm locks to upgrade ucanto to 4.2.0 * [x] ensure `tsc` + tests pass here --- .../src/service/upload-api-proxy.js | 3 -- packages/access-api/src/ucanto/proxy.js | 28 ++++++------------- packages/access-api/test/ucanto-proxy.test.js | 2 -- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/packages/access-api/src/service/upload-api-proxy.js b/packages/access-api/src/service/upload-api-proxy.js index d23939587..606645bab 100644 --- a/packages/access-api/src/service/upload-api-proxy.js +++ b/packages/access-api/src/service/upload-api-proxy.js @@ -16,7 +16,6 @@ import { createProxyHandler } from '../ucanto/proxy.js' * @template {string|number|symbol} M * @template {Ucanto.ConnectionView} [Connection=Ucanto.ConnectionView] * @param {object} options - * @param {Ucanto.Signer} options.signer * @param {Array} options.methods * @param {{ default: Connection } & Record} options.connections */ @@ -97,7 +96,6 @@ function getDefaultConnections(options) { /** * @template {Ucanto.ConnectionView} [Connection=Ucanto.ConnectionView] * @param {object} options - * @param {Ucanto.Signer} options.signer * @param {typeof globalThis.fetch} [options.fetch] * @param {{ default: Connection, [K: Ucanto.UCAN.DID]: Connection }} [options.connections] * @param {Record} [options.audienceToUrl] @@ -116,7 +114,6 @@ export function createUploadProxy(options) { /** * @template {Ucanto.ConnectionView} [Connection=Ucanto.ConnectionView] * @param {object} options - * @param {Ucanto.Signer} options.signer * @param {typeof globalThis.fetch} [options.fetch] * @param {{ default: Connection, [K: Ucanto.UCAN.DID]: Connection }} [options.connections] * @param {Record} [options.audienceToUrl] diff --git a/packages/access-api/src/ucanto/proxy.js b/packages/access-api/src/ucanto/proxy.js index 543ffe0e7..0f9909621 100644 --- a/packages/access-api/src/ucanto/proxy.js +++ b/packages/access-api/src/ucanto/proxy.js @@ -47,35 +47,23 @@ function defaultCatchInvocationError(error) { * @param {object} options * @param {(error: unknown) => Promise} [options.catchInvocationError] - catches any error that comes from invoking the proxy invocation on the connection. If it returns a value, that value will be the proxied invocation result. * @param {{ default: Connection, [K: Ucanto.UCAN.DID]: Connection }} options.connections - * @param {Ucanto.Signer} options.signer */ export function createProxyHandler(options) { /** * @template {import('@ucanto/interface').Capability} Capability - * @param {Ucanto.Invocation} invocationIn + * @param {Ucanto.Invocation} invocation * @param {Ucanto.InvocationContext} context * @returns {Promise>} */ - return async function handleInvocation(invocationIn, context) { - const { - connections, - signer, - catchInvocationError = defaultCatchInvocationError, - } = options - const { audience, capabilities, expiration, notBefore } = invocationIn - const connection = connections[audience.did()] ?? connections.default - const proxyInvocation = Client.invoke({ - issuer: signer, - capability: capabilities[0], - audience, - proofs: [invocationIn], - expiration, - notBefore, - }) + return async function handleInvocation(invocation, context) { + const { connections, catchInvocationError = defaultCatchInvocationError } = + options + const connection = + connections[invocation.audience.did()] ?? connections.default try { const [result] = await Client.execute( - [proxyInvocation], - /** @type {Client.ConnectionView} */ (connection) + [await invocation.delegate()], + connection ) return result } catch (error) { diff --git a/packages/access-api/test/ucanto-proxy.test.js b/packages/access-api/test/ucanto-proxy.test.js index fb7ef3f6b..e6f873564 100644 --- a/packages/access-api/test/ucanto-proxy.test.js +++ b/packages/access-api/test/ucanto-proxy.test.js @@ -45,7 +45,6 @@ describe('ucanto-proxy', () => { service: { test: { succeed: createProxyHandler({ - signer: proxyPrincipal, connections: { default: Client.connect({ id: upstreamPrincipal, @@ -117,7 +116,6 @@ describe('ucanto-proxy', () => { service: { test: { succeed: createProxyHandler({ - signer: upstreamPrincipal, connections: { default: Client.connect({ id: upstreamPrincipal,