UNPKG

isomorphic-git

Version:

Node library for interacting with git repositories, circa 2017

232 lines (213 loc) 7.52 kB
'use strict' import * as openpgp from 'openpgp' openpgp.config.aead_protect = false openpgp.config.prefer_hash_algorithm = 2 // SHA1 var hkp = new openpgp.HKP('https://pgp.mit.edu') var hkp2 = new openpgp.HKP('http://keys.gnupg.net') var keyring = new openpgp.Keyring() // Print a key function printKey () { let keyid = printKeyid(this.primaryKey.getKeyId()) let userid = printUser(this.getPrimaryUser().user) return keyid + ' ' + userid } // openpgp.key.toString = printKey function printKeyid (keyid) { return keyid.toHex() } // openpgp.Keyid.prototype.toString = openpgp.Keyid.prototype.toHex function printUser (user) { return user.userId.userid } function getFullSignature (signature) { let key = keyring.getKeysForId(printKeyid(signature.keyid))[0] let user = key.getPrimaryUser().user signature.user = user signature.email = printUser(user).match(/<(.*)>/)[1] return signature } // Find the public key(s) for `email` on the local browser keyring. function locallookup (email) { let keys = keyring.publicKeys.getForAddress(email) if (keys.length === 0) { return null } // keys[0].toString = printKey return keys[0] } export default class PGP { // Find the public key(s) for `email` on a server (note - how can you trust the PGP server?) add them to the browser keyring. static async lookup (email) { // Has no option to do an exact email search for some reason. // william@example.net instead returns results for "william example net" // so we must work around this stupidity try { let keys = await hkp.lookup({ query: email }) if (typeof keys === 'undefined') return null keys = openpgp.key.readArmored(keys).keys // Find keys with an exact match for the email address given let results = [] for (let k of keys) { for (let u of k.users) { if (u.userId.userid.includes(`<${email}>`)) { results.push(k.primaryKey.keyid.toHex()) keyring.publicKeys.push(k) } } } results = results.length > 0 ? results : null return results } catch (err) { console.log('err =', err) return null } } // Generate a key pair in the browser and add it to the browser keyring. static async keygen (name, email) { const { privateKeyArmored, publicKeyArmored } = await openpgp.generateKey({ userIds: [ { name: name, email: email } ] }) keyring.publicKeys.importKey(publicKeyArmored) keyring.privateKeys.importKey(privateKeyArmored) // let key = openpgp.key.readArmored(privateKeyArmored).keys[0] // key.toString = printKey // We need to manually call this to save the keypair to localstorage keyring.store() } // Returns a human-readable list of all the public keys in the browser's keyring. static async list () { let print = [] for (let key of keyring.publicKeys.keys) { print.push(printKey.apply(key)) } return print } // Encrypt `msg` using the public key for `email` static async encrypt (email, msg) { // Load Alice's keypair from localstorage // let privateKey = keyring.privateKeys.keys[0] let publicKey = locallookup(email) const encrypted = await openpgp.encrypt({ publicKeys: publicKey, // NOTE: it's plural... data: msg }) return encrypted.data } // Decrypt `msg` using the private key for `email` // msg should be the full encrypted message including the -----BEGIN PGP MESSAGE----- and -----END PGP MESSAGE----- lines. static async decrypt (email, msg) { let privateKey = PGP.lookupPrivateKey(email) const decrypted = openpgp.decrypt({ privateKey: privateKey, message: openpgp.message.readArmored(msg) }) return decrypted.data } // Sign `msg` using the private key for `email' static async sign (email, msg) { // Load keypair from localstorage let privateKey = PGP.lookupPrivateKey(email) if (privateKey) { const signed = await openpgp.sign({ privateKeys: privateKey, data: msg }) return signed.data } else { throw new Error( 'No PrivateKey in the OpenPGP keyring for the email address: ' + email ) } } // Verify a signed `msg` using the public key for `email` static async verify (email, msg) { let publicKeys = locallookup(email) const verified = await openpgp.verify({ publicKeys: publicKeys, message: openpgp.cleartext.readArmored(msg) }) let signature = verified.signatures.map(getFullSignature) signature = signature.filter(x => x.email === email) if (signature.length !== 1) { return false } else { return signature[0].valid } } // Sign `plaintext` using the private key for `email' static async createBinaryDetachedSignature (email, plaintext) { // Load keypair from localstorage let privateKey = PGP.lookupPrivateKey(email) if (privateKey) { // Is the only difference between cleartext signatures and detached binary the text normalization? // If so, I could probably add that functionality to openpgpjs - I'd just need a little guidance // on how to encode the PacketType and add the functionality to export to armor.js let bytes = openpgp.util.str2Uint8Array(plaintext) let message = openpgp.message.fromBinary(bytes) let signedMessage = message.sign([privateKey]) let signature = signedMessage.packets.filterByTag( openpgp.enums.packet.signature ) let armoredMessage = openpgp.armor.encode( openpgp.enums.armor.message, signature.write() ) // Github won't recognize the signature unless we rename the headers (Tested 2017-01-04) armoredMessage = armoredMessage.replace( '-----BEGIN PGP MESSAGE-----\r\n', '-----BEGIN PGP SIGNATURE-----\r\n' ) armoredMessage = armoredMessage.replace( '-----END PGP MESSAGE-----\r\n', '-----END PGP SIGNATURE-----\r\n' ) return armoredMessage } else { throw new Error( 'No PrivateKey in the OpenPGP keyring for the email address: ' + email ) } } // Verify `message` with detached `signature` using the public key for `email` static async verifyDetachedSignature (email, message, signature) { locallookup(email) console.log('email, message, signature =', email, message, signature) let msg = openpgp.message.readSignedContent(message, signature) console.log('msg =', msg) var result = msg.verify(keyring.publicKeys.keys) console.log('result[0] =', result[0]) console.log('keyid =', printKeyid(result[0].keyid)) return result[0].valid } // Returns true if the keyring has a private key for `email`. static hasPrivateKey (email) { let keys = keyring.privateKeys.getForAddress(email) return keys.length > 0 } // Export public signing key static exportPublicKey (email) { return PGP.lookupPrivateKey(email) .toPublic() .armor() .trim() .replace(/\r/g, '') } // Upload the public signing key to the MIT key server static async publish (email) { let key = PGP.exportPublicKey(email) return Promise.all([hkp.upload(key), hkp2.upload(key)]) } static lookupPrivateKey (email) { let keys = keyring.privateKeys.getForAddress(email) if (keys.length === 0) { return null } // keys[0].toString = printKey return keys[0] } }