Skip to content

Commit 3831cc2

Browse files
Throw specific error when trying to sign with an expired session (#887)
* Throw when supported session signer is expired * Fix tests
1 parent 7e9b483 commit 3831cc2

3 files changed

Lines changed: 46 additions & 6 deletions

File tree

packages/wallet/core/src/signers/session-manager.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,9 @@ export class SessionManager implements SapientSigner {
137137
if (identitySigners.length === 0) {
138138
throw new Error('Identity signers not found')
139139
}
140-
const validImplicitSigners = this._implicitSigners.filter((signer) => signer.isValid(topology, chainId).isValid)
141-
const validExplicitSigners = this._explicitSigners.filter((signer) => signer.isValid(topology, chainId).isValid)
142140

143141
// Prioritize implicit signers
144-
const availableSigners = [...validImplicitSigners, ...validExplicitSigners]
142+
const availableSigners = [...this._implicitSigners, ...this._explicitSigners]
145143
if (availableSigners.length === 0) {
146144
throw new Error('No signers match the topology')
147145
}
@@ -150,9 +148,18 @@ export class SessionManager implements SapientSigner {
150148
const signers: SessionSigner[] = []
151149
for (const call of calls) {
152150
let supported = false
151+
let expiredSupportedSigner: SessionSigner | undefined
153152
for (const signer of availableSigners) {
154153
try {
155154
supported = await signer.supportedCall(wallet, chainId, call, this.address, this._provider)
155+
if (supported) {
156+
// Check signer validity
157+
const signerValidity = await signer.isValid(topology, chainId)
158+
if (signerValidity.invalidReason === 'Expired') {
159+
expiredSupportedSigner = signer
160+
}
161+
supported = signerValidity.isValid
162+
}
156163
} catch (error) {
157164
console.error('findSignersForCalls error', error)
158165
continue
@@ -163,6 +170,9 @@ export class SessionManager implements SapientSigner {
163170
}
164171
}
165172
if (!supported) {
173+
if (expiredSupportedSigner) {
174+
throw new Error(`Signer supporting call is expired: ${expiredSupportedSigner.address}`)
175+
}
166176
throw new Error('No signer supported for call')
167177
}
168178
}
@@ -256,6 +266,7 @@ export class SessionManager implements SapientSigner {
256266

257267
const signers = await this.findSignersForCalls(wallet, chainId, payload.calls)
258268
if (signers.length !== payload.calls.length) {
269+
// Unreachable. Throw in findSignersForCalls
259270
throw new Error('No signer supported for call')
260271
}
261272
const signatures = await Promise.all(

packages/wallet/core/test/session-manager.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ for (const extension of ALL_EXTENSIONS) {
562562

563563
// Sign the transaction
564564
expect(sessionManager.signSapient(wallet.address, chainId, payload, imageHash)).rejects.toThrow(
565-
'No signers match the topology',
565+
`Signer supporting call is expired: ${explicitSigner.address}`,
566566
)
567567
},
568568
timeout,

packages/wallet/dapp-client/src/ChainSessionManager.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,9 @@ export class ChainSessionManager {
449449
throw new ModifyExplicitSessionError('Session address is required.')
450450
}
451451

452-
const existingExplicitSession: ExplicitSession = this.explicitSessions.find((s) =>
452+
const existingExplicitSession = this.explicitSessions.find((s) =>
453453
Address.isEqual(s.sessionAddress!, modifiedExplicitSession.sessionAddress!),
454-
) as ExplicitSession
454+
)
455455
if (!existingExplicitSession) {
456456
throw new ModifyExplicitSessionError('Session not found.')
457457
}
@@ -487,6 +487,8 @@ export class ChainSessionManager {
487487
}
488488

489489
existingExplicitSession.permissions = modifiedExplicitSession.permissions
490+
existingExplicitSession.deadline = modifiedExplicitSession.deadline
491+
existingExplicitSession.valueLimit = modifiedExplicitSession.valueLimit
490492

491493
if (this.transport?.mode === TransportMode.POPUP) {
492494
this.transport?.closeWallet()
@@ -721,6 +723,20 @@ export class ChainSessionManager {
721723
throw new InitializationError(`Explicit session init failed after ${maxRetries} attempts: ${lastError.message}`)
722724
}
723725

726+
private async _refreshExplicitSession(expiredSignerAddress: Address.Address): Promise<void> {
727+
if (!this.wallet || !this.sessionManager || !this.provider || !this.isInitialized)
728+
throw new InitializationError('Session is not initialized.')
729+
// Find current explicit session
730+
const explicitSigner = this.explicitSessions.find((s) => Address.isEqual(s.sessionAddress, expiredSignerAddress))
731+
if (!explicitSigner) throw new ModifyExplicitSessionError('Explicit session not found.')
732+
// Update the deadline
733+
const newExplicitSession = {
734+
...explicitSigner,
735+
deadline: BigInt(Math.floor(Date.now() / 1000)) + BigInt(24 * 60 * 60),
736+
}
737+
await this.modifyExplicitSession(newExplicitSession)
738+
}
739+
724740
/**
725741
* Checks if the current session has permission to execute a set of transactions.
726742
* @param transactions The transactions to check permissions for.
@@ -747,6 +763,19 @@ export class ChainSessionManager {
747763
await this.sessionManager.findSignersForCalls(this.wallet.address, this.chainId, calls)
748764
return true
749765
} catch (error) {
766+
if (error instanceof Error && error.message.includes('Signer supporting call is expired')) {
767+
// Extract the expired signer address from the message with address regex
768+
const expiredSignerAddress = error.message.match(/(0x[0-9a-fA-F]{40})/)?.[1]
769+
if (expiredSignerAddress) {
770+
// Refresh the session
771+
await this._refreshExplicitSession(Address.from(expiredSignerAddress))
772+
// Retry the permission check
773+
return this.hasPermission(transactions)
774+
} else {
775+
// Could not parse error message. Rethrow as this shouldn't happen.
776+
throw error
777+
}
778+
}
750779
// An error from findSignersForCalls indicates a permission failure.
751780
console.warn(
752781
`Permission check failed for chain ${this.chainId}:`,

0 commit comments

Comments
 (0)