From 84bd68d6211d6fdd3986d3553dc94230fc4a5fad Mon Sep 17 00:00:00 2001 From: Marc Juchli Date: Fri, 22 May 2026 10:57:14 +0200 Subject: [PATCH 1/6] feat: hide secret details from listNetwork The absence of the clientSecret also implies that the self-signed login can no longer be done on the frontend. Instead, the backend now must mint a self-signed token. Signed-off-by: Marc Juchli --- api-specs/openrpc-user-api.json | 107 +++++++++++++++++- .../src/components/login-form.ts | 17 ++- .../src/components/network-card.ts | 10 +- .../src/components/network-table.ts | 4 +- .../src/components/networks.ts | 11 +- core/wallet-user-rpc-client/src/index.ts | 32 +++++- core/wallet-user-rpc-client/src/openrpc.json | 107 +++++++++++++++++- .../wallet-gateway/apis/index.md | 3 +- .../remote/src/user-api/controller.ts | 77 ++++++++++++- .../remote/src/user-api/rpc-gen/index.ts | 3 + .../remote/src/user-api/rpc-gen/typings.ts | 27 ++++- .../remote/src/user-api/server.test.ts | 9 +- .../remote/src/web/frontend/login/login.ts | 29 +++-- .../remote/src/web/frontend/networks/index.ts | 7 +- .../src/web/frontend/networks/review/index.ts | 22 ++-- .../remote/src/web/frontend/settings/index.ts | 4 +- 16 files changed, 403 insertions(+), 66 deletions(-) diff --git a/api-specs/openrpc-user-api.json b/api-specs/openrpc-user-api.json index 130c84f91..843ba3bc0 100644 --- a/api-specs/openrpc-user-api.json +++ b/api-specs/openrpc-user-api.json @@ -74,13 +74,50 @@ "title": "networks", "type": "array", "items": { - "$ref": "#/components/schemas/Network" + "$ref": "#/components/schemas/PublicNetwork" } } }, "required": ["networks"] } - } + }, + "description": "Lists configured networks without sensitive authentication details." + }, + { + "name": "getNetwork", + "params": [ + { + "name": "params", + "schema": { + "title": "GetNetworkParams", + "type": "object", + "additionalProperties": false, + "properties": { + "networkId": { + "title": "networkId", + "type": "string", + "description": "Network ID" + } + }, + "required": ["networkId"] + } + } + ], + "result": { + "name": "result", + "schema": { + "title": "GetNetworkResult", + "type": "object", + "additionalProperties": false, + "properties": { + "network": { + "$ref": "#/components/schemas/Network" + } + }, + "required": ["network"] + } + }, + "description": "Returns full network configuration including auth details. Admin only." }, { "name": "addIdp", @@ -877,6 +914,72 @@ "format": "uuid", "description": "The internal transaction identifier." }, + "PublicNetwork": { + "title": "PublicNetwork", + "type": "object", + "additionalProperties": false, + "description": "Network metadata exposed by listNetworks without sensitive auth configuration", + "properties": { + "id": { + "title": "networkId", + "type": "string", + "description": "Network ID" + }, + "name": { + "title": "name", + "type": "string", + "description": "Name of network" + }, + "description": { + "title": "description", + "type": "string", + "description": "Description of network" + }, + "synchronizerId": { + "title": "synchronizerId", + "type": "string", + "description": "Synchronizer ID" + }, + "identityProviderId": { + "title": "identityProviderId", + "type": "string", + "description": "Identity Provider ID" + }, + "ledgerApi": { + "title": "ledgerApi", + "type": "string", + "description": "Ledger api url" + }, + "authMethod": { + "title": "authMethod", + "type": "string", + "description": "Authentication method configured for this network" + }, + "clientId": { + "title": "clientId", + "type": "string", + "description": "OAuth or self-signed client ID used for user login" + }, + "scope": { + "title": "scope", + "type": "string", + "description": "OAuth scope used for user login" + }, + "audience": { + "title": "audience", + "type": "string", + "description": "OAuth audience used for user login" + } + }, + "required": [ + "id", + "name", + "description", + "identityProviderId", + "ledgerApi", + "authMethod" + ] + }, "Network": { "title": "Network", "type": "object", diff --git a/core/wallet-ui-components/src/components/login-form.ts b/core/wallet-ui-components/src/components/login-form.ts index 0495a170d..d0278d5ab 100644 --- a/core/wallet-ui-components/src/components/login-form.ts +++ b/core/wallet-ui-components/src/components/login-form.ts @@ -5,14 +5,14 @@ import { css, html, PropertyValues } from 'lit' import { customElement, property, state } from 'lit/decorators.js' import './back-link.js' import { BaseElement } from '../internal/base-element.js' -import { Network, Idp } from '@canton-network/core-wallet-user-rpc-client' +import { PublicNetwork, Idp } from '@canton-network/core-wallet-user-rpc-client' import { chevronDownIcon } from '../icons' import cantonLogo from '../../images/logos/canton-logo.png' /** Emitted when the user clicks the Connect button */ export class LoginConnectEvent extends Event { constructor( - public selectedNetwork: Network, + public selectedNetwork: PublicNetwork, public selectedIdp: Idp, public clientId: string ) { @@ -34,7 +34,7 @@ export class LoginBackEvent extends Event { @customElement('wg-login-form') export class WgLoginForm extends BaseElement { /** Available networks to show in the dropdown */ - @property({ type: Array }) networks: Network[] = [] + @property({ type: Array }) networks: PublicNetwork[] = [] /** Available identity providers */ @property({ type: Array }) idps: Idp[] = [] @@ -42,7 +42,7 @@ export class WgLoginForm extends BaseElement { @property({ type: Boolean }) connecting = false @property({ type: String }) backHref = '/' - @state() accessor selectedNetwork: Network | null = null + @state() accessor selectedNetwork: PublicNetwork | null = null @state() accessor selectedIdp: Idp | null = null @state() accessor message: string | null = null @state() accessor messageType: 'error' | 'info' | null = null @@ -141,7 +141,7 @@ export class WgLoginForm extends BaseElement { if (changedProperties.has('networks') && !this.selectedNetwork) { const index = this.networks.findIndex( - (network) => network.auth.method !== 'client_credentials' + (network) => network.authMethod !== 'client_credentials' ) if (index >= 0) { @@ -211,7 +211,7 @@ export class WgLoginForm extends BaseElement { this.renderRoot.querySelector( '#client-id' ) as HTMLInputElement | null - )?.value || this.selectedNetwork.auth.clientId + )?.value || this.selectedNetwork.clientId this.dispatchEvent( new LoginConnectEvent(this.selectedNetwork, idp, clientId) @@ -262,7 +262,7 @@ export class WgLoginForm extends BaseElement { (net, index) => html`