Skip to content

Commit

Permalink
feat: use passkeys in sdk initialisation (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
ditoglez authored Dec 15, 2023
1 parent 8bbf79f commit a3a8fe3
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 73 deletions.
19 changes: 9 additions & 10 deletions apps/idos-enclave/src/enclave.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import { idOSKeyDerivation } from "./idOSKeyDerivation";
export class Enclave {
constructor({ parentOrigin }) {
this.parentOrigin = parentOrigin;

this.store = new Store();
this.storeBase64 = this.store.pipeCodec(Base64Codec);

this.unlockButton = document.querySelector("button#unlock");
this.confirmButton = document.querySelector("button#confirm");

let secretKey = this.storeBase64.get("encryption-private-key");
const storeWithCodec = this.store.pipeCodec(Base64Codec);
let secretKey = storeWithCodec.get("encryption-private-key");
if (secretKey) this.keyPair = nacl.box.keyPair.fromSecretKey(secretKey);

this.#listenToRequests();
Expand All @@ -30,8 +29,8 @@ export class Enclave {
signerPublicKey && this.store.set("signer-public-key", signerPublicKey);

return {
encryptionPublicKey: this.storeBase64.get("encryption-public-key"),
humanId: this.store.get("human-id"),
encryptionPublicKey: this.store.get("encryption-public-key"),
signerAddress: this.store.get("signer-address"),
signerPublicKey: this.store.get("signer-public-key")
};
Expand Down Expand Up @@ -115,14 +114,16 @@ export class Enclave {
const password = this.store.get("password");
const salt = this.store.get("human-id");

const storeWithCodec = this.store.pipeCodec(Base64Codec);

let secretKey =
this.storeBase64.get("encryption-private-key") ||
storeWithCodec.get("encryption-private-key") ||
(await idOSKeyDerivation({ password, salt }));

this.keyPair = nacl.box.keyPair.fromSecretKey(secretKey);

this.storeBase64.set("encryption-private-key", this.keyPair.secretKey);
this.storeBase64.set("encryption-public-key", this.keyPair.publicKey);
storeWithCodec.set("encryption-private-key", this.keyPair.secretKey);
storeWithCodec.set("encryption-public-key", this.keyPair.publicKey);
}

encrypt(message, receiverPublicKey) {
Expand All @@ -142,7 +143,7 @@ export class Enclave {
{
message: Base64Codec.encode(message),
nonce: Base64Codec.encode(nonce),
receiverPublicKey: Base64Codec.encode(receiverPublicKey),
senderPublicKey: Base64Codec.encode(senderPublicKey),
localPublicKey: Base64Codec.encode(this.keyPair.publicKey)
},
null,
Expand All @@ -158,8 +159,6 @@ export class Enclave {
}

decrypt(fullMessage, senderPublicKey) {
senderPublicKey = senderPublicKey || this.keyPair.publicKey;

const nonce = fullMessage.slice(0, nacl.box.nonceLength);
const message = fullMessage.slice(nacl.box.nonceLength, fullMessage.length);

Expand Down
21 changes: 19 additions & 2 deletions apps/idos-example-dapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,31 @@ <h2>Connect wallet</h2>
<p>
<strong>Show:</strong>
<br />
<label><input type="checkbox" name="wallets" />Wallets</label>
<br />
<label><input type="checkbox" name="consent" />Consent</label>
<br />
<label><input type="checkbox" name="wallets" />Wallets</label>
<br />
<label><input type="checkbox" name="credentials" />Credentials</label>
<br />
<label><input type="checkbox" name="grants" />Grants</label>
</p>
<p>
<strong>Use:</strong>
<br />
<label
><input type="radio" name="use" value="" checked />Password</label
>
<br />
<label
><input type="radio" name="use" value="password" />Passkey
(password)</label
>
<br />
<label
><input type="radio" name="use" value="webauthn" />Passkey
(WebAuthn)</label
>
</p>
</form>

<div id="terminal">
Expand Down
12 changes: 7 additions & 5 deletions apps/idos-example-dapp/src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ export class Cache {
}

get(key) {
return JSON.parse(this.store.getItem(key), (k, v) =>
v && v.bigint ? BigInt(v.bigint) : v
return JSON.parse(
this.store.getItem(key),
(k, v) => v && v.bigint ? BigInt(v.bigint) : v,
);
}

set(key, value) {
return (this.store[key] = JSON.stringify(value, (k, v) =>
typeof v === "bigint" ? { bigint: v.toString() } : v
));
return this.store[key] = JSON.stringify(
value,
(k, v) => typeof v === "bigint" ? {bigint: v.toString()} : v,
);
}
}
9 changes: 8 additions & 1 deletion apps/idos-example-dapp/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import { Terminal } from "./terminal";
* Initializing the idOS
*
*/
const idos = await idOS.init({ container: "#idos-container" });
const idos = await idOS.init({
container: "#idos-container"
});

/*
* Setting up the demo
Expand Down Expand Up @@ -49,6 +51,11 @@ if (!chosenWallet) {
);
window.localStorage.setItem("chosen-flow", JSON.stringify(chosenFlow));

window.localStorage.setItem(
"use",
e.target.querySelector("input[type=radio]:checked").value
);

resolve();
});
});
Expand Down
1 change: 1 addition & 0 deletions apps/idos-example-dapp/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ div#terminal {
height: 500px;
flex-direction: column;
justify-content: flex-end;
margin: 10px 0;
}

div#terminal:has(> #overview:not(:empty)) {
Expand Down
70 changes: 24 additions & 46 deletions apps/idos-example-dapp/src/terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,26 @@ export class Terminal {

this.currentElem = this.overviewElem;

document.querySelector("button#close").addEventListener("click", (e) => {
document.querySelector("button#close").addEventListener("click", e => {
this.detailElem.parentElement.classList.remove("visible");
this.detailElem.innerHTML = "";
this.currentElem = this.overviewElem;
});

this.restartButton = wrapper.querySelector("button.restart");
this.restartButton.addEventListener(
"click",
(e) => (window.location = window.location.origin)
);
this.restartButton.addEventListener("click", e => (
window.location = window.location.origin
));

this.resetDappButton = wrapper.querySelector("button.reset-dapp");
this.resetDappButton.addEventListener("click", async (e) => {
this.resetDappButton.addEventListener("click", async e => {
window.localStorage.clear();
await idos.reset();
window.location = window.location.origin;
});

this.resetFullButton = wrapper.querySelector("button.reset-full");
this.resetFullButton.addEventListener("click", async (e) => {
this.resetFullButton.addEventListener("click", async e => {
window.localStorage.clear();
await idos.reset({ enclave: true });
window.location = window.location.origin;
Expand All @@ -39,13 +38,11 @@ export class Terminal {
}

log(str) {
this.currentElem.innerHTML += /^<.*>$/.test(str)
? str
: `<span>${str}</span>`;
this.currentElem.innerHTML += /^<.*>$/.test(str) ? str : `<span>${str}</span>`;

this.overviewElem.scrollTo({
top: this.overviewElem.scrollHeight,
behavior: "smooth"
behavior: "smooth",
});

return this;
Expand All @@ -68,13 +65,12 @@ export class Terminal {
table(items = [], keyFilter = [], handlers) {
const wrappedItems = Array.isArray(items) ? items : [items];

const allKeys = Object.keys(
wrappedItems[0] || Object.fromEntries(keyFilter.map((e) => [e]))
);
const allKeys =
Object.keys(wrappedItems[0] || Object.fromEntries(keyFilter.map(e => [e])));
if (!allKeys.length) throw new Error(`No keys in ${JSON.stringify(items)}`);

const keys = keyFilter.length ? keyFilter : allKeys;
const headers = keys.map((key) =>
const headers = keys.map(key =>
key
.replaceAll(/([a-z])([A-Z])/g, "$1 $2")
.toLowerCase()
Expand All @@ -88,57 +84,39 @@ export class Terminal {
<div class="table">
<div class="thead">
<div class="tr">
${headers.reduce(
(row, header) =>
row +
`
${headers.reduce((row, header) => row + `
<div class="td"><span>${header}</span></div>
`,
""
)}
`, "")}
</div>
</div>
<div class="tbody">
${wrappedItems
.map((item) => keys.map((key) => [key, item[key]]))
.reduce(
(row, values) =>
row +
`
.map(item => keys.map(key => [key, item[key]]))
.reduce((row, values) => row + `
<div class="tr">
${values.reduce(
(row, [key, value]) =>
row +
`
${values.reduce((row, [key, value]) => row + `
<div class="td">
${
handlers?.[key]
? `<a onclick="terminalHandlers['${handlerId}']['${key}']('${value}')">${value}</a>`
: value
${handlers?.[key]
? `<a onclick="terminalHandlers['${handlerId}']['${key}']('${value}')">${value}</a>`
: value
}
</div>
`,
""
)}
`, "")}
</div>
`,
""
)}
`, "")}
</div>
</div>
`);
}

status(className, html = "") {
status(className, html="") {
return this.log(`<span class="status ${className}">${html}</span>`);
}

json(object) {
const stringified = JSON.stringify(object, "", 2).replace(
/"(data:.*?;).*/g,
"$1 (...)"
);
const stringified = JSON.stringify(object, "", 2)
.replace(/"(data:.*?;).*/g, "$1 (...)");
return this.log(`<pre>${stringified}</pre>`);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/idos-example-dapp/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineConfig } from "vite";
import mkcert from "vite-plugin-mkcert";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import mkcert from "vite-plugin-mkcert";

// https://vitejs.dev/config/
export default defineConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ export class IframeEnclave extends EnclaveProvider {

container: string;
iframe: HTMLIFrameElement;
usePasskeys?: string;

constructor(options: { container: string }) {
constructor(options: { container: string; usePasskeys?: boolean }) {
super();
this.container = options.container;
this.iframe = document.createElement("iframe");
this.usePasskeys = options.usePasskeys ? "webauthn" : undefined;
}

async load(): Promise<StoredData> {
Expand All @@ -27,7 +29,7 @@ export class IframeEnclave extends EnclaveProvider {

this.#showEnclave();

return this.#requestToEnclave({ keys: { usePasskeys: false } }).then((encryptionPublicKey) => {
return this.#requestToEnclave({ keys: { usePasskeys: this.usePasskeys } }).then((encryptionPublicKey) => {
this.#hideEnclave();
return encryptionPublicKey as Uint8Array;
});
Expand Down
4 changes: 2 additions & 2 deletions packages/idos-sdk-js/src/lib/enclave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ export class Enclave {
provider: EnclaveProvider;
encryptionPublicKey?: Uint8Array;

constructor(idOS: idOS, container: string, providerType: ProviderType = "iframe") {
constructor(idOS: idOS, container: string, providerType: ProviderType = "iframe", usePasskeys = false) {
this.initialized = false;
this.idOS = idOS;

switch (providerType) {
case "iframe":
this.provider = new IframeEnclave({ container });
this.provider = new IframeEnclave({ container, usePasskeys });
break;
case "metamask-snap":
this.provider = new MetaMaskSnapEnclave({});
Expand Down
9 changes: 5 additions & 4 deletions packages/idos-sdk-js/src/lib/idos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface InitParams {
nodeUrl?: string;
dbId?: string;
container: string;
usePasskeys?: boolean;
}

export class idOS {
Expand All @@ -30,21 +31,21 @@ export class idOS {
grants: Grants;
store: Store;

private constructor({ nodeUrl, dbId, container }: InitParams) {
private constructor({ nodeUrl, dbId, container, usePasskeys = false }: InitParams) {
if (!idOS.initializing) throw new Error("Usage: `idOS.init(options)`");

this.auth = new Auth(this);
this.data = new Data(this);
this.enclave = new Enclave(this, container);
this.enclave = new Enclave(this, container, undefined, usePasskeys);
this.kwilWrapper = new KwilWrapper({ nodeUrl, dbId });
this.grants = new Grants(this);
this.store = new Store();
}

static async init({ nodeUrl, dbId, container }: InitParams): Promise<idOS> {
static async init({ nodeUrl, dbId, container, usePasskeys }: InitParams): Promise<idOS> {
this.initializing = true;

const idos = new this({ nodeUrl, dbId, container });
const idos = new this({ nodeUrl, dbId, container, usePasskeys });
await idos.enclave.load();

return idos;
Expand Down

2 comments on commit a3a8fe3

@vercel
Copy link

@vercel vercel bot commented on a3a8fe3 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

idos-example-dapp – ./apps/idos-example-dapp

idos-example-dapp.vercel.app
idos-example-dapp-fractal-id.vercel.app
idos-example-dapp-git-main-fractal-id.vercel.app

@vercel
Copy link

@vercel vercel bot commented on a3a8fe3 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

idos-enclave – ./apps/idos-enclave

idos-enclave-git-main-fractal-id.vercel.app
idos-enclave.vercel.app
enclave.idos.network
idos-enclave-fractal-id.vercel.app

Please sign in to comment.