Skip to content
Open
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
10 changes: 5 additions & 5 deletions core/signing-blockdaemon/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface
public partyMode = PartyMode.EXTERNAL
public signingProvider = SigningProvider.BLOCKDAEMON

public controller = (userId: AuthContext['userId'] | undefined) =>
public controller = (authContext: AuthContext | undefined) =>
buildController({
signTransaction: async (
params: SignTransactionParams
Expand All @@ -67,7 +67,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface
...(params.internalTxId !== undefined && {
internalTxId: params.internalTxId,
}),
userIdentifier: userId,
userIdentifier: authContext?.email,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userId used to be the email as far as i can see.

please double-check @pawelstepien-da

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we definitely used value from email here. In BD signing driver controller the argument was called userId, it was typed as userId: AuthContext['userId'], but it was actually supposed to be email, so it was quite confusing and is so much clearer now.

})
return {
txId: tx.txId,
Expand Down Expand Up @@ -135,7 +135,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface
const transactions = await this.client.getTransactions({
txIds: params.txIds!,
publicKeys: params.publicKeys!,
userIdentifier: userId,
userIdentifier: authContext?.email,
})
return {
transactions: transactions.map((tx) => ({
Expand Down Expand Up @@ -175,7 +175,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface
id: k.id,
name: k.name,
publicKey: k.publicKey,
userIdentifier: userId,
userIdentifier: authContext?.email,
})),
}
} catch (error) {
Expand All @@ -192,7 +192,7 @@ export default class BlockdaemonSigningDriver implements SigningDriverInterface
try {
const key = await this.client.createKey({
name: params.name,
userIdentifier: userId,
userIdentifier: authContext?.email,
})
return {
id: key.id,
Expand Down
2 changes: 1 addition & 1 deletion core/signing-dfns/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default class DfnsSigningDriver implements SigningDriverInterface {

public controller = (
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_userId: AuthContext['userId'] | undefined
authContext: AuthContext | undefined
) =>
buildController({
signTransaction: async (
Expand Down
12 changes: 7 additions & 5 deletions core/signing-fireblocks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface {
}
public partyMode = PartyMode.EXTERNAL
public signingProvider = SigningProvider.FIREBLOCKS
public controller = (userId: AuthContext['userId'] | undefined) =>
public controller = (authContext: AuthContext | undefined) =>
buildController({
signTransaction: async (
params: SignTransactionParams
Expand All @@ -84,7 +84,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface {

try {
const tx = await this.fireblocks.signTransaction(
userId,
authContext?.userId,
params.txHash,
params.keyIdentifier,
params.internalTxId
Expand Down Expand Up @@ -117,7 +117,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface {
params: GetTransactionParams
): Promise<GetTransactionResult> => {
const tx = await this.fireblocks.getTransaction(
userId,
authContext?.userId,
params.txId
)
if (tx) {
Expand All @@ -144,7 +144,7 @@ export default class FireblocksSigningDriver implements SigningDriverInterface {
const txIds = new Set(params.txIds)
const publicKeys = new Set(params.publicKeys)
for await (const tx of this.fireblocks.getTransactions(
userId
authContext?.userId
)) {
if (
txIds.has(tx.txId) ||
Expand Down Expand Up @@ -180,7 +180,9 @@ export default class FireblocksSigningDriver implements SigningDriverInterface {

getKeys: async (): Promise<GetKeysResult> => {
try {
const keys = await this.fireblocks.getPublicKeys(userId)
const keys = await this.fireblocks.getPublicKeys(
authContext?.userId
)
return {
keys: keys.map((k) => ({
id: k.derivationPath.join('-'),
Expand Down
28 changes: 15 additions & 13 deletions core/signing-internal/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
SignMessageResult,
} from '@canton-network/core-signing-lib'
import { randomUUID } from 'node:crypto'
import { AuthContext } from '@canton-network/core-wallet-auth'
import { AuthAware, AuthContext } from '@canton-network/core-wallet-auth'

interface InternalKey {
id: string
Expand All @@ -62,17 +62,18 @@ const convertInternalTransaction = (tx: InternalTransaction): Transaction => {
}

export class InternalSigningDriver implements SigningDriverInterface {
private store: SigningDriverStore

private store: SigningDriverStore & AuthAware<SigningDriverStore>
public partyMode = PartyMode.EXTERNAL
public signingProvider = SigningProvider.WALLET_KERNEL

constructor(store: SigningDriverStore) {
constructor(store: SigningDriverStore & AuthAware<SigningDriverStore>) {
this.store = store
}

public controller = (_userId: AuthContext['userId'] | undefined) =>
buildController({
public controller = (authContext: AuthContext | undefined) => {
const scopedStore = this.store.withAuthContext(authContext)
const _userId = authContext?.userId
return buildController({
signTransaction: async (
params: SignTransactionParams
): Promise<SignTransactionResult> => {
Expand All @@ -86,7 +87,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
})
}

const key = await this.store.getSigningKeyByPublicKey(
const key = await scopedStore.getSigningKeyByPublicKey(
params.keyIdentifier.publicKey
)

Expand All @@ -109,7 +110,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
signedAt: now,
}

this.store.setSigningTransaction(
scopedStore.setSigningTransaction(
_userId,
internalTransaction
)
Expand Down Expand Up @@ -146,7 +147,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
})
}

const key = await this.store.getSigningKeyByPublicKey(
const key = await scopedStore.getSigningKeyByPublicKey(
params.keyIdentifier.publicKey
)
if (!key?.privateKey) {
Expand All @@ -172,7 +173,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
})
}

const storedTx = await this.store.getSigningTransaction(
const storedTx = await scopedStore.getSigningTransaction(
_userId,
params.txId
)
Expand Down Expand Up @@ -204,7 +205,7 @@ export class InternalSigningDriver implements SigningDriverInterface {

if (params.publicKeys || params.txIds) {
const transactions =
await this.store.listSigningTransactionsByTxIdsAndPublicKeys(
await scopedStore.listSigningTransactionsByTxIdsAndPublicKeys(
params.txIds || [],
params.publicKeys || []
)
Expand Down Expand Up @@ -237,7 +238,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
})
}

const keys = await this.store.listSigningKeys(_userId)
const keys = await scopedStore.listSigningKeys(_userId)
if (keys.length > 0) {
return Promise.resolve({
keys: Array.from(keys).map((key) => ({
Expand Down Expand Up @@ -276,7 +277,7 @@ export class InternalSigningDriver implements SigningDriverInterface {
updatedAt: now,
}

await this.store.setSigningKey(_userId, internalKey)
await scopedStore.setSigningKey(_userId, internalKey)

return {
id,
Expand All @@ -299,4 +300,5 @@ export class InternalSigningDriver implements SigningDriverInterface {
): Promise<SubscribeTransactionsResult> =>
Promise.resolve({} as SubscribeTransactionsResult),
})
}
}
2 changes: 1 addition & 1 deletion core/signing-lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface KeyPair {
export interface SigningDriverInterface {
partyMode: PartyMode
signingProvider: SigningProvider
controller: (userId: AuthContext['userId'] | undefined) => Methods
controller: (authContext: AuthContext | undefined) => Methods
}

export const verifySignedTxHash = (
Expand Down
2 changes: 1 addition & 1 deletion core/signing-participant/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class ParticipantSigningDriver implements SigningDriverInterface {
public signingProvider = SigningProvider.PARTICIPANT

public controller = (
_userId: AuthContext['userId'] | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
authContext: AuthContext | undefined // eslint-disable-line @typescript-eslint/no-unused-vars
) =>
buildController({
signTransaction: async (
Expand Down
107 changes: 107 additions & 0 deletions core/signing-store-sql/src/store-sql.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, test, beforeEach } from 'vitest'
import { AuthContext } from '@canton-network/core-wallet-auth'
import { Kysely } from 'kysely'
import { pino } from 'pino'
import { migrator } from './migrator.js'
import { DB } from './schema.js'
import { connection, StoreSql } from './store-sql.js'

const userA: AuthContext = {
userId: 'user-a',
accessToken: 'token-a',
}

const userB: AuthContext = {
userId: 'user-b',
accessToken: 'token-b',
}

describe('StoreSql auth scoping', () => {
let db: Kysely<DB>

beforeEach(async () => {
db = connection({ connection: { type: 'memory' } })
const umzug = migrator(db)
await umzug.up()
})

test('returns empty for getSigningKeyByPublicKey owned by another user', async () => {
const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' }))
await storeWithoutAuth.setSigningKey(userB.userId, {
id: 'key-b',
name: 'key-b',
publicKey: 'user-b-public-key',
privateKey: 'private-key-b',
createdAt: new Date(),
updatedAt: new Date(),
})

const scopedStore = storeWithoutAuth.withAuthContext(userA)
const key =
await scopedStore.getSigningKeyByPublicKey('user-b-public-key')

expect(key).toBeUndefined()
})

test('scopes getSigningKeyByPublicKey to authContext user', async () => {
const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' }))
await storeWithoutAuth.setSigningKey(userA.userId, {
id: 'key-a',
name: 'key-a',
publicKey: 'shared-public-key',
privateKey: 'private-key-a',
createdAt: new Date(),
updatedAt: new Date(),
})
await storeWithoutAuth.setSigningKey(userB.userId, {
id: 'key-b',
name: 'key-b',
publicKey: 'shared-public-key',
privateKey: 'private-key-b',
createdAt: new Date(),
updatedAt: new Date(),
})

const scopedStore = storeWithoutAuth.withAuthContext(userA)
const key =
await scopedStore.getSigningKeyByPublicKey('shared-public-key')

expect(key?.id).toBe('key-a')
expect(key?.privateKey).toBe('private-key-a')
})

test('scopes listSigningTransactionsByTxIdsAndPublicKeys to authContext user', async () => {
const storeWithoutAuth = new StoreSql(db, pino({ level: 'silent' }))
const now = new Date()

await storeWithoutAuth.setSigningTransaction(userA.userId, {
id: 'tx-a',
hash: 'hash-a',
publicKey: 'public-key-a',
status: 'signed',
createdAt: now,
updatedAt: now,
})
await storeWithoutAuth.setSigningTransaction(userB.userId, {
id: 'tx-b',
hash: 'hash-b',
publicKey: 'public-key-b',
status: 'signed',
createdAt: now,
updatedAt: now,
})

const scopedStore = storeWithoutAuth.withAuthContext(userA)
const transactions =
await scopedStore.listSigningTransactionsByTxIdsAndPublicKeys(
['tx-a', 'tx-b'],
[]
)

expect(transactions).toHaveLength(1)
expect(transactions[0]?.id).toBe('tx-a')
})
})
2 changes: 2 additions & 0 deletions core/signing-store-sql/src/store-sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class StoreSql implements SigningDriverStore, AuthAware<StoreSql> {
.selectFrom('signingKeys')
.selectAll()
.where('publicKey', '=', publicKey)
.where('userId', '=', this.assertConnected())
.executeTakeFirst()
return result ? toSigningKey(result) : undefined
}
Expand Down Expand Up @@ -240,6 +241,7 @@ export class StoreSql implements SigningDriverStore, AuthAware<StoreSql> {
eb('id', 'in', txIds),
])
)
.where('userId', '=', this.assertConnected())
.execute()

return results.map(toSigningTransaction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LedgerClient,
} from '@canton-network/core-ledger-client'
import { createHash } from 'node:crypto'
import { AccessTokenProvider } from '@canton-network/core-wallet-auth'
import { AccessTokenProvider, UserId } from '@canton-network/core-wallet-auth'
import { Logger } from 'pino'

export type AllocatedParty = {
Expand Down Expand Up @@ -165,14 +165,14 @@ export class PartyAllocationService {
namespace: string,
transactions: string[],
signature: string,
userId: string
userId: UserId
): Promise<string>

async allocatePartyWithExistingWallet(
namespace: string,
transactions: string[],
signature: string,
userId: string
userId: UserId
): Promise<string> {
const synchronizerId =
this.synchronizerId ?? (await this.ledgerClient.getSynchronizerId())
Expand Down
Loading
Loading