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:
Generated
+2
-2
@@ -8685,8 +8685,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@timesafari/daily-notification-plugin": {
|
"node_modules/@timesafari/daily-notification-plugin": {
|
||||||
"version": "2.1.5",
|
"version": "2.2.0",
|
||||||
"resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#469167a55fbebb91b3e61d6c8b3aec6fc873a13c",
|
"resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#9121b1e0f7e1be50d00eb3e78d52e06816196697",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|||||||
@@ -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 { wordlist } from "ethereum-cryptography/bip39/wordlists/english";
|
||||||
import { HDNode } from "@ethersproject/hdnode";
|
import { HDNode } from "@ethersproject/hdnode";
|
||||||
|
|
||||||
|
import { BACKGROUND_JWT_EXPIRY_SECONDS } from "@/constants/backgroundJwt";
|
||||||
import {
|
import {
|
||||||
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
|
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
|
||||||
createEndorserJwtForDid,
|
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
|
* Extract JWT from various URL formats
|
||||||
* @param jwtUrlText The URL containing the JWT
|
* @param jwtUrlText The URL containing the JWT
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import { Capacitor } from "@capacitor/core";
|
import { Capacitor } from "@capacitor/core";
|
||||||
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
||||||
import { getHeaders } from "@/libs/endorserServer";
|
import { accessTokenForBackgroundNotifications } from "@/libs/crypto";
|
||||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||||
import { logger } from "@/utils/logger";
|
import { logger } from "@/utils/logger";
|
||||||
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
||||||
@@ -63,12 +63,7 @@ export async function configureNativeFetcherIfReady(
|
|||||||
: DEFAULT_ENDORSER_API_SERVER;
|
: DEFAULT_ENDORSER_API_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = await getHeaders(did);
|
const jwtToken = await accessTokenForBackgroundNotifications(did);
|
||||||
const auth = headers?.Authorization;
|
|
||||||
const jwtToken =
|
|
||||||
typeof auth === "string" && auth.startsWith("Bearer ")
|
|
||||||
? auth.slice(7)
|
|
||||||
: "";
|
|
||||||
if (!jwtToken) {
|
if (!jwtToken) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"[nativeFetcherConfig] No JWT for native fetcher; API-driven notifications may fail",
|
"[nativeFetcherConfig] No JWT for native fetcher; API-driven notifications may fail",
|
||||||
|
|||||||
Reference in New Issue
Block a user