Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions components/utility-components/nostr-context-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,20 @@ export function SignerContextProvider({ children }: { children: ReactNode }) {
loadKeys(signerObject);

const isAlreadyLoaded = localStorage.getItem("signer");
if (
!isAlreadyLoaded ||
JSON.stringify(existingSigner) !== isAlreadyLoaded
) {
localStorage.setItem("signer", JSON.stringify(existingSigner));
const shouldPersistSigner = existingSigner?.type !== "nip46";
const serializedSigner = JSON.stringify(existingSigner);
const hasStorageMismatch =
!isAlreadyLoaded || serializedSigner !== isAlreadyLoaded;

if (shouldPersistSigner && hasStorageMismatch) {
localStorage.setItem("signer", serializedSigner);
}

if (!shouldPersistSigner && isAlreadyLoaded) {
localStorage.removeItem("signer");
}

if (hasStorageMismatch || (!shouldPersistSigner && isAlreadyLoaded)) {
const shouldReloadSigner = false;
window.dispatchEvent(
new CustomEvent("storage", { detail: { shouldReloadSigner } })
Expand Down
41 changes: 40 additions & 1 deletion utils/nostr/__tests__/local-storage-data.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {
LogOut,
getDefaultBlossomServer,
getDefaultMint,
getDefaultRelays,
getLocalStorageData,
setLocalStorageDataOnSignIn,
} from "../nostr-helper-functions";

describe("getLocalStorageData", () => {
beforeEach(() => {
localStorage.clear();
LogOut();
jest.restoreAllMocks();
});

Expand Down Expand Up @@ -70,4 +72,41 @@ describe("getLocalStorageData", () => {
encryptedPrivKey: "ncryptsec1mock",
});
});

it("keeps bunker signer data in runtime memory only", () => {
setLocalStorageDataOnSignIn({
signer: {
toJSON: () => ({
type: "nip46",
bunker: "bunker://pubkey?secret=supersecret",
appPrivKey: "app-private-key",
}),
} as any,
});

const data = getLocalStorageData();

expect(data.signer).toEqual({
type: "nip46",
bunker: "bunker://pubkey?secret=supersecret",
appPrivKey: "app-private-key",
});
expect(localStorage.getItem("signer")).toBeNull();
});

it("removes legacy persisted bunker signer data on read", () => {
localStorage.setItem(
"signer",
JSON.stringify({
type: "nip46",
bunker: "bunker://pubkey?secret=legacysecret",
appPrivKey: "legacy-app-privkey",
})
);

const data = getLocalStorageData();

expect(data.signer).toBeUndefined();
expect(localStorage.getItem("signer")).toBeNull();
});
});
42 changes: 34 additions & 8 deletions utils/nostr/nostr-helper-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,17 @@ const LOCALSTORAGECONSTANTS = {
nwcInfo: "nwcInfo",
};

export type StoredSignerData =
| { type: "nip07" }
| { type: "nip46"; bunker: string; appPrivKey?: string }
| { type: "nsec"; encryptedPrivKey: string; pubkey?: string };

let runtimeSignerData: StoredSignerData | undefined;

function shouldPersistSignerData(signerData: StoredSignerData): boolean {
return signerData.type !== "nip46";
}

export const setLocalStorageDataOnSignIn = ({
encryptedPrivateKey,
relays,
Expand Down Expand Up @@ -1347,7 +1358,17 @@ export const setLocalStorageDataOnSignIn = ({
}

if (signer) {
localStorage.setItem(LOCALSTORAGECONSTANTS.signer, JSON.stringify(signer));
const signerData = signer.toJSON() as StoredSignerData;
runtimeSignerData = signerData;

if (shouldPersistSignerData(signerData)) {
localStorage.setItem(
LOCALSTORAGECONSTANTS.signer,
JSON.stringify(signerData)
);
} else {
localStorage.removeItem(LOCALSTORAGECONSTANTS.signer);
}
}

if (migrationComplete) {
Expand Down Expand Up @@ -1375,18 +1396,15 @@ export interface LocalStorageInterface {
bunkerRemotePubkey?: string;
bunkerRelays?: string[];
bunkerSecret?: string;
signer?:
| { type: "nip07" }
| { type: "nip46"; bunker: string; appPrivKey?: string }
| { type: "nsec"; encryptedPrivKey: string; pubkey?: string };
signer?: StoredSignerData;
nwcString?: string | null;
nwcInfo?: string | null;
migrationComplete?: boolean;
}

function isStoredSignerData(
value: unknown
): value is NonNullable<LocalStorageInterface["signer"]> {
): value is StoredSignerData {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return false;
}
Expand Down Expand Up @@ -1440,7 +1458,7 @@ export const getLocalStorageData = (): LocalStorageInterface => {
let bunkerRemotePubkey;
let bunkerRelays;
let bunkerSecret;
let signer: LocalStorageInterface["signer"] | undefined;
let signer: StoredSignerData | undefined = runtimeSignerData;
let migrationComplete;
let nwcString;
let nwcInfo;
Expand Down Expand Up @@ -1576,14 +1594,20 @@ export const getLocalStorageData = (): LocalStorageInterface => {
? localStorage.getItem(LOCALSTORAGECONSTANTS.bunkerSecret)
: undefined;

signer = getLocalStorageJson<LocalStorageInterface["signer"] | undefined>(
const persistedSigner = getLocalStorageJson<StoredSignerData | undefined>(
LOCALSTORAGECONSTANTS.signer,
undefined,
{
removeOnError: true,
validate: isStoredSignerData,
}
);
if (persistedSigner?.type === "nip46") {
localStorage.removeItem(LOCALSTORAGECONSTANTS.signer);
} else if (persistedSigner) {
signer = persistedSigner;
}

if (!signer) {
switch (signInMethod) {
case "extension":
Expand Down Expand Up @@ -1647,6 +1671,8 @@ export const getLocalStorageData = (): LocalStorageInterface => {
};

export const LogOut = () => {
runtimeSignerData = undefined;

// remove old data
localStorage.removeItem("npub");
localStorage.removeItem("signIn");
Expand Down