Skip to content

Commit

Permalink
feat: download encrypted private key
Browse files Browse the repository at this point in the history
Use mnemonic so it's a little easier to manage the non encrpyted version
  • Loading branch information
cpb8010 committed Jan 22, 2025
1 parent 13cd6d2 commit ccfb48e
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 18 deletions.
2 changes: 1 addition & 1 deletion examples/bank-demo/components/app/AddCryptoButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import NoPasskeyDialog from "~/components/app/NoPasskeyDialog.vue";
import { deployAccount } from "zksync-sso/client";
import { registerNewPasskey } from "zksync-sso/client/passkey";
import { getDeployerClient } from "../common/CrpytoDeployer";
import { getDeployerClient } from "../common/CryptoDeployer";
import type { Hex } from "viem";
const { appMeta, userDisplay, userId, contracts, deployerKey } = useAppMeta();
Expand Down
68 changes: 51 additions & 17 deletions examples/bank-demo/components/app/NoPasskeyDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,25 @@
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Enter Password
Create Crypto Account
</h3>
<p>
Please backup in a password manager or similar.
</p>
<div class="mt-2">
<input>
<p class="text-sm text-gray-500">
Please enter your password to continue.
Use a mix of letters, numbers, and symbols.
</p>
<input v-model="password" type="password" class="mt-2 w-full border border-gray-300 px-3 py-2 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" >
<input v-model="password" :type="showPassword ? 'text' : 'password'" class="mt-2 w-full border border-gray-300 px-3 py-2 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" >
<button type="button" class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-500" @click="showPassword = !showPassword">
<svg v-if="showPassword" class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
</svg>
<svg v-else class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>
</svg>
</button>
</div>
</div>
</div>
Expand All @@ -60,21 +72,22 @@
</template>

<script setup lang="ts">
import type { Hex, PrivateKeyAccount } from "viem";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import type { HDAccount, Hex } from "viem";
import { english, generateMnemonic, mnemonicToAccount } from "viem/accounts";
import { deployAccount } from "zksync-sso/client";
import { getDeployerClient } from "../common/CrpytoDeployer";
import { getDeployerClient } from "../common/CryptoDeployer";

const { appMeta, contracts, deployerKey } = useAppMeta();

const password = ref("");
const account = ref<PrivateKeyAccount>();
const privateKey = ref<Hex>();
const showPassword = ref(false);
const account = ref<HDAccount>();
const mnemonic = ref<string>();

// create account with EOA owner
onMounted(() => {
privateKey.value = generatePrivateKey();
account.value = privateKeyToAccount(privateKey.value);
mnemonic.value = generateMnemonic(english);
account.value = mnemonicToAccount(mnemonic.value);
});

async function encryptMessage(cryptoPrivateKey: string) {
Expand Down Expand Up @@ -112,37 +125,58 @@ async function decryptMessage(encryptedKey: ArrayBuffer, key: CryptoKey, iv: Uin
}

async function checkPassword() {
if (!privateKey.value) {
if (!mnemonic.value) {
console.warn("Private key not set");
return;
}
const encrypted = await encryptMessage(privateKey.value);
if (!account.value) {
console.warn("account not ready");
return;
}
const encrypted = await encryptMessage(mnemonic.value);
if (!encrypted) {
console.error("Encryption failed", privateKey.value);
console.error("Encryption failed", mnemonic.value);
return;
}
const testDecrypted = await decryptMessage(encrypted.encryptedKey, encrypted.keyEncryptionKey, encrypted.iv);
if (privateKey.value != testDecrypted) {
console.error("Decryption failed", privateKey.value, testDecrypted);
if (mnemonic.value != testDecrypted) {
console.error("Decryption failed", mnemonic.value, testDecrypted);
return;
}
console.log("Decryption success", encrypted);
// export the encrypted key

const deployerClient = await getDeployerClient(deployerKey as Hex);
const { address } = await deployAccount(deployerClient, {
credentialPublicKey: new Uint8Array(),
ownerPublicKeys: [account.value?.address],
ownerPublicKeys: [account.value.address],
contracts,
});

appMeta.value = {
...appMeta.value,
cryptoAccountAddress: address,
};
downloadArrayBuffer("encrypted-private-key.txt", encrypted.encryptedKey);
navigateTo("/crypto-account");
confirm();
}

function downloadArrayBuffer(filename: string, buffer: ArrayBuffer, mimeType: string = "application/octet-stream") {
const blob = new Blob([buffer], { type: mimeType });
const url = window.URL.createObjectURL(blob);

const a = document.createElement("a");
a.href = url;
a.download = filename;

a.style.display = "none";
document.body.appendChild(a);

a.click();

window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}

defineEmits(["confirm", "cancel"]);
</script>

0 comments on commit ccfb48e

Please sign in to comment.