mirror of
https://github.com/onsonr/sonr.git
synced 2025-03-10 13:07:09 +00:00
feat: add WebAuthn credential management functionality
This commit is contained in:
parent
a785d3a01f
commit
ad2902b0bb
1
.gitignore
vendored
1
.gitignore
vendored
@ -77,6 +77,7 @@ deploy/**/data
|
|||||||
x/.DS_Store
|
x/.DS_Store
|
||||||
.aider*
|
.aider*
|
||||||
buildenv*
|
buildenv*
|
||||||
|
nebula/node_modules
|
||||||
|
|
||||||
!devbox.lock
|
!devbox.lock
|
||||||
!motr/build
|
!motr/build
|
||||||
|
BIN
nebula/bun.lockb
Executable file
BIN
nebula/bun.lockb
Executable file
Binary file not shown.
@ -1,2 +1,255 @@
|
|||||||
// src/ts/main.ts
|
import Dexie from "dexie";
|
||||||
console.log("Hello from TypeScript!");
|
import {
|
||||||
|
PublicKeyCredentialRequestOptions,
|
||||||
|
PublicKeyCredentialCreationOptions,
|
||||||
|
} from "@simplewebauthn/types";
|
||||||
|
|
||||||
|
export class Motr {
|
||||||
|
constructor(config) {
|
||||||
|
this.config = config;
|
||||||
|
this.vault = null;
|
||||||
|
this.initializeVault();
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeVault() {
|
||||||
|
const { schema } = this.config;
|
||||||
|
this.vault = new Dexie("Vault");
|
||||||
|
this.vault.version(schema.version).stores(schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account methods
|
||||||
|
async insertAccount(accountData) {
|
||||||
|
return this.vault.account.add(accountData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAccount(id) {
|
||||||
|
return this.vault.account.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAccount(id, accountData) {
|
||||||
|
return this.vault.account.update(id, accountData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAccount(id) {
|
||||||
|
return this.vault.account.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset methods
|
||||||
|
async insertAsset(assetData) {
|
||||||
|
return this.vault.asset.add(assetData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAsset(id) {
|
||||||
|
return this.vault.asset.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAsset(id, assetData) {
|
||||||
|
return this.vault.asset.update(id, assetData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAsset(id) {
|
||||||
|
return this.vault.asset.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain methods
|
||||||
|
async insertChain(chainData) {
|
||||||
|
return this.vault.chain.add(chainData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getChain(id) {
|
||||||
|
return this.vault.chain.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateChain(id, chainData) {
|
||||||
|
return this.vault.chain.update(id, chainData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteChain(id) {
|
||||||
|
return this.vault.chain.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credential methods
|
||||||
|
async insertCredential(credentialData) {
|
||||||
|
const publicKey = await this.createPublicKeyCredential(credentialData);
|
||||||
|
credentialData.credentialId = publicKey.id;
|
||||||
|
credentialData.publicKey = publicKey.publicKey;
|
||||||
|
return this.vault.credential.add(credentialData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCredential(id) {
|
||||||
|
return this.vault.credential.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateCredential(id, credentialData) {
|
||||||
|
return this.vault.credential.update(id, credentialData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteCredential(id) {
|
||||||
|
return this.vault.credential.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWK methods
|
||||||
|
async insertJwk(jwkData) {
|
||||||
|
return this.vault.jwk.add(jwkData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getJwk(id) {
|
||||||
|
return this.vault.jwk.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateJwk(id, jwkData) {
|
||||||
|
return this.vault.jwk.update(id, jwkData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteJwk(id) {
|
||||||
|
return this.vault.jwk.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grant methods
|
||||||
|
async insertGrant(grantData) {
|
||||||
|
return this.vault.grant.add(grantData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGrant(id) {
|
||||||
|
return this.vault.grant.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateGrant(id, grantData) {
|
||||||
|
return this.vault.grant.update(id, grantData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteGrant(id) {
|
||||||
|
return this.vault.grant.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyshare methods
|
||||||
|
async insertKeyshare(keyshareData) {
|
||||||
|
return this.vault.keyshare.add(keyshareData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getKeyshare(id) {
|
||||||
|
return this.vault.keyshare.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateKeyshare(id, keyshareData) {
|
||||||
|
return this.vault.keyshare.update(id, keyshareData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteKeyshare(id) {
|
||||||
|
return this.vault.keyshare.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey methods
|
||||||
|
async insertPublicKey(publicKeyData) {
|
||||||
|
return this.vault.publicKey.add(publicKeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPublicKey(id) {
|
||||||
|
return this.vault.publicKey.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePublicKey(id, publicKeyData) {
|
||||||
|
return this.vault.publicKey.update(id, publicKeyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deletePublicKey(id) {
|
||||||
|
return this.vault.publicKey.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile methods
|
||||||
|
async insertProfile(profileData) {
|
||||||
|
return this.vault.profile.add(profileData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfile(id) {
|
||||||
|
return this.vault.profile.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateProfile(id, profileData) {
|
||||||
|
return this.vault.profile.update(id, profileData);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteProfile(id) {
|
||||||
|
return this.vault.profile.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAuthn methods
|
||||||
|
async createPublicKeyCredential(): Promise<PublicKeyCredentialRequestOptions> {
|
||||||
|
const publicKeyCredentialCreationOptions = {
|
||||||
|
challenge: new Uint8Array(32),
|
||||||
|
rp: {
|
||||||
|
name: this.config.motr.origin,
|
||||||
|
id: new URL(this.config.motr.origin).hostname,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: new TextEncoder().encode(options.subject),
|
||||||
|
name: options.subject,
|
||||||
|
displayName: options.label,
|
||||||
|
},
|
||||||
|
pubKeyCredParams: [
|
||||||
|
{ alg: -7, type: "public-key" },
|
||||||
|
{ alg: -257, type: "public-key" },
|
||||||
|
],
|
||||||
|
authenticatorSelection: {
|
||||||
|
authenticatorAttachment: "platform",
|
||||||
|
userVerification: "required",
|
||||||
|
},
|
||||||
|
timeout: 60000,
|
||||||
|
attestation: "direct",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credential = await navigator.credentials.create({
|
||||||
|
publicKey: publicKeyCredentialCreationOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
const publicKeyJwk = await crypto.subtle.exportKey(
|
||||||
|
"jwk",
|
||||||
|
credential.response.getPublicKey(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: credential.id,
|
||||||
|
publicKey: publicKeyJwk,
|
||||||
|
type: credential.type,
|
||||||
|
transports: credential.response.getTransports(),
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating credential:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPublicKeyCredential(options) {
|
||||||
|
const publicKeyCredentialRequestOptions = {
|
||||||
|
challenge: new Uint8Array(32),
|
||||||
|
rpId: new URL(this.config.motr.origin).hostname,
|
||||||
|
allowCredentials: options.allowCredentials || [],
|
||||||
|
userVerification: "required",
|
||||||
|
timeout: 60000,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const assertion = await navigator.credentials.get({
|
||||||
|
publicKey: publicKeyCredentialRequestOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: assertion.id,
|
||||||
|
type: assertion.type,
|
||||||
|
rawId: new Uint8Array(assertion.rawId),
|
||||||
|
response: {
|
||||||
|
authenticatorData: new Uint8Array(
|
||||||
|
assertion.response.authenticatorData,
|
||||||
|
),
|
||||||
|
clientDataJSON: new Uint8Array(assertion.response.clientDataJSON),
|
||||||
|
signature: new Uint8Array(assertion.response.signature),
|
||||||
|
userHandle: new Uint8Array(assertion.response.userHandle),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error getting credential:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user