Skip to content

awesome-algorand/prf-wallet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

2 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Overview

This is a basice Vite application based off the PRF Explainer that shows the basics of creating a seed from a discoverable Passkey/PublicKeyCredential

Get started

Clone the repository

git clone [email protected]:awesome-algorand/prf-wallet.git

Install Dependencies

npm install

Run the Demo

npm run dev

Full Example

import './style.css'
import typescriptLogo from './typescript.svg'
import viteLogo from '/vite.svg'
import algosdk from 'algosdk'
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="${viteLogo}" class="logo" alt="Vite logo" />
    </a>
    <a href="https://www.typescriptlang.org/" target="_blank">
      <img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
    </a>
    <h1>Vite + TypeScript</h1>
    <div class="card">
        <button id="create" type="button">create</button>
        <button id="get" type="button">get</button>
    </div>
    <p class="read-the-docs">
      Click on the Vite and TypeScript logos to learn more
    </p>
    
  </div>
`

function setupCreate(button: HTMLButtonElement){
    button.addEventListener('click', async () => {
        const credential = await navigator.credentials.create({
            publicKey: {
                challenge: new Uint8Array(32),
                pubKeyCredParams: [
                    { type: 'public-key', alg: -7 },
                    { type: 'public-key', alg: -8 },
                    { type: 'public-key', alg: -257 },
                ],
                rp: {
                    id: 'localhost',
                    name: 'Example',
                },
                extensions: {
                    prf: {},
                },
                authenticatorSelection: {
                    authenticatorAttachment: "cross-platform",
                    userVerification: 'preferred',
                    requireResidentKey: true,
                    residentKey: 'required',
                },
                user: {
                    id: new Uint8Array(32),
                    name: '',
                    displayName: '',
                }
            }
        })
        if(!credential){
            return
        }
        localStorage['credential'] = JSON.stringify([...new Uint8Array(credential.rawId)])
        const extensions: AuthenticationExtensionsClientOutputs & {prf?: {enabled?: boolean}} = (credential as PublicKeyCredential).getClientExtensionResults();
        if(extensions?.prf?.enabled){
            alert('prf enabled')
        }
    })
}
function setupGet(button: HTMLButtonElement){
    button.addEventListener('click', async () => {
        let rawId = localStorage['credential']
        if (!rawId) {
            return
        } else {
            rawId = new Uint8Array(JSON.parse(rawId))
        }
        const credential = await navigator.credentials.get({
            publicKey: {
                challenge: new Uint8Array(32),
                allowCredentials: [
                    {
                        type: 'public-key',
                        id: rawId,
                    },
                ],
                extensions: {
                    prf: {eval: {first: new TextEncoder().encode("Foo encryption key")}}
                },
                userVerification: 'preferred',
            }
        })
        if(!credential){
            return
        }
        const results = (credential as PublicKeyCredential).getClientExtensionResults();
        globalThis.mneomnic = algosdk.secretKeyToMnemonic(new Uint8Array(results.prf.results.first))
        globalThis.account = algosdk.mnemonicToSecretKey(globalThis.mneomnic)
        alert(`mneomnic: \n ${globalThis.mneomnic} \n account: ${globalThis.account.addr}`)
    })
}
setupCreate(document.querySelector<HTMLButtonElement>('#create')!)
setupGet(document.querySelector<HTMLButtonElement>('#get')!)