99 lines
3 KiB
JavaScript
99 lines
3 KiB
JavaScript
|
|
// Client-side PGP utilities - wraps openpgp for browser-only usage
|
||
|
|
|
||
|
|
export async function generateKeyPair(username, passphrase = '') {
|
||
|
|
if (typeof window === 'undefined') {
|
||
|
|
throw new Error('PGP operations can only be performed in the browser');
|
||
|
|
}
|
||
|
|
|
||
|
|
const { generateKey, readKey } = await import('openpgp');
|
||
|
|
|
||
|
|
const { privateKey, publicKey } = await generateKey({
|
||
|
|
type: 'rsa',
|
||
|
|
rsaBits: 2048,
|
||
|
|
userIDs: [{ name: username }],
|
||
|
|
passphrase
|
||
|
|
});
|
||
|
|
|
||
|
|
const key = await readKey({ armoredKey: publicKey });
|
||
|
|
const fingerprint = key.getFingerprint();
|
||
|
|
|
||
|
|
return {
|
||
|
|
privateKey,
|
||
|
|
publicKey,
|
||
|
|
fingerprint
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function getFingerprint(publicKey) {
|
||
|
|
if (typeof window === 'undefined') return null;
|
||
|
|
|
||
|
|
try {
|
||
|
|
const { readKey } = await import('openpgp');
|
||
|
|
const key = await readKey({ armoredKey: publicKey });
|
||
|
|
return key.getFingerprint();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Error getting fingerprint:', error);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function signMessage(message, privateKeyArmored, passphrase = '') {
|
||
|
|
if (typeof window === 'undefined') {
|
||
|
|
throw new Error('PGP operations can only be performed in the browser');
|
||
|
|
}
|
||
|
|
|
||
|
|
const { decryptKey, readPrivateKey, createMessage, sign } = await import('openpgp');
|
||
|
|
|
||
|
|
const privateKey = await decryptKey({
|
||
|
|
privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }),
|
||
|
|
passphrase
|
||
|
|
});
|
||
|
|
|
||
|
|
const unsignedMessage = await createMessage({ text: message });
|
||
|
|
const signature = await sign({
|
||
|
|
message: unsignedMessage,
|
||
|
|
signingKeys: privateKey,
|
||
|
|
detached: true
|
||
|
|
});
|
||
|
|
|
||
|
|
return signature;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function verifySignature(message, signature, publicKeyArmored) {
|
||
|
|
if (typeof window === 'undefined') return false;
|
||
|
|
|
||
|
|
try {
|
||
|
|
const { readKey, readSignature, createMessage, verify } = await import('openpgp');
|
||
|
|
|
||
|
|
const publicKey = await readKey({ armoredKey: publicKeyArmored });
|
||
|
|
const signatureObj = await readSignature({ armoredSignature: signature });
|
||
|
|
const messageObj = await createMessage({ text: message });
|
||
|
|
|
||
|
|
const verificationResult = await verify({
|
||
|
|
message: messageObj,
|
||
|
|
signature: signatureObj,
|
||
|
|
verificationKeys: publicKey
|
||
|
|
});
|
||
|
|
|
||
|
|
const { verified } = verificationResult.signatures[0];
|
||
|
|
return await verified;
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Signature verification error:', error);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function storePrivateKey(privateKey) {
|
||
|
|
if (typeof window === 'undefined') return;
|
||
|
|
localStorage.setItem('pgp_private_key', privateKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getStoredPrivateKey() {
|
||
|
|
if (typeof window === 'undefined') return null;
|
||
|
|
return localStorage.getItem('pgp_private_key');
|
||
|
|
}
|
||
|
|
|
||
|
|
export function removeStoredPrivateKey() {
|
||
|
|
if (typeof window === 'undefined') return;
|
||
|
|
localStorage.removeItem('pgp_private_key');
|
||
|
|
}
|