taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit e5747aa88008c3d94bf49907b44629c8a08292b4
parent 0fb764621e173493d09501b833b23d1e7a1237db
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Fri, 23 Oct 2026 12:35:37 +0200

mailbox/taldir: actually update mailbox expiration in wallet DB; simplify code

Diffstat:
Mpackages/taler-util/src/types-taler-wallet.ts | 3++-
Mpackages/taler-wallet-core/src/mailbox.ts | 54+++++++++++++++++++++++++++++++++++++-----------------
Mpackages/taler-wallet-core/src/wallet-api-types.ts | 4++--
3 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts @@ -1721,8 +1721,9 @@ export interface GetMailboxResponse { mailboxConfiguration?: MailboxConfiguration; } -export interface MailboxMessageRecordsResponse { +export interface MailboxRefreshResponse { messages: MailboxMessageRecord[]; + mailboxExpiration: Timestamp; } export interface GetMailboxRequest { diff --git a/packages/taler-wallet-core/src/mailbox.ts b/packages/taler-wallet-core/src/mailbox.ts @@ -31,7 +31,7 @@ import { Logger, MailboxConfiguration, MailboxMessageRecord, - MailboxMessageRecordsResponse, + MailboxRefreshResponse, MailboxMessagesResponse, MailboxMetadata, MailboxRefreshRequest, @@ -335,7 +335,7 @@ function decryptTalerUriMessage( export async function refreshMailbox( wex: WalletExecutionContext, req: MailboxRefreshRequest, -): Promise<MailboxMessageRecordsResponse> { +): Promise<MailboxRefreshResponse> { return runWithMaybeProgressContext( wex, "mailboxRefreshRequest", @@ -347,12 +347,23 @@ export async function refreshMailbox( async function internalRefreshMailbox( wex: WalletExecutionContext, req: MailboxRefreshRequest, -): Promise<MailboxMessageRecordsResponse> { - const mailboxConf = req.mailboxConf; +): Promise<MailboxRefreshResponse> { const mailboxClient = new TalerMailboxInstanceHttpClient( - mailboxConf.mailboxBaseUrl, + req.mailboxConf.mailboxBaseUrl, wex.http, ); + const mailboxMeta = await runWithProgressRetries(wex, async () => + succeedOrThrow(await mailboxClient.getMailboxInfo( + req.mailboxConf.hAddress, + )), + ); + // Update expiration if changed + if (req.mailboxConf.expiration.t_s != mailboxMeta.expiration.t_s) { + req.mailboxConf.expiration = mailboxMeta.expiration; + await wex.runWalletDbTx(async (tx) => { + await tx.upsertMailboxConfiguration(req.mailboxConf); + }); + } // Refresh message size var message_size; var message_response_limit; @@ -367,7 +378,7 @@ async function internalRefreshMailbox( default: throw TalerError.fromDetail( TalerErrorCode.WALLET_MAILBOX_UNAVAILABLE, - { mailboxBaseUrl: mailboxConf.mailboxBaseUrl }, + { mailboxBaseUrl: req.mailboxConf.mailboxBaseUrl }, "could not read the configuration of the mailbox service", ); } @@ -378,7 +389,7 @@ async function internalRefreshMailbox( throw TalerError.fromDetail( TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { - requestUrl: mailboxConf.mailboxBaseUrl, + requestUrl: req.mailboxConf.mailboxBaseUrl, requestMethod: "GET", httpStatusCode: HttpStatusCode.Ok, }, @@ -386,8 +397,8 @@ async function internalRefreshMailbox( ); } - const hpkeSk: Uint8Array = decodeCrock(mailboxConf.privateEncryptionKey); - const privateSigningKey: Uint8Array = decodeCrock(mailboxConf.privateKey); + const hpkeSk: Uint8Array = decodeCrock(req.mailboxConf.privateEncryptionKey); + const privateSigningKey: Uint8Array = decodeCrock(req.mailboxConf.privateKey); const records: MailboxMessageRecord[] = []; for ( let batchIndex = 0; @@ -396,13 +407,13 @@ async function internalRefreshMailbox( ) { const res = await runWithProgressRetries(wex, async () => await mailboxClient.getMessages({ - hMailbox: mailboxConf.hAddress, + hMailbox: req.mailboxConf.hAddress, }), ); if (res.case !== "ok") { throw TalerError.fromDetail( TalerErrorCode.WALLET_MAILBOX_UNAVAILABLE, - { mailboxBaseUrl: mailboxConf.mailboxBaseUrl }, + { mailboxBaseUrl: req.mailboxConf.mailboxBaseUrl }, "the mailbox service did not return the messages", ); } @@ -413,7 +424,7 @@ async function internalRefreshMailbox( throw TalerError.fromDetail( TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { - requestUrl: mailboxConf.mailboxBaseUrl, + requestUrl: req.mailboxConf.mailboxBaseUrl, requestMethod: "GET", httpStatusCode: HttpStatusCode.Ok, }, @@ -422,7 +433,10 @@ async function internalRefreshMailbox( } const numMessages = messages.byteLength / message_size; if (numMessages === 0) { - return { messages: records }; + return { + messages: records, + mailboxExpiration: mailboxMeta.expiration, + }; } for (let i = 0; i < numMessages; i++) { @@ -434,7 +448,7 @@ async function internalRefreshMailbox( continue; } const newMessage = { - originMailboxBaseUrl: mailboxConf.mailboxBaseUrl, + originMailboxBaseUrl: req.mailboxConf.mailboxBaseUrl, talerUri: uri, downloadedAt: now, }; @@ -457,7 +471,7 @@ async function internalRefreshMailbox( await runWithProgressRetries(wex, async () => succeedOrThrow( await mailboxClient.deleteMessages({ - mailboxConf, + mailboxConf: req.mailboxConf, matchIf: res.body.etag, count: numMessages, signature: encodeCrock(signature), @@ -466,13 +480,19 @@ async function internalRefreshMailbox( ); if (!mailboxBatchMayHaveMoreMessages(numMessages, message_response_limit)) { - return { messages: records }; + return { + messages: records, + mailboxExpiration: mailboxMeta.expiration, + }; } } logger.warn( `mailbox refresh stopped after ${MAX_MAILBOX_REFRESH_BATCHES} full batches`, ); - return { messages: records }; + return { + messages: records, + mailboxExpiration: mailboxMeta.expiration, + }; } function encryptTalerUriMessage( diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -159,7 +159,7 @@ import { ListSubscriptionsRequest, ListSubscriptionsResponse, MailboxConfiguration, - MailboxMessageRecordsResponse, + MailboxRefreshResponse, MailboxMessagesResponse, PrepareBankIntegratedWithdrawalRequest, PrepareBankIntegratedWithdrawalResponse, @@ -650,7 +650,7 @@ export type GetSupportedAliasesOp = { export type RefreshMailboxOp = { op: WalletApiOperation.RefreshMailbox; request: MailboxRefreshRequest; - response: MailboxMessageRecordsResponse; + response: MailboxRefreshResponse; }; /**