-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
539 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,22 @@ | ||
import { createCredential } from "webauthn-p256"; | ||
import { cache } from "./cache"; | ||
import { P256Credential } from "viem/account-abstraction"; | ||
import { createBridge, PasskeyCredential } from "@latticexyz/id/internal"; | ||
|
||
export async function createPasskey(): Promise<P256Credential> { | ||
const credential = await createCredential({ name: "MUD Account" }); | ||
console.log("created passkey", credential); | ||
export async function createPasskey(): Promise<PasskeyCredential> { | ||
const bridge = await createBridge({ message: "Creating account…" }); | ||
try { | ||
const credential = await bridge.request("create"); | ||
console.log("created passkey", credential); | ||
|
||
cache.setState((state) => ({ | ||
activeCredential: credential.id, | ||
publicKeys: { | ||
...state.publicKeys, | ||
[credential.id]: credential.publicKey, | ||
}, | ||
})); | ||
cache.setState((state) => ({ | ||
activeCredential: credential.credentialId, | ||
publicKeys: { | ||
...state.publicKeys, | ||
[credential.credentialId]: credential.publicKey, | ||
}, | ||
})); | ||
|
||
return credential; | ||
return credential; | ||
} finally { | ||
bridge.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { getCandidatePublicKeys } from "./getCandidatePublicKeys"; | ||
import { SignatureAndMessage } from "./common"; | ||
import { Hex } from "viem"; | ||
|
||
export function findPublicKey([input1, input2]: [SignatureAndMessage, SignatureAndMessage]): Hex | undefined { | ||
// Return the candidate public key that appears twice | ||
return firstDuplicate([...getCandidatePublicKeys(input1), ...getCandidatePublicKeys(input2)]); | ||
} | ||
|
||
function firstDuplicate<T>(arr: T[]): T | undefined { | ||
const seen = new Set<T>(); | ||
for (const s of arr) { | ||
if (seen.has(s)) { | ||
return s; | ||
} | ||
seen.add(s); | ||
} | ||
return undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,54 @@ | ||
import { bytesToHex, hashMessage } from "viem"; | ||
import { sign } from "webauthn-p256"; | ||
import { cache } from "./cache"; | ||
import { getMessageHash } from "./getMessageHash"; | ||
import { recoverPasskeyPublicKey } from "./recoverPasskeyPublicKey"; | ||
import { P256Credential } from "viem/account-abstraction"; | ||
|
||
export async function reusePasskey(): Promise<P256Credential> { | ||
const randomChallenge = bytesToHex(crypto.getRandomValues(new Uint8Array(256))); | ||
const messageHash = hashMessage(randomChallenge); | ||
const { signature, webauthn, raw: credential } = await sign({ hash: messageHash }); | ||
|
||
const publicKey = await (async () => { | ||
const publicKey = cache.getState().publicKeys[credential.id]; | ||
if (publicKey) return publicKey; | ||
|
||
// TODO: look up account/public key by credential ID once we store it onchain | ||
|
||
const webauthnHash = await getMessageHash(webauthn); | ||
const passkey = await recoverPasskeyPublicKey({ | ||
credentialId: credential.id, | ||
messageHash: webauthnHash, | ||
signatureHex: signature, | ||
}); | ||
if (!passkey) { | ||
throw new Error("recovery failed"); | ||
} | ||
if (passkey.credential.id !== credential.id) { | ||
throw new Error("wrong credential"); | ||
} | ||
|
||
cache.setState((state) => ({ | ||
publicKeys: { | ||
...state.publicKeys, | ||
[credential.id]: passkey.publicKey, | ||
}, | ||
import { findPublicKey } from "./findPublicKey"; | ||
import { PasskeyCredential, createBridge } from "@latticexyz/id/internal"; | ||
|
||
export async function reusePasskey(): Promise<PasskeyCredential> { | ||
const bridge = await createBridge({ message: "Signing in…" }); | ||
try { | ||
const challenge = hashMessage(bytesToHex(crypto.getRandomValues(new Uint8Array(256)))); | ||
const { credentialId, signature, metadata } = await bridge.request("sign", { challenge }); | ||
|
||
const publicKey = await (async () => { | ||
const cachedPublicKey = cache.getState().publicKeys[credentialId]; | ||
if (cachedPublicKey) return cachedPublicKey; | ||
|
||
// TODO: look up account/public key by credential ID once we store it onchain | ||
|
||
const messageHash = await getMessageHash(metadata); | ||
const challenge2 = hashMessage(signature); | ||
const signature2 = await bridge.request("sign", { credentialId, challenge: challenge2 }); | ||
if (signature2.credentialId !== credentialId) { | ||
throw new Error("wrong credential"); | ||
} | ||
|
||
const publicKey = findPublicKey([ | ||
{ messageHash, signatureHex: signature }, | ||
{ messageHash: await getMessageHash(signature2.metadata), signatureHex: signature2.signature }, | ||
]); | ||
if (!publicKey) { | ||
throw new Error("recovery failed"); | ||
} | ||
|
||
cache.setState((state) => ({ | ||
publicKeys: { | ||
...state.publicKeys, | ||
[credentialId]: publicKey, | ||
}, | ||
})); | ||
|
||
return publicKey; | ||
})(); | ||
|
||
console.log("recovered passkey", credentialId, publicKey); | ||
|
||
cache.setState(() => ({ | ||
activeCredential: credentialId, | ||
})); | ||
|
||
return passkey.publicKey; | ||
})(); | ||
|
||
console.log("recovered passkey", credential.id, publicKey); | ||
|
||
cache.setState(() => ({ | ||
activeCredential: credential.id, | ||
})); | ||
|
||
return { id: credential.id, publicKey, raw: credential }; | ||
return { credentialId, publicKey }; | ||
} finally { | ||
bridge.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": ["../../.eslintrc"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>MUD ID</title> | ||
<style> | ||
body { | ||
background: black; | ||
color: white; | ||
font-family: sans-serif; | ||
} | ||
#message { | ||
position: absolute; | ||
inset: 0; | ||
display: grid; | ||
place-items: center; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="message"></div> | ||
<script type="module" src="./src/index.ts"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
procs: | ||
client: | ||
shell: pnpm vite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
{ | ||
"name": "@latticexyz/id", | ||
"version": "0.0.0", | ||
"description": "Simple MUD accounts with passkeys", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/latticexyz/mud.git", | ||
"directory": "packages/id" | ||
}, | ||
"license": "MIT", | ||
"type": "module", | ||
"exports": { | ||
"./internal": "./dist/internal.js" | ||
}, | ||
"typesVersions": { | ||
"*": { | ||
"internal": [ | ||
"./dist/internal.d.ts" | ||
] | ||
} | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "tsup", | ||
"clean": "shx rm -rf dist", | ||
"dev": "tsup --watch", | ||
"test": "tsc --noEmit && vitest --run", | ||
"test:ci": "pnpm run test" | ||
}, | ||
"dependencies": { | ||
"@ark/util": "0.2.2", | ||
"debug": "^4.3.4", | ||
"ox": "0.1.0" | ||
}, | ||
"devDependencies": { | ||
"@types/debug": "^4.1.7", | ||
"mprocs": "^0.7.1", | ||
"tsup": "^6.7.0", | ||
"vite": "^5.4.1" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
Oops, something went wrong.