feat(notifications): mint long-lived JWT for native New Activity prefetch (Phase A)
Add BACKGROUND_JWT_EXPIRY_DAYS/SECONDS and accessTokenForBackgroundNotifications via createEndorserJwtForDid; configureNativeFetcher uses it instead of getHeaders so WorkManager prefetch is not stuck with a 60s access token. Interactive API calls unchanged.
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -8685,8 +8685,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@timesafari/daily-notification-plugin": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#469167a55fbebb91b3e61d6c8b3aec6fc873a13c",
|
||||
"version": "2.2.0",
|
||||
"resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#9121b1e0f7e1be50d00eb3e78d52e06816196697",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
|
||||
9
src/constants/backgroundJwt.ts
Normal file
9
src/constants/backgroundJwt.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* JWT lifetime for native New Activity background prefetch (`configureNativeFetcher`).
|
||||
* Phase A: single long-lived token minted in TS; see doc/plan-background-jwt-pool-and-expiry.md.
|
||||
* Confirm max `exp` with Endorser before raising.
|
||||
*/
|
||||
export const BACKGROUND_JWT_EXPIRY_DAYS = 90;
|
||||
|
||||
export const BACKGROUND_JWT_EXPIRY_SECONDS =
|
||||
BACKGROUND_JWT_EXPIRY_DAYS * 24 * 60 * 60;
|
||||
@@ -4,6 +4,7 @@ import { entropyToMnemonic } from "ethereum-cryptography/bip39";
|
||||
import { wordlist } from "ethereum-cryptography/bip39/wordlists/english";
|
||||
import { HDNode } from "@ethersproject/hdnode";
|
||||
|
||||
import { BACKGROUND_JWT_EXPIRY_SECONDS } from "@/constants/backgroundJwt";
|
||||
import {
|
||||
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
|
||||
createEndorserJwtForDid,
|
||||
@@ -104,6 +105,23 @@ export const accessToken = async (did?: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* JWT for native New Activity prefetch (`configureNativeFetcher` / WorkManager).
|
||||
* Uses a long `exp` (`BACKGROUND_JWT_EXPIRY_SECONDS`); do not use for ordinary
|
||||
* in-app API calls — use `getHeaders` / `accessToken` instead.
|
||||
*/
|
||||
export const accessTokenForBackgroundNotifications = async (
|
||||
did?: string,
|
||||
): Promise<string> => {
|
||||
if (!did) {
|
||||
return "";
|
||||
}
|
||||
const nowEpoch = Math.floor(Date.now() / 1000);
|
||||
const endEpoch = nowEpoch + BACKGROUND_JWT_EXPIRY_SECONDS;
|
||||
const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did };
|
||||
return createEndorserJwtForDid(did, tokenPayload);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract JWT from various URL formats
|
||||
* @param jwtUrlText The URL containing the JWT
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
||||
import { getHeaders } from "@/libs/endorserServer";
|
||||
import { accessTokenForBackgroundNotifications } from "@/libs/crypto";
|
||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||
import { logger } from "@/utils/logger";
|
||||
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
||||
@@ -63,12 +63,7 @@ export async function configureNativeFetcherIfReady(
|
||||
: DEFAULT_ENDORSER_API_SERVER;
|
||||
}
|
||||
|
||||
const headers = await getHeaders(did);
|
||||
const auth = headers?.Authorization;
|
||||
const jwtToken =
|
||||
typeof auth === "string" && auth.startsWith("Bearer ")
|
||||
? auth.slice(7)
|
||||
: "";
|
||||
const jwtToken = await accessTokenForBackgroundNotifications(did);
|
||||
if (!jwtToken) {
|
||||
logger.warn(
|
||||
"[nativeFetcherConfig] No JWT for native fetcher; API-driven notifications may fail",
|
||||
|
||||
Reference in New Issue
Block a user