diff --git a/package-lock.json b/package-lock.json
index 169f7b91..b8cb2571 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"license": "APACHE 2.0",
"dependencies": {
"lodash": "^4.17.21",
+ "nanoid": "^5.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-intl": "^6.6.2",
@@ -4485,19 +4486,20 @@
"license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.7",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz",
+ "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"bin": {
- "nanoid": "bin/nanoid.cjs"
+ "nanoid": "bin/nanoid.js"
},
"engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ "node": "^18 || >=20"
}
},
"node_modules/natural-compare": {
@@ -5002,6 +5004,24 @@
"version": "4.2.0",
"license": "MIT"
},
+ "node_modules/postcss/node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"dev": true,
@@ -5764,6 +5784,23 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
+ "node_modules/styled-components/node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/styled-components/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
diff --git a/package.json b/package.json
index d2df7cf7..c732d778 100755
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"type": "module",
"dependencies": {
"lodash": "^4.17.21",
+ "nanoid": "^5.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-intl": "^6.6.2",
diff --git a/src/components/signinCard.tsx b/src/components/signinCard.tsx
index dcb143aa..6389b5a9 100644
--- a/src/components/signinCard.tsx
+++ b/src/components/signinCard.tsx
@@ -46,7 +46,7 @@ export function SigninCard({
? formatMessage({ id: "signin.identifierAlias" })
: formatMessage({ id: "credential.title" })}
- {signin?.identifier?.name}
+ {signin?.identifier?.name ?? signin?.credential?.schema?.title}
@@ -63,7 +63,7 @@ export function SigninCard({
{formatMessage({ id: "signin.autoSignin" })}
}
/>
diff --git a/src/components/signinList.tsx b/src/components/signinList.tsx
index 5cf8005a..706bf8ff 100644
--- a/src/components/signinList.tsx
+++ b/src/components/signinList.tsx
@@ -4,9 +4,12 @@ import { SigninCard } from "@components/signinCard";
import { Loader, Flex, Box, Text } from "@components/ui";
import { IMessage, ISignin } from "@config/types";
-interface IResourceSignin {
- index: number;
- signin?: ISignin;
+interface IDeleteSignin {
+ id: string;
+}
+
+interface IUpdateSignin {
+ signin: ISignin;
}
export function SigninList(): JSX.Element {
@@ -23,14 +26,14 @@ export function SigninList(): JSX.Element {
setIsLoading(false);
};
- const deleteSignin = async (index: number) => {
+ const deleteSignin = async (id: string) => {
const { data } = await chrome.runtime.sendMessage<
- IMessage
+ IMessage
>({
type: "delete-resource",
subtype: "signins",
data: {
- index,
+ id,
},
});
if (data?.isDeleted) {
@@ -52,15 +55,13 @@ export function SigninList(): JSX.Element {
}
};
- const updateAutoSignin = async (index: number, signin: ISignin) => {
- console.log("signin", signin, index);
+ const updateAutoSignin = async (signin: ISignin) => {
const { data } = await chrome.runtime.sendMessage<
- IMessage
+ IMessage
>({
type: "update-resource",
subtype: "auto-signin",
data: {
- index,
signin,
},
});
@@ -94,12 +95,12 @@ export function SigninList(): JSX.Element {
) : null}
- {signins.map((signin, index) => (
-
+ {signins.map((signin) => (
+
deleteSignin(index)}
- handleAutoSignin={() => updateAutoSignin(index, signin)}
+ handleDelete={() => deleteSignin(signin.id)}
+ handleAutoSignin={() => updateAutoSignin(signin)}
/>
))}
diff --git a/src/config/types.ts b/src/config/types.ts
index d7772c4d..3f5c27fc 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -1,3 +1,7 @@
+export interface ObjectOfArrays {
+ [key: string]: T[];
+}
+
export interface IMessage {
type: string;
subtype?: string;
@@ -31,18 +35,22 @@ export interface IVendorData {
}
export interface ISignin {
+ id: string;
domain: string;
identifier?: {
name?: string;
+ prefix?: string;
};
credential?: {
issueeName?: string;
+ sad: { d: string };
schema?: {
title: string;
};
};
- updatedAt: string;
- autoSignin: boolean;
+ createdAt: number;
+ updatedAt: number;
+ autoSignin?: boolean;
}
export interface IIdentifier {
@@ -52,7 +60,7 @@ export interface IIdentifier {
export interface ICredential {
issueeName: string;
- sad: { a: { i: string } };
+ sad: { a: { i: string }, d: string };
schema: {
title: string;
credentialType: string;
diff --git a/src/pages/background/index.ts b/src/pages/background/index.ts
index 8589d015..f0154cc7 100644
--- a/src/pages/background/index.ts
+++ b/src/pages/background/index.ts
@@ -1,10 +1,10 @@
-import { browserStorageService } from "@pages/background/services/browser-storage";
import {
WEB_APP_PERMS,
configService,
} from "@pages/background/services/config";
import { userService } from "@pages/background/services/user";
import { signifyService } from "@pages/background/services/signify";
+import * as signinResource from "@pages/background/resource/signin";
import { IMessage, IIdentifier, ICredential } from "@config/types";
import { senderIsPopup } from "@pages/background/utils";
import {
@@ -12,11 +12,6 @@ import {
getCurrentUrl,
setActionIcon,
} from "@pages/background/utils";
-import {
- updateDomainAutoSigninByIndex,
- getSigninsByDomain,
- deleteSigninByIndex,
-} from "@pages/background/signins-utils";
console.log("Background script loaded");
@@ -116,8 +111,7 @@ chrome.runtime.onMessage.addListener(function (
message.subtype === "auto-signin-signature"
) {
// Validate that message comes from a page that has a signin
- const origin = removeSlash(sender.url);
- const signins = await getSigninsByDomain(origin);
+ const signins = await signinResource.getSigninsByDomain(sender.url!);
const autoSignin = signins?.find((signin) => signin.autoSignin);
if (!signins?.length || !autoSignin) {
sendResponse({
@@ -179,7 +173,7 @@ chrome.runtime.onMessage.addListener(function (
message.type === "fetch-resource" &&
message.subtype === "tab-signin"
) {
- const signins = await getSigninsByDomain(removeSlash(sender.url));
+ const signins = await signinResource.getSigninsByDomain(sender.url);
const autoSigninObj = signins?.find((signin) => signin.autoSignin);
sendResponse({ data: { signins: signins ?? [], autoSigninObj } });
}
@@ -214,7 +208,6 @@ chrome.runtime.onMessage.addListener(function (
message.subtype === "disconnect-agent"
) {
await signifyService.disconnect();
- await userService.removePasscode();
sendResponse({ data: { isConnected: false } });
}
@@ -277,47 +270,44 @@ chrome.runtime.onMessage.addListener(function (
}
if (message.type === "create-resource" && message.subtype === "signin") {
- const signins = (await browserStorageService.getValue(
- "signins"
- )) as any[];
+ const signins = await signinResource.getSignins();
const currentUrl = await getCurrentUrl();
const { identifier, credential } = message.data;
let signinExists = false;
if (identifier && identifier.prefix) {
- signinExists = signins?.find(
- (signin) =>
- signin.domain === currentUrl?.origin &&
- signin?.identifier?.prefix === identifier.prefix
+ signinExists = Boolean(
+ signins?.find(
+ (signin) =>
+ signin.domain === currentUrl?.origin &&
+ signin?.identifier?.prefix === identifier.prefix
+ )
);
}
if (credential && credential.sad.d) {
- signinExists = signins?.find(
- (signin) =>
- signin.domain === currentUrl?.origin &&
- signin?.credential?.sad?.d === credential.sad.d
+ signinExists = Boolean(
+ signins?.find(
+ (signin) =>
+ signin.domain === currentUrl?.origin &&
+ signin?.credential?.sad?.d === credential.sad.d
+ )
);
}
if (signinExists) {
sendResponse({ data: { signins: signins } });
} else {
- const signinObj = {
+ const signinObj = signinResource.newSigninObject({
identifier,
credential,
- createdAt: new Date().getTime(),
- updatedAt: new Date().getTime(),
domain: currentUrl!.origin,
- };
+ });
if (signins && signins?.length) {
- await browserStorageService.setValue("signins", [
- ...signins,
- signinObj,
- ]);
+ await signinResource.updateSignins([...signins, signinObj]);
} else {
- await browserStorageService.setValue("signins", [signinObj]);
+ await signinResource.updateSignins([signinObj]);
}
- const storageSignins = await browserStorageService.getValue("signins");
+ const storageSignins = await signinResource.getSignins();
sendResponse({ data: { signins: storageSignins } });
}
}
@@ -344,10 +334,10 @@ chrome.runtime.onMessage.addListener(function (
}
if (message.type === "fetch-resource" && message.subtype === "signins") {
- const signins = await browserStorageService.getValue("signins");
+ const signins = await signinResource.getSignins();
sendResponse({
data: {
- signins: signins ?? [],
+ signins,
},
});
}
@@ -356,10 +346,7 @@ chrome.runtime.onMessage.addListener(function (
message.type === "update-resource" &&
message.subtype === "auto-signin"
) {
- const resp = await updateDomainAutoSigninByIndex(
- message?.data?.index,
- message?.data?.signin
- );
+ const resp = await signinResource.updateAutoSigninByDomain(message?.data?.signin);
sendResponse({
data: {
...resp,
@@ -368,7 +355,7 @@ chrome.runtime.onMessage.addListener(function (
}
if (message.type === "delete-resource" && message.subtype === "signins") {
- const resp = await deleteSigninByIndex(message?.data?.index);
+ const resp = await signinResource.deleteSigninById(message?.data?.id);
sendResponse({
data: {
...resp,
@@ -415,8 +402,7 @@ chrome.runtime.onMessageExternal.addListener(function (
message.subtype === "auto-signin-signature"
) {
// Validate that message comes from a page that has a signin
- const origin = removeSlash(sender.url);
- const signins = await getSigninsByDomain(origin);
+ const signins = await signinResource.getSigninsByDomain(sender.url);
console.log("signins", signins);
const autoSignin = signins?.find((signin) => signin.autoSignin);
if (!signins?.length || !autoSignin) {
@@ -431,7 +417,7 @@ chrome.runtime.onMessageExternal.addListener(function (
autoSignin?.identifier
? autoSignin?.identifier?.name
: autoSignin?.credential?.issueeName,
- origin
+ removeSlash(sender.url)
);
let jsonHeaders: { [key: string]: string } = {};
for (const pair of signedHeaders.entries()) {
diff --git a/src/pages/background/resource/signin/index.ts b/src/pages/background/resource/signin/index.ts
new file mode 100644
index 00000000..43e5b1c9
--- /dev/null
+++ b/src/pages/background/resource/signin/index.ts
@@ -0,0 +1,87 @@
+import { nanoid } from "nanoid";
+import { browserStorageService } from "@pages/background/services/browser-storage";
+import { signifyService } from "@pages/background/services/signify";
+import { removeSlash } from "@pages/background/utils";
+import {
+ ObjectOfArrays,
+ ISignin,
+ ICredential,
+ IIdentifier,
+} from "@config/types";
+
+type IObjectSignins = ObjectOfArrays;
+
+const getSigninsObject = async (): Promise => {
+ const signinsObj = (await browserStorageService.getValue(
+ "signins"
+ )) as IObjectSignins;
+ return signinsObj ?? {};
+};
+
+export const getSignins = async (): Promise => {
+ const signinsObj = await getSigninsObject();
+ const controllerId = await signifyService.getControllerID();
+ return signinsObj[controllerId] ?? [];
+};
+
+export const updateSignins = async (signins: ISignin[]) => {
+ const signinsObj = await getSigninsObject();
+ const controllerId = await signifyService.getControllerID();
+ signinsObj[controllerId] = signins;
+ await browserStorageService.setValue("signins", signinsObj);
+};
+
+export const getSigninsByDomain = async (url?: string) => {
+ const domain = removeSlash(url);
+ const signins = await getSignins();
+ return signins?.filter((signin) => signin.domain === domain);
+};
+
+export const updateAutoSigninByDomain = async (signin: ISignin) => {
+ let signins = await getSignins();
+ if (signins?.length) {
+ const newSignins = signins.map((_ele) => {
+ if (_ele.domain === signin.domain) {
+ if (signin.id === _ele.id)
+ return { ..._ele, autoSignin: !signin?.autoSignin };
+ return { ..._ele, autoSignin: false };
+ }
+ return _ele;
+ });
+ await updateSignins(newSignins);
+ signins = await getSignins();
+ }
+ return { signins };
+};
+
+export const deleteSigninById = async (id: string) => {
+ let signins = await getSignins();
+ let deleted = false;
+ if (signins?.length) {
+ const newSignins = signins.filter((_ele) => id !== _ele.id);
+ await updateSignins(newSignins);
+ deleted = newSignins.length !== signins?.length;
+ }
+ signins = await getSignins();
+ return { isDeleted: deleted, signins };
+};
+
+export const newSigninObject = ({
+ identifier,
+ credential,
+ domain,
+}: {
+ identifier?: IIdentifier;
+ credential?: ICredential;
+ domain: string;
+}): ISignin => {
+ const signinObj: ISignin = {
+ id: nanoid(),
+ credential,
+ domain,
+ identifier,
+ createdAt: new Date().getTime(),
+ updatedAt: new Date().getTime(),
+ };
+ return signinObj;
+};
diff --git a/src/pages/background/services/signify.ts b/src/pages/background/services/signify.ts
index 4fdde8c2..2ae23a1e 100644
--- a/src/pages/background/services/signify.ts
+++ b/src/pages/background/services/signify.ts
@@ -20,6 +20,7 @@ const Signify = () => {
} catch (error) {
console.log("Timer expired, client and passcode zeroed out");
_client = null;
+ await userService.removeControllerId();
await userService.removePasscode();
}
@@ -47,6 +48,8 @@ const Signify = () => {
_client = new SignifyClient(agentUrl, passcode, Tier.low, bootUrl);
await _client.boot();
await _client.connect();
+ const state = await getState();
+ await userService.setControllerId(state?.controller?.state?.i);
setTimeoutAlarm();
} catch (error) {
console.error(error);
@@ -60,6 +63,8 @@ const Signify = () => {
await ready();
_client = new SignifyClient(agentUrl, passcode, Tier.low);
await _client.connect();
+ const state = await getState();
+ await userService.setControllerId(state?.controller?.state?.i);
setTimeoutAlarm();
} catch (error) {
console.error(error);
@@ -117,6 +122,7 @@ const Signify = () => {
const disconnect = async () => {
_client = null;
+ await userService.removeControllerId();
await userService.removePasscode();
};
@@ -150,6 +156,11 @@ const Signify = () => {
return signed_headers;
};
+ const getControllerID = async (): Promise => {
+ const controllerId = await userService.getControllerId();
+ return controllerId;
+ };
+
const createAID = async (name: string) => {
validateClient();
let res = await _client?.identifiers().create(name);
@@ -166,6 +177,7 @@ const Signify = () => {
createAID,
generatePasscode,
bootAndConnect,
+ getControllerID,
};
};
diff --git a/src/pages/background/services/user.ts b/src/pages/background/services/user.ts
index b9f5140a..f91152d7 100644
--- a/src/pages/background/services/user.ts
+++ b/src/pages/background/services/user.ts
@@ -1,27 +1,50 @@
-import { browserStorageService } from "@pages/background/services/browser-storage"
+import { browserStorageService } from "@pages/background/services/browser-storage";
const USER_ENUMS = {
- PASSCODE: "user-passcode"
-}
+ PASSCODE: "user-passcode",
+ CONTROLLER_ID: "controller-id",
+};
const User = () => {
- const getPasscode = async () : Promise => {
- return await browserStorageService.getValue(USER_ENUMS.PASSCODE) as string;
- }
-
- const removePasscode = async () => {
- await browserStorageService.removeKey(USER_ENUMS.PASSCODE);
- }
-
- const setPasscode = async (passcode: string) => {
- await browserStorageService.setValue(USER_ENUMS.PASSCODE, passcode)
- }
-
- return {
- removePasscode,
- getPasscode,
- setPasscode
- }
-}
-
-export const userService = User()
\ No newline at end of file
+ const getPasscode = async (): Promise => {
+ return (await browserStorageService.getValue(
+ USER_ENUMS.PASSCODE
+ )) as string;
+ };
+
+ const removePasscode = async () => {
+ await browserStorageService.removeKey(USER_ENUMS.PASSCODE);
+ };
+
+ const setPasscode = async (passcode: string) => {
+ await browserStorageService.setValue(USER_ENUMS.PASSCODE, passcode);
+ };
+
+ const getControllerId = async (): Promise => {
+ return (await browserStorageService.getValue(
+ USER_ENUMS.CONTROLLER_ID
+ )) as string;
+ };
+
+ const removeControllerId = async () => {
+ await browserStorageService.removeKey(USER_ENUMS.CONTROLLER_ID);
+ };
+
+ const setControllerId = async (controllerId: string) => {
+ await browserStorageService.setValue(
+ USER_ENUMS.CONTROLLER_ID,
+ controllerId
+ );
+ };
+
+ return {
+ removePasscode,
+ getPasscode,
+ setPasscode,
+ getControllerId,
+ setControllerId,
+ removeControllerId,
+ };
+};
+
+export const userService = User();
diff --git a/src/pages/background/signins-utils.ts b/src/pages/background/signins-utils.ts
deleted file mode 100644
index c54ee8e6..00000000
--- a/src/pages/background/signins-utils.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { browserStorageService } from "@pages/background/services/browser-storage";
-import { ISignin } from "@config/types";
-
-export const getSigninsByDomain = async (domain: string) => {
- const signins = (await browserStorageService.getValue(
- "signins"
- )) as ISignin[];
- return signins?.filter((signin) => signin.domain === domain) ?? [];
-};
-
-export const updateDomainAutoSigninByIndex = async (
- index: number,
- signin: ISignin
-) => {
- let signins = (await browserStorageService.getValue("signins")) as ISignin[];
- if (signins?.length) {
- const newSignins = signins.map((_ele, idx) => {
- if (idx !== index && _ele.domain !== signin.domain) return _ele;
-
- if (idx !== index && _ele.domain === signin.domain)
- return { ..._ele, autoSignin: false };
-
- return { ..._ele, autoSignin: !signin?.autoSignin };
- });
- await browserStorageService.setValue("signins", newSignins);
- }
- signins = (await browserStorageService.getValue("signins")) as ISignin[];
-
- return { signins };
-};
-
-export const deleteSigninByIndex = async (index: number) => {
- let signins = (await browserStorageService.getValue("signins")) as ISignin[];
- let deleted = false;
- if (signins?.length) {
- const newSignins = signins.filter((_ele, idx) => idx !== index);
- await browserStorageService.setValue("signins", newSignins);
- deleted = newSignins.length !== signins?.length;
- }
- signins = (await browserStorageService.getValue("signins")) as ISignin[];
-
- return { isDeleted: deleted, signins };
-};