mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
124 lines
4.0 KiB
Templ
124 lines
4.0 KiB
Templ
package forms
|
|
|
|
import "github.com/onsonr/sonr/pkg/blocks/cards"
|
|
|
|
type RegisterPasskeyData struct {
|
|
Address string
|
|
Handle string
|
|
Name string
|
|
Challenge string
|
|
CreationBlock string
|
|
}
|
|
|
|
templ RegisterPasskey(action, method string, data RegisterPasskeyData) {
|
|
<form action={ templ.SafeURL(action) } method={ method } onsubmit="return validateCredential()">
|
|
<input type="hidden" name="credential" id="credential-data" required/>
|
|
<sl-card class="card-form gap-4 max-w-lg">
|
|
<div slot="header">
|
|
<div class="w-full py-1">
|
|
@cards.SonrProfile(data.Address, data.Name, data.Handle, data.CreationBlock)
|
|
</div>
|
|
</div>
|
|
@passkeyDropzone(data.Address, data.Handle, data.Challenge)
|
|
<div slot="footer">
|
|
<sl-button type="submit" pill style="width: 100%;" variant="primary">
|
|
<sl-icon slot="prefix" name="shield-fill-check"></sl-icon>
|
|
Register Vault
|
|
<sl-icon slot="suffix" name="arrow-outbound" library="sonr"></sl-icon>
|
|
</sl-button>
|
|
</div>
|
|
<script>
|
|
function validateCredential() {
|
|
const credentialInput = document.getElementById('credential-data');
|
|
if (!credentialInput.value) {
|
|
alert('Please create a passkey before submitting');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
</script>
|
|
<style>
|
|
.card-form [slot='footer'] {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
</style>
|
|
</sl-card>
|
|
</form>
|
|
}
|
|
|
|
templ passkeyDropzone(addr string, userHandle string, challenge string) {
|
|
<div class="w-full flex flex-col items-center justify-center gap-4">
|
|
<div id="credential-details" class="w-full p-4 border border-neutral-200 rounded-md hidden">
|
|
<div class="flex items-center gap-3">
|
|
<sl-icon name="fingerprint" library="sonr" style="font-size: 24px;" class="text-primary-500"></sl-icon>
|
|
<div class="flex flex-col">
|
|
<span class="text-sm font-medium" id="credential-name">Platform Authenticator</span>
|
|
<span class="text-xs text-neutral-500" id="credential-id"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="w-full p-4 border-dashed border-2 border-neutral-500 cursor-pointer rounded-md hover:border-neutral-400 transition-colors" onclick={ createPasskey(addr, userHandle, challenge) }>
|
|
<div class="flex flex-col items-center gap-2">
|
|
<sl-icon slot="prefix" name="passkey" library="sonr" style="font-size: 24px;" class="text-neutral-500"></sl-icon>
|
|
<span class="text-neutral-500">Link a passkey to your vault</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
script createPasskey(userId string, userHandle string, challenge string) {
|
|
const publicKey = {
|
|
challenge: Uint8Array.from(challenge, (c) => c.charCodeAt(0)),
|
|
rp: {
|
|
name: "Sonr.ID",
|
|
},
|
|
user: {
|
|
// Assuming that userId is ASCII-only
|
|
id: Uint8Array.from(userId, (c) => c.charCodeAt(0)),
|
|
name: userId,
|
|
displayName: userHandle,
|
|
},
|
|
pubKeyCredParams: [
|
|
{
|
|
type: "public-key",
|
|
alg: -7, // "ES256"
|
|
},
|
|
{
|
|
type: "public-key",
|
|
alg: -257, // "RS256"
|
|
},
|
|
],
|
|
authenticatorSelection: {
|
|
userVerification: "required",
|
|
residentKey: "required",
|
|
authenticatorAttachment: "platform",
|
|
},
|
|
timeout: 60000, // 1 minute
|
|
extensions: {
|
|
payment: {
|
|
isPayment: true,
|
|
},
|
|
},
|
|
};
|
|
navigator.credentials
|
|
.create({ publicKey })
|
|
.then((newCredentialInfo) => {
|
|
// Convert credential to base64 string
|
|
const credentialJSON = JSON.stringify({
|
|
CredentialID: Array.from(new Uint8Array(newCredentialInfo.rawId)),
|
|
Type: newCredentialInfo.type,
|
|
Transport: newCredentialInfo.response.getTransports ? newCredentialInfo.response.getTransports() : []
|
|
});
|
|
document.getElementById('credential-data').value = btoa(credentialJSON);
|
|
// Show credential details
|
|
document.getElementById('credential-details').classList.remove('hidden');
|
|
document.getElementById('credential-id').textContent = newCredentialInfo.id;
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
// No acceptable authenticator or user refused consent. Handle appropriately.
|
|
});
|
|
}
|