0d3b8ed23d
- Sanitize event-sourced URLs before CSS url() interpolation in ProfileCard banner and letter stationery background (closes H-1, H-2) - Sanitize event-sourced font families at the parse layer and in letter card/detail consumers that bypass resolveStationery (closes M-6) - Export sanitizeCssString for broader reuse - Route NWC wallet connection URIs and active pointer through a new useSecureLocalStorage hook, storing in iOS Keychain / Android KeyStore on native (closes M-1) - Add removeItem to secureStorage - Add Android backup/data-extraction rules that exclude WebView storage and Capacitor secure-storage SharedPreferences so wallet credentials don't leak via Google Auto Backup (closes M-5) - Document that GOOGLE_PLAY_SERVICE_ACCOUNT_JSON must be base64-encoded to match what the CI job expects (closes M-2)
58 lines
1.7 KiB
TypeScript
58 lines
1.7 KiB
TypeScript
import { Capacitor } from '@capacitor/core';
|
|
import { SecureStoragePlugin } from 'capacitor-secure-storage-plugin';
|
|
|
|
/**
|
|
* Storage adapter that uses native secure storage (iOS Keychain / Android KeyStore)
|
|
* on Capacitor builds and falls back to localStorage on web.
|
|
*
|
|
* Implements the `NLoginStorage` interface from @nostrify/react.
|
|
*
|
|
* On the first native read, if the key is not found in secure storage but exists
|
|
* in localStorage, it is automatically migrated to secure storage and the
|
|
* plaintext localStorage copy is removed.
|
|
*/
|
|
export const secureStorage = {
|
|
async getItem(key: string): Promise<string | null> {
|
|
if (!Capacitor.isNativePlatform()) {
|
|
return localStorage.getItem(key);
|
|
}
|
|
|
|
try {
|
|
const { value } = await SecureStoragePlugin.get({ key });
|
|
return value;
|
|
} catch {
|
|
// Key not found in secure storage — check localStorage for migration.
|
|
const legacy = localStorage.getItem(key);
|
|
if (legacy !== null) {
|
|
// Migrate to secure storage and remove the plaintext copy.
|
|
await SecureStoragePlugin.set({ key, value: legacy });
|
|
localStorage.removeItem(key);
|
|
return legacy;
|
|
}
|
|
return null;
|
|
}
|
|
},
|
|
|
|
async setItem(key: string, value: string): Promise<void> {
|
|
if (!Capacitor.isNativePlatform()) {
|
|
localStorage.setItem(key, value);
|
|
return;
|
|
}
|
|
|
|
await SecureStoragePlugin.set({ key, value });
|
|
},
|
|
|
|
async removeItem(key: string): Promise<void> {
|
|
if (!Capacitor.isNativePlatform()) {
|
|
localStorage.removeItem(key);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await SecureStoragePlugin.remove({ key });
|
|
} catch {
|
|
// Key didn't exist — ignore.
|
|
}
|
|
},
|
|
};
|