Skip to content

Instantly share code, notes, and snippets.

@jeasonstudio
Created June 24, 2024 09:54
Show Gist options
  • Save jeasonstudio/617becf209bcbb5afaab34decae3e4be to your computer and use it in GitHub Desktop.
Save jeasonstudio/617becf209bcbb5afaab34decae3e4be to your computer and use it in GitHub Desktop.
Convert MetaMask snap(arsnap) into JWK file, and you can import to ArConnect Wallet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Arweave Keyfile Converter</title>
</head>
<body>
<main>
<input
type="text"
id="mnemonic"
style="width: 800px"
placeholder="Please input your metamask mnemonic"
/>
<button onclick="downloadfile()">download arweave JWK</button>
</main>
<script type="module">
import bip39 from 'https://esm.sh/bip39?bundle-deps';
import FileSaver from 'https://esm.sh/file-saver?bundle-deps';
import { SLIP10Node } from 'https://esm.sh/@metamask/key-tree?bundle-deps';
import init, {
keygen,
} from 'https://esm.sh/@pianity/arsnap-keygen?bundle-deps';
function hexToUint8Array(hex) {
const chunks = [];
for (let i = 0; i < hex.length; i += 2) {
chunks.push(hex.slice(i, i + 2));
}
return new Uint8Array(chunks.map((chunk) => parseInt(chunk, 16)));
}
function base64ToUint8Array(base64String) {
const binaryString = window.atob(base64String);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
/**
* Convert the pem string to a binary representation
*/
function pemToBin(pem) {
const encoded = pem
.split('\n')
.reduce(
(lines, line) => (line.indexOf('-----') < 0 ? lines + line : lines),
''
);
return base64ToUint8Array(encoded);
}
/**
* Convert the pem key to the official arweave key format
*/
async function pemToJwk(pem) {
const cryptoKey = await window.crypto.subtle.importKey(
'pkcs8',
pemToBin(pem),
{
name: 'RSA-PSS',
hash: { name: 'SHA-256' },
},
true,
['sign']
);
const jwk = await crypto.subtle.exportKey('jwk', cryptoKey);
return {
kty: jwk.kty,
n: jwk.n,
e: jwk.e,
d: jwk.d,
p: jwk.p,
q: jwk.q,
dp: jwk.dp,
dq: jwk.dq,
qi: jwk.qi,
};
}
async function main(mnemonic) {
await init();
const ed25519Node = await SLIP10Node.fromDerivationPath({
curve: 'ed25519',
derivationPath: [
`bip39:${mnemonic}`,
`slip10:44'`,
`slip10:472'`,
`slip10:0'`,
],
});
const privateKey = ed25519Node.privateKey.slice(2);
const secret = hexToUint8Array(privateKey);
const pem = await keygen(secret);
const jwk = await pemToJwk(pem);
console.log(jwk);
return jwk;
}
window.downloadfile = async () => {
try {
const mnemonic = document.getElementById('mnemonic').value;
const result = await main(mnemonic);
const blob = new Blob([JSON.stringify(result, null, 2)], {
type: 'text/plain;charset=utf-8',
});
await FileSaver.saveAs(blob, 'keyfile.json');
} catch (error) {
alert('Error:' + JSON.stringify(error));
}
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment