sonr/pkg/vault/motr.mjs
Prad Nukala a4dbb41202
feature/dwn database state (#18)
* refactor: move database, navigator scripts to state package

* feat: add Schema config for dwn

* test: add unit tests for InitializeDatabase

* feat: use templated index.html for the DWN frontend

* feat: introduce templ generation for templ

* chore(deps): update devbox.json to use latest packages

* chore: update devbox to use bun

* feat: introduce dwn config generation

* feat: add motr.mjs for vault management

* refactor: move front end from  to  (alert)

* feat: implement devbox integration and devbox-based process management

* feat: embed motr.mjs script for offline demo

* refactor: embed motr.mjs data in embed.go

* chore: update workflows to use actions/checkout@v4

* refactor: move process-compose.yaml to deploy directory

* refactor: remove unnecessary JSON conversion
2024-09-21 21:42:51 -04:00

254 lines
5.8 KiB
JavaScript

// motr.mjs
import Dexie from "dexie";
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(options) {
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;
}
}
}