Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions wallet-gateway/remote/src/config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,24 @@ export const kernelInfoSchema = z.object({
z.literal('mobile'),
z.literal('remote'),
]),
url: z.string().url(),
userUrl: z.string().url(),
})

export const serverConfigSchema = z.object({
host: z.string(),
port: z.number(),
tls: z.boolean(),
dappPath: z.string().default('/api/v0/dapp'),
userPath: z.string().default('/api/v0/user'),
allowedOrigins: z.union([z.literal('*'), z.array(z.string())]).default('*'),
})

export const configSchema = z.object({
kernel: kernelInfoSchema,
server: serverConfigSchema,
store: storeConfigSchema,
signingStore: signingStoreConfigSchema,
})

export type KernelInfo = z.infer<typeof kernelInfoSchema>
export type ServerConfig = z.infer<typeof serverConfigSchema>
export type Config = z.infer<typeof configSchema>
13 changes: 12 additions & 1 deletion wallet-gateway/remote/src/config/ConfigUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { readFileSync, existsSync } from 'fs'
import { Config, configSchema } from './Config.js'
import { Config, configSchema, ServerConfig } from './Config.js'

export class ConfigUtils {
static loadConfigFile(filePath: string): Config {
Expand Down Expand Up @@ -104,3 +104,14 @@ function validateNetworkAuthMethods(
}
}
}

export const deriveKernelUrls = (
serverConfig: ServerConfig
): { dappUrl: string; userUrl: string } => {
const protocol = serverConfig.tls ? 'https' : 'http'
const dappUrl = `${protocol}://${serverConfig.host}:${serverConfig.port}${serverConfig.dappPath}`
// userUrl is the base URL for the web frontend (no path)
const userUrl = `${protocol}://${serverConfig.host}:${serverConfig.port}`

return { dappUrl, userUrl }
}
11 changes: 6 additions & 5 deletions wallet-gateway/remote/src/dapp-api/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { networkStatus } from '../utils.js'

export const dappController = (
kernelInfo: KernelInfoConfig,
dappUrl: string,
userUrl: string,
store: Store,
notificationService: NotificationService,
_logger: Logger,
Expand All @@ -41,7 +43,7 @@ export const dappController = (
isConnected: false,
isNetworkConnected: false,
networkReason: 'Unauthenticated',
userUrl: 'http://localhost:3030/login/', // TODO: pull user URL from config
userUrl: `${userUrl}/login/`,
},
}
}
Expand All @@ -61,7 +63,7 @@ export const dappController = (
isConnected: true,
isNetworkConnected: status.isConnected,
networkReason: status.reason ? status.reason : 'OK',
userUrl: 'http://localhost:3030/login/', // TODO: pull user URL from config
userUrl: `${userUrl}/login/`,
},
}
},
Expand All @@ -76,7 +78,7 @@ export const dappController = (
isConnected: false,
isNetworkConnected: false,
networkReason: 'Unauthenticated',
userUrl: 'http://localhost:3030/login/', // TODO: pull user URL from config
userUrl: `${userUrl}/login/`,
} as StatusEvent)
}

Expand Down Expand Up @@ -164,8 +166,7 @@ export const dappController = (
})

return {
// TODO: pull user base URL / port from config
userUrl: `http://localhost:3030/approve/index.html?commandId=${commandId}`,
userUrl: `${userUrl}/approve/index.html?commandId=${commandId}`,
}
},
prepareReturn: async (params: PrepareReturnParams) => {
Expand Down
8 changes: 5 additions & 3 deletions wallet-gateway/remote/src/dapp-api/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import express from 'express'
import { dapp } from './server.js'
import { StoreInternal } from '@canton-network/core-wallet-store-inmemory'
import { AuthService } from '@canton-network/core-wallet-auth'
import { ConfigUtils } from '../config/ConfigUtils.js'
import { ConfigUtils, deriveKernelUrls } from '../config/ConfigUtils.js'
import { Notifier } from '../notification/NotificationService.js'
import { pino } from 'pino'
import { sink } from 'pino-test'
Expand Down Expand Up @@ -41,13 +41,17 @@ test('call connect rpc', async () => {
app.use(cors())
app.use(express.json())
const server = createServer(app)
const { dappUrl, userUrl } = deriveKernelUrls(config.server)
const response = await request(
dapp(
'/api/v0/dapp',
app,
pino(sink()),
server,
config.kernel,
dappUrl,
userUrl,
config.server,
notificationService,
authService,
store
Expand All @@ -67,8 +71,6 @@ test('call connect rpc', async () => {
kernel: {
id: 'remote-da',
clientType: 'remote',
url: 'http://localhost:3030/api/v0/dapp',
userUrl: 'http://localhost:3030',
},
isConnected: false,
isNetworkConnected: false,
Expand Down
15 changes: 12 additions & 3 deletions wallet-gateway/remote/src/dapp-api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,32 @@ import {
NotificationService,
Notifier,
} from '../notification/NotificationService.js'
import { KernelInfo } from '../config/Config.js'
import { KernelInfo, ServerConfig } from '../config/Config.js'

export const dapp = (
route: string,
app: express.Express,
logger: Logger,
server: Server,
kernelInfo: KernelInfo,
dappUrl: string,
userUrl: string,
serverConfig: ServerConfig,
notificationService: NotificationService,
authService: AuthService,
store: Store & AuthAware<Store>
) => {
app.use(cors()) // TODO: read allowedOrigins from config
app.use(
cors({
origin: serverConfig.allowedOrigins,
})
)
app.use(route, (req, res, next) =>
jsonRpcHandler<Methods>({
controller: dappController(
kernelInfo,
dappUrl,
userUrl,
store.withAuthContext(req.authContext),
notificationService,
logger,
Expand All @@ -43,7 +52,7 @@ export const dapp = (

const io = new SocketIoServer(server, {
cors: {
origin: '*', // TODO: read allowedOrigins from config
origin: serverConfig.allowedOrigins,
methods: ['GET', 'POST'],
},
})
Expand Down
10 changes: 8 additions & 2 deletions wallet-gateway/remote/src/example-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ export default {
kernel: {
id: 'remote-da',
clientType: 'remote',
url: 'http://localhost:3030/api/v0/dapp',
userUrl: 'http://localhost:3030',
},
server: {
host: 'localhost',
port: 3030,
tls: false,
dappPath: '/api/v0/dapp',
userPath: '/api/v0/user',
allowedOrigins: ['http://localhost:8080'],
},
signingStore: {
connection: {
Expand Down
37 changes: 27 additions & 10 deletions wallet-gateway/remote/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { CliOptions } from './index.js'
import { jwtAuth } from './middleware/jwtAuth.js'
import { rpcRateLimit } from './middleware/rateLimit.js'
import { Config } from './config/Config.js'
import { deriveKernelUrls } from './config/ConfigUtils.js'
import { existsSync, readFileSync } from 'fs'
import path from 'path'

Expand Down Expand Up @@ -133,12 +134,17 @@ async function initializeSigningDatabase(
}

export async function initialize(opts: CliOptions, logger: Logger) {
const port = opts.port ? Number(opts.port) : 3030
const config = ConfigUtils.loadConfigFile(opts.config)

// Use CLI port override or config port
const port = opts.port ? Number(opts.port) : config.server.port
const host = config.server.host
const protocol = config.server.tls ? 'https' : 'http'

const app = express()
const server = app.listen(port, () => {
const server = app.listen(port, host, () => {
logger.info(
`Remote Wallet Gateway starting on http://localhost:${port}`
`Remote Wallet Gateway starting on ${protocol}://${host}:${port}`
)
})

Expand All @@ -153,8 +159,6 @@ export async function initialize(opts: CliOptions, logger: Logger) {

const notificationService = new NotificationService(logger)

const config = ConfigUtils.loadConfigFile(opts.config)

const store = await initializeDatabase(config, logger)
const signingStore = await initializeSigningDatabase(config, logger)
const authService = jwtAuthService(store, logger)
Expand Down Expand Up @@ -192,31 +196,44 @@ export async function initialize(opts: CliOptions, logger: Logger) {
app.use('/api/*splat', rpcRateLimit)
app.use('/api/*splat', jwtAuth(authService, logger))

// Override config port with CLI parameter port if provided, then derive URLs
const serverConfigWithOverride = {
...config.server,
port, // Use the actual port we're listening on
}
const { dappUrl, userUrl } = deriveKernelUrls(serverConfigWithOverride)

const kernelInfo = config.kernel

// register dapp API handlers
dapp(
'/api/v0/dapp',
config.server.dappPath,
app,
logger,
server,
config.kernel,
kernelInfo,
dappUrl,
userUrl,
config.server,
notificationService,
authService,
store
)

// register user API handlers
user(
'/api/v0/user',
config.server.userPath,
app,
logger,
config.kernel,
kernelInfo,
userUrl,
notificationService,
drivers,
store
)

// register web handler
web(app, server)
web(app, server, config.server.userPath)
isReady = true

logger.info('Wallet Gateway initialization complete')
Expand Down
3 changes: 2 additions & 1 deletion wallet-gateway/remote/src/user-api/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type AvailableSigningDrivers = Partial<

export const userController = (
kernelInfo: KernelInfo,
userUrl: string,
store: Store,
notificationService: NotificationService,
authContext: AuthContext | undefined,
Expand Down Expand Up @@ -603,7 +604,7 @@ export const userController = (
isConnected: false,
isNetworkConnected: false,
networkReason: 'Unauthenticated',
userUrl: 'http://localhost:3030/login/', // TODO: pull user URL from config
userUrl: `${userUrl}/login/`,
} as StatusEvent)
return null
},
Expand Down
4 changes: 3 additions & 1 deletion wallet-gateway/remote/src/user-api/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import request from 'supertest'
import { user } from './server.js'
import { StoreInternal } from '@canton-network/core-wallet-store-inmemory'
import { Network } from '@canton-network/core-wallet-store'
import { ConfigUtils } from '../config/ConfigUtils.js'
import { ConfigUtils, deriveKernelUrls } from '../config/ConfigUtils.js'
import { Notifier } from '../notification/NotificationService.js'
import { pino } from 'pino'
import { sink } from 'pino-test'
Expand All @@ -33,12 +33,14 @@ test('call listNetworks rpc', async () => {
app.use(cors())
app.use(express.json())

const { userUrl } = deriveKernelUrls(config.server)
const response = await request(
user(
'/api/v0/user',
app,
pino(sink()),
config.kernel,
userUrl,
notificationService,
drivers,
store
Expand Down
2 changes: 2 additions & 0 deletions wallet-gateway/remote/src/user-api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const user = (
app: express.Express,
logger: Logger,
kernelInfo: KernelInfo,
userUrl: string,
notificationService: NotificationService,
drivers: Partial<Record<SigningProvider, SigningDriverInterface>>,
store: Store & AuthAware<Store>
Expand All @@ -28,6 +29,7 @@ export const user = (
jsonRpcHandler<Methods>({
controller: userController(
kernelInfo,
userUrl,
store.withAuthContext(req.authContext),
notificationService,
req.authContext,
Expand Down
8 changes: 6 additions & 2 deletions wallet-gateway/remote/src/web/frontend/approve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ export class ApproveUi extends LitElement {
}

private async updateState() {
const userClient = createUserClient(stateManager.accessToken.get())
const userClient = await createUserClient(
stateManager.accessToken.get()
)
userClient
.request('getTransaction', { commandId: this.commandId })
.then((result) => {
Expand Down Expand Up @@ -201,7 +203,9 @@ export class ApproveUi extends LitElement {
preparedTransaction: this.tx,
}

const userClient = createUserClient(stateManager.accessToken.get())
const userClient = await createUserClient(
stateManager.accessToken.get()
)
const { signature, signedBy } = await userClient.request(
'sign',
signRequest
Expand Down
6 changes: 4 additions & 2 deletions wallet-gateway/remote/src/web/frontend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export class UserApp extends LitElement {
private async handleLogout() {
localStorage.clear()

const userClient = createUserClient(stateManager.accessToken.get())
const userClient = await createUserClient(
stateManager.accessToken.get()
)
await userClient.request('removeSession')

if (
Expand Down Expand Up @@ -106,7 +108,7 @@ export const authenticate = async (
accessToken: string,
networkId: string
): Promise<void> => {
const authenticatedUserClient = createUserClient(accessToken)
const authenticatedUserClient = await createUserClient(accessToken)
await authenticatedUserClient.request('addSession', {
networkId,
})
Expand Down
Loading
Loading