@consento/crypto
Advanced tools
Comparing version 0.0.12 to 0.1.0
@@ -12,4 +12,5 @@ "use strict"; | ||
const buffer_1 = require("../util/buffer"); | ||
const types_1 = require("./types"); | ||
/* eslint @typescript-eslint/camelcase: "off" */ | ||
const { crypto_kdf_derive_from_key, randombytes_buf, crypto_scalarmult_base, crypto_scalarmult, crypto_scalarmult_ed25519_BYTES, crypto_kdf_BYTES_MAX, crypto_kdf_CONTEXTBYTES, crypto_box_SEALBYTES, crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES, crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES, crypto_sign_BYTES, crypto_sign_ed25519_sk_to_curve25519, crypto_sign_ed25519_pk_to_curve25519, crypto_sign_seed_keypair, crypto_sign_detached, crypto_sign_verify_detached, crypto_sign_ed25519_sk_to_pk, crypto_box_seal, crypto_box_seal_open, crypto_sign_keypair, crypto_secretbox_easy, crypto_secretbox_open_easy, crypto_secretbox_NONCEBYTES, crypto_secretbox_MACBYTES, crypto_secretbox_KEYBYTES, sodium_malloc } = sodium.default; | ||
const { randombytes_buf, crypto_scalarmult_base, crypto_scalarmult, crypto_scalarmult_BYTES, crypto_kdf_CONTEXTBYTES, crypto_box_seal, crypto_box_seal_open, crypto_box_keypair, crypto_box_SEALBYTES, crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES, crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES, crypto_sign_BYTES, crypto_sign_detached, crypto_sign_verify_detached, crypto_sign_keypair, crypto_secretbox_easy, crypto_secretbox_open_easy, crypto_secretbox_NONCEBYTES, crypto_secretbox_MACBYTES, crypto_secretbox_KEYBYTES, sodium_malloc } = sodium.default; | ||
function randomBuffer(size) { | ||
@@ -31,25 +32,2 @@ const buffer = sodium_malloc(size); | ||
} | ||
function boxSecretFromSignSecret(signSecretKey) { | ||
const encryptSecretKey = sodium_malloc(crypto_box_SECRETKEYBYTES); | ||
crypto_sign_ed25519_sk_to_curve25519(encryptSecretKey, signSecretKey); | ||
return encryptSecretKey; | ||
} | ||
function boxPublicFromSignPublic(signPublicKey) { | ||
const encryptPublicKey = sodium_malloc(crypto_box_PUBLICKEYBYTES); | ||
crypto_sign_ed25519_pk_to_curve25519(encryptPublicKey, signPublicKey); | ||
return encryptPublicKey; | ||
} | ||
function decrypt(encryptPublicKey, encryptSecretKey, messageEncrypted) { | ||
const messageDecrypted = sodium_malloc(messageEncrypted.length - crypto_box_SEALBYTES); | ||
const successful = crypto_box_seal_open(messageDecrypted, messageEncrypted, encryptPublicKey, encryptSecretKey); | ||
if (!successful) { | ||
return null; | ||
} | ||
return messageDecrypted; | ||
} | ||
function encrypt(encryptPublicKey, message) { | ||
const messageEncrypted = sodium_malloc(message.length + crypto_box_SEALBYTES); | ||
crypto_box_seal(messageEncrypted, message, encryptPublicKey); | ||
return messageEncrypted; | ||
} | ||
function sign(signSecretKey, body) { | ||
@@ -65,7 +43,2 @@ const signature = sodium_malloc(crypto_sign_BYTES); | ||
/* eslint @typescript-eslint/require-await: "off" */ | ||
async deriveKdfKey(key) { | ||
const derivedKey = sodium_malloc(crypto_kdf_BYTES_MAX); | ||
crypto_kdf_derive_from_key(derivedKey, 1, deriveContext, key); | ||
return derivedKey; | ||
}, | ||
async sign(signSecretKey, body) { | ||
@@ -77,16 +50,2 @@ return sign(signSecretKey, body); | ||
}, | ||
async deriveAnnonymousKeys(readKey) { | ||
const sign = { | ||
annonymous: true, | ||
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
write: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
}; | ||
crypto_sign_seed_keypair(sign.read, sign.write, readKey); | ||
return sign; | ||
}, | ||
async deriveReadKey(writeKey) { | ||
const readKey = sodium_malloc(crypto_sign_PUBLICKEYBYTES); | ||
crypto_sign_ed25519_sk_to_pk(readKey, writeKey); | ||
return readKey; | ||
}, | ||
async createSecretKey() { | ||
@@ -111,34 +70,25 @@ return randomBuffer(crypto_secretbox_KEYBYTES); | ||
}, | ||
async decryptMessage(signReadKey, signWriteKey, readKey, message) { | ||
if (!verify(signReadKey, message.signature, message.body)) { | ||
async decryptMessage(verifyKey, writeKey, readKey, message) { | ||
if (!verify(verifyKey, message.signature, message.body)) { | ||
return { | ||
error: 'invalid-channel' | ||
error: types_1.EDecryptionError.invalidSignature | ||
}; | ||
} | ||
const encryptPublicKey = boxPublicFromSignPublic(signReadKey); | ||
const encryptSecretKey = boxSecretFromSignSecret(signWriteKey); | ||
const decrypted = decrypt(encryptPublicKey, encryptSecretKey, message.body); | ||
if (decrypted === null) { | ||
const messageDecrypted = sodium_malloc(message.body.length - crypto_box_SEALBYTES); | ||
const successful = crypto_box_seal_open(messageDecrypted, message.body, writeKey, readKey); | ||
if (!successful) { | ||
return { | ||
error: 'invalid-encryption' | ||
error: types_1.EDecryptionError.invalidEncryption | ||
}; | ||
} | ||
const [signature, body] = split(decrypted, crypto_sign_BYTES); | ||
if (!verify(readKey, signature, body)) { | ||
return { | ||
error: 'invalid-owner' | ||
}; | ||
} | ||
return { | ||
body: buffer_1.bufferToAny(body) | ||
body: buffer_1.bufferToAny(messageDecrypted) | ||
}; | ||
}, | ||
async encryptMessage(annonymousReadKey, annonymousWriteKey, writeKey, message) { | ||
async encryptMessage(signKey, writeKey, message) { | ||
const msgBuffer = buffer_1.anyToBuffer(message); | ||
const signedStandardized = sign(writeKey, msgBuffer); | ||
const secret = buffer_1.Buffer.concat([signedStandardized, msgBuffer]); | ||
const encryptPublicKey = boxPublicFromSignPublic(annonymousReadKey); | ||
const body = encrypt(encryptPublicKey, secret); | ||
const body = sodium_malloc(msgBuffer.length + crypto_box_SEALBYTES); | ||
crypto_box_seal(body, msgBuffer, writeKey); | ||
return { | ||
signature: sign(annonymousWriteKey, body), | ||
signature: sign(signKey, body), | ||
body | ||
@@ -148,21 +98,29 @@ }; | ||
async initHandshake() { | ||
const pri = randomBuffer(crypto_scalarmult_ed25519_BYTES); | ||
const pub = sodium_malloc(crypto_scalarmult_ed25519_BYTES); | ||
crypto_scalarmult_base(pub, pri); | ||
return { write: pri, read: pub }; | ||
const privateKey = randomBuffer(crypto_scalarmult_BYTES); | ||
const publicKey = sodium_malloc(crypto_scalarmult_BYTES); | ||
crypto_scalarmult_base(publicKey, privateKey); | ||
return { privateKey, publicKey }; | ||
}, | ||
async computeSecret(pri, remotePublic) { | ||
const secret = sodium_malloc(crypto_scalarmult_ed25519_BYTES); | ||
crypto_scalarmult(secret, pri, remotePublic); | ||
async computeSecret(privateKey, remotePublic) { | ||
const secret = sodium_malloc(crypto_scalarmult_BYTES); | ||
crypto_scalarmult(secret, privateKey, remotePublic); | ||
return secret; | ||
}, | ||
async createKeys() { | ||
async createEncryptionKeys() { | ||
const keys = { | ||
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
write: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
publicKey: sodium_malloc(crypto_box_PUBLICKEYBYTES), | ||
privateKey: sodium_malloc(crypto_box_SECRETKEYBYTES) | ||
}; | ||
crypto_sign_keypair(keys.read, keys.write); | ||
crypto_box_keypair(keys.publicKey, keys.privateKey); | ||
return keys; | ||
}, | ||
async createSignKeys() { | ||
const keys = { | ||
publicKey: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
privateKey: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
}; | ||
crypto_sign_keypair(keys.publicKey, keys.privateKey); | ||
return keys; | ||
} | ||
}; | ||
//# sourceMappingURL=friends.js.map |
@@ -6,4 +6,6 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable @typescript-eslint/camelcase */ | ||
const libsodium_wrappers_sumo_1 = __importDefault(require("@consento/libsodium-wrappers-sumo")); | ||
const buffer_1 = require("../util/buffer"); | ||
const types_1 = require("./types"); | ||
const _global = global; | ||
@@ -20,23 +22,2 @@ if (_global.document === null || _global.document === undefined) { | ||
} | ||
const deriveContext = 'conotify'; | ||
/* eslint @typescript-eslint/camelcase: "off" */ | ||
async function boxSecretFromSignSecret(signSecretKey) { | ||
const { crypto_sign_ed25519_sk_to_curve25519 } = await libsodium; | ||
return crypto_sign_ed25519_sk_to_curve25519(assertUint8(signSecretKey)); | ||
} | ||
async function boxPublicFromSignPublic(signPublicKey) { | ||
const { crypto_sign_ed25519_pk_to_curve25519 } = await libsodium; | ||
return crypto_sign_ed25519_pk_to_curve25519(assertUint8(signPublicKey)); | ||
} | ||
async function decrypt(signReadKey, signWriteKey, messageEncrypted) { | ||
const encryptPublicKey = await boxPublicFromSignPublic(signReadKey); | ||
const encryptSecretKey = await boxSecretFromSignSecret(signWriteKey); | ||
const { crypto_box_seal_open } = await libsodium; | ||
return crypto_box_seal_open(assertUint8(messageEncrypted), encryptPublicKey, encryptSecretKey); | ||
} | ||
async function encrypt(signPublicKey, message) { | ||
const { crypto_box_seal: seal } = await libsodium; | ||
const encryptPublicKey = await boxPublicFromSignPublic(assertUint8(signPublicKey)); | ||
return seal(assertUint8(message), encryptPublicKey); | ||
} | ||
function assertUint8(input) { | ||
@@ -57,44 +38,20 @@ if (!('Buffer' in global) || input instanceof buffer_1.Buffer) { | ||
exports.sodium = { | ||
async deriveKdfKey(key) { | ||
const { crypto_kdf_derive_from_key, crypto_kdf_BYTES_MAX } = await libsodium; | ||
return crypto_kdf_derive_from_key(crypto_kdf_BYTES_MAX, 1, deriveContext, assertUint8(key)); | ||
}, | ||
sign, | ||
verify, | ||
async deriveAnnonymousKeys(readKey) { | ||
const { crypto_sign_seed_keypair } = await libsodium; | ||
const pair = crypto_sign_seed_keypair(assertUint8(readKey)); | ||
return { | ||
annonymous: true, | ||
read: pair.publicKey, | ||
write: pair.privateKey | ||
}; | ||
}, | ||
async deriveReadKey(writeKey) { | ||
const { crypto_sign_ed25519_sk_to_pk } = await libsodium; | ||
return crypto_sign_ed25519_sk_to_pk(assertUint8(writeKey)); | ||
}, | ||
async decryptMessage(signReadKey, signWriteKey, readKey, message) { | ||
signReadKey = assertUint8(signReadKey); | ||
async decryptMessage(verifyKey, writeKey, readKey, message) { | ||
const bodyIn = assertUint8(message.body); | ||
if (!await verify(signReadKey, message.signature, bodyIn)) { | ||
if (!await verify(verifyKey, message.signature, bodyIn)) { | ||
return { | ||
error: 'invalid-channel' | ||
error: types_1.EDecryptionError.invalidSignature | ||
}; | ||
} | ||
const decrypted = await decrypt(signReadKey, assertUint8(signWriteKey), bodyIn); | ||
if (decrypted === null) { | ||
const { crypto_box_seal_open } = await libsodium; | ||
const messageDecrypted = crypto_box_seal_open(message.body, writeKey, readKey); | ||
if (messageDecrypted === null) { | ||
return { | ||
error: 'invalid-encryption' | ||
error: types_1.EDecryptionError.invalidEncryption | ||
}; | ||
} | ||
const { crypto_sign_BYTES } = await libsodium; | ||
const [signature, body] = split(decrypted, crypto_sign_BYTES); | ||
if (!await verify(assertUint8(readKey), signature, body)) { | ||
return { | ||
error: 'invalid-owner' | ||
}; | ||
} | ||
return { | ||
body: buffer_1.bufferToAny(body) | ||
body: buffer_1.bufferToAny(messageDecrypted) | ||
}; | ||
@@ -119,9 +76,8 @@ }, | ||
}, | ||
async encryptMessage(annonymousReadKey, annonymousWriteKey, writeKey, message) { | ||
const msgBuffer = assertUint8(buffer_1.anyToBuffer(message)); | ||
const signedStandardized = await sign(assertUint8(writeKey), msgBuffer); | ||
const secret = buffer_1.concatUint8Arrays([signedStandardized, msgBuffer]); | ||
const body = await encrypt(assertUint8(annonymousReadKey), secret); | ||
async encryptMessage(signKey, writeKey, message) { | ||
const { crypto_box_seal } = await libsodium; | ||
const msgBuffer = buffer_1.anyToBuffer(message); | ||
const body = crypto_box_seal(msgBuffer, writeKey); | ||
return { | ||
signature: await sign(assertUint8(annonymousWriteKey), body), | ||
signature: await sign(signKey, body), | ||
body | ||
@@ -132,5 +88,7 @@ }; | ||
const { randombytes_buf, crypto_scalarmult_BYTES, crypto_scalarmult_base } = await libsodium; | ||
const pri = randombytes_buf(crypto_scalarmult_BYTES); | ||
const pub = crypto_scalarmult_base(pri); | ||
return { write: pri, read: pub }; | ||
const privateKey = randombytes_buf(crypto_scalarmult_BYTES); | ||
return { | ||
privateKey, | ||
publicKey: crypto_scalarmult_base(privateKey) | ||
}; | ||
}, | ||
@@ -141,11 +99,11 @@ async computeSecret(pri, remotePublic) { | ||
}, | ||
async createKeys() { | ||
async createEncryptionKeys() { | ||
const { crypto_box_keypair } = await libsodium; | ||
return crypto_box_keypair(); | ||
}, | ||
async createSignKeys() { | ||
const { crypto_sign_keypair } = await libsodium; | ||
const keyPair = crypto_sign_keypair(); | ||
return { | ||
write: keyPair.privateKey, | ||
read: keyPair.publicKey | ||
}; | ||
return crypto_sign_keypair(); | ||
} | ||
}; | ||
//# sourceMappingURL=sodium.js.map |
@@ -7,16 +7,13 @@ import { IEncodable } from '../util/buffer'; | ||
} | ||
export interface IKeyPair { | ||
read: Uint8Array; | ||
write?: Uint8Array; | ||
export interface IRawKeys { | ||
privateKey: Uint8Array; | ||
publicKey: Uint8Array; | ||
} | ||
export interface IKeys extends IKeyPair { | ||
write: Uint8Array; | ||
export declare enum EDecryptionError { | ||
invalidEncryption = "invalid-encryption", | ||
invalidSignature = "invalid-signature" | ||
} | ||
export interface IAnnonymousKeys extends IKeys { | ||
annonymous: true; | ||
write: Uint8Array; | ||
} | ||
export interface IDecryption { | ||
body?: IEncodable; | ||
error?: 'invalid-channel' | 'invalid-encryption' | 'invalid-owner'; | ||
error?: EDecryptionError; | ||
} | ||
@@ -26,16 +23,14 @@ export interface ICryptoCore { | ||
verify(signPublicKey: Uint8Array, signature: Uint8Array, body: Uint8Array): Promise<boolean>; | ||
deriveKdfKey(key: Uint8Array): Promise<Uint8Array>; | ||
deriveAnnonymousKeys(readKey: Uint8Array): Promise<IAnnonymousKeys>; | ||
deriveReadKey(writeKey: Uint8Array): Promise<Uint8Array>; | ||
decryptMessage(signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>; | ||
decryptMessage(verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>; | ||
createSecretKey(): Promise<Uint8Array>; | ||
decrypt(secretKey: Uint8Array, encrypted: IEncodable): Promise<IEncodable>; | ||
createEncryptionKeys(): Promise<IRawKeys>; | ||
createSignKeys(): Promise<IRawKeys>; | ||
decrypt(secretKey: Uint8Array, encrypted: Uint8Array): Promise<IEncodable>; | ||
encrypt(secretKey: Uint8Array, body: IEncodable): Promise<Uint8Array>; | ||
encryptMessage(annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{ | ||
encryptMessage(signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{ | ||
signature: Uint8Array; | ||
body: Uint8Array; | ||
}>; | ||
initHandshake(): Promise<IKeys>; | ||
computeSecret(pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>; | ||
createKeys(): Promise<IKeys>; | ||
initHandshake(): Promise<IRawKeys>; | ||
computeSecret(privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var EDecryptionError; | ||
(function (EDecryptionError) { | ||
EDecryptionError["invalidEncryption"] = "invalid-encryption"; | ||
EDecryptionError["invalidSignature"] = "invalid-signature"; | ||
})(EDecryptionError = exports.EDecryptionError || (exports.EDecryptionError = {})); | ||
//# sourceMappingURL=types.js.map |
@@ -5,2 +5,2 @@ import { ICryptoCore } from '../core/types'; | ||
export declare const HANDSHAKE_MSG_VERSION: Buffer; | ||
export declare function setupHandshake(crypto: ICryptoCore, { createSender, createSenderFromSendKey, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake; | ||
export declare function setupHandshake(crypto: ICryptoCore, { createReceiver, Sender, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake; |
@@ -11,3 +11,3 @@ "use strict"; | ||
} | ||
if (msg.length !== 97) { | ||
if (msg.length !== 161) { | ||
throw Object.assign(new Error(`Error while processing handshake: Invalid handshake size: ${msg.length}`), { code: 'invalid-size', size: msg.length }); | ||
@@ -20,7 +20,7 @@ } | ||
} | ||
function setupHandshake(crypto, { createSender, createSenderFromSendKey, Receiver, Connection }) { | ||
function setupHandshake(crypto, { createReceiver, Sender, Receiver, Connection }) { | ||
class HandshakeInit { | ||
constructor({ receiver, confirmKey, firstMessage }) { | ||
constructor({ receiver, handshakeSecret, firstMessage }) { | ||
this.receiver = isReceiver_1.isReceiver(receiver) ? receiver : new Receiver(receiver); | ||
this.confirmKey = buffer_1.toBuffer(confirmKey); | ||
this.handshakeSecret = buffer_1.toBuffer(handshakeSecret); | ||
this.firstMessage = buffer_1.toBuffer(firstMessage); | ||
@@ -32,3 +32,3 @@ } | ||
firstMessage: buffer_1.bufferToString(this.firstMessage, 'base64'), | ||
confirmKey: buffer_1.bufferToString(this.confirmKey, 'base64') | ||
handshakeSecret: buffer_1.bufferToString(this.handshakeSecret, 'base64') | ||
}; | ||
@@ -38,5 +38,6 @@ } | ||
confirm(accept) { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable_1.cancelable(function* () { | ||
const secretKey = (yield crypto.computeSecret(this.confirmKey, buffer_1.Buffer.from(accept.token, 'base64'))); | ||
const bob = (yield createSender()); | ||
const secretKey = (yield crypto.computeSecret(this.handshakeSecret, buffer_1.Buffer.from(accept.token, 'base64'))); | ||
const bob = (yield createReceiver()); | ||
const sendKey = (yield crypto.decrypt(secretKey, buffer_1.Buffer.from(accept.secret, 'base64'))); | ||
@@ -46,11 +47,13 @@ if (!(sendKey instanceof Uint8Array)) { | ||
} | ||
const sender = (yield createSenderFromSendKey(sendKey)); | ||
const aliceSender = (yield new Sender({ sendKey })); | ||
return yield new HandshakeConfirmation({ | ||
connection: new Connection({ | ||
sender, | ||
receiver: bob.newReceiver() | ||
sender: aliceSender, | ||
receiver: bob.receiver | ||
}), | ||
// In case you are wondering why we not just simply return "bob" as sender | ||
// but instead pass it in two messages: the reason is that without this step | ||
finalMessage: bob.sendKey | ||
// the API is clearer. | ||
// TODO: rethink | ||
finalMessage: bob.sender.sendKey | ||
}); | ||
@@ -71,3 +74,3 @@ }, this); | ||
receiver: this.receiver, | ||
sender: await createSenderFromSendKey(message) | ||
sender: new Sender({ sendKey: message }) | ||
}); | ||
@@ -90,12 +93,11 @@ } | ||
async initHandshake() { | ||
const tempChannel = await createSender(); | ||
const receiver = tempChannel.newReceiver(); | ||
const { write: confirmKey, read: receiveKey } = await crypto.initHandshake(); | ||
const { receiver, sender } = await createReceiver(); | ||
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake(); | ||
return new HandshakeInit({ | ||
receiver, | ||
confirmKey, | ||
handshakeSecret, | ||
firstMessage: buffer_1.Buffer.concat([ | ||
exports.HANDSHAKE_MSG_VERSION, | ||
receiveKey, | ||
tempChannel.sendKey | ||
handshakePublic, | ||
sender.sendKey | ||
]) | ||
@@ -107,10 +109,10 @@ }); | ||
const { token, sendKey } = processHandshake(firstMessage); | ||
const keys = await crypto.initHandshake(); | ||
const secretKey = await crypto.computeSecret(keys.write, token); | ||
const sender = await createSender(); | ||
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake(); | ||
const secretKey = await crypto.computeSecret(handshakeSecret, token); | ||
const { receiver, sender } = await createReceiver(); | ||
return new HandshakeAccept({ | ||
sender: await createSenderFromSendKey(sendKey), | ||
receiver: sender.newReceiver(), | ||
sender: new Sender({ sendKey }), | ||
receiver, | ||
acceptMessage: { | ||
token: buffer_1.bufferToString(keys.read, 'base64'), | ||
token: buffer_1.bufferToString(handshakePublic, 'base64'), | ||
secret: buffer_1.bufferToString(await crypto.encrypt(secretKey, sender.sendKey), 'base64') | ||
@@ -117,0 +119,0 @@ } |
{ | ||
"name": "@consento/crypto", | ||
"version": "0.0.12", | ||
"version": "0.1.0", | ||
"description": "Crypto functionality used in Consento", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"@consento/libsodium-wrappers-sumo": "^0.7.7", | ||
"buffer": "^5.4.3", | ||
"buffer": "^5.6.0", | ||
"sodium-universal": "^2.0.0" | ||
@@ -14,0 +14,0 @@ }, |
@@ -6,2 +6,29 @@ "use strict"; | ||
const buffer_1 = require("../util/buffer"); | ||
const isReceiver_1 = require("../util/isReceiver"); | ||
const isSender_1 = require("../util/isSender"); | ||
const VERIFY_KEY_SIZE = 32; | ||
const VERIFY_KEY_START = 0; | ||
const VERIFY_KEY_END = VERIFY_KEY_SIZE; | ||
const SIGN_KEY_SIZE = 64; | ||
const SIGN_KEY_START = VERIFY_KEY_END; | ||
const SIGN_KEY_END = SIGN_KEY_START + SIGN_KEY_SIZE; | ||
const ENCRYPT_KEY_SIZE = 32; | ||
const ENCRYPT_KEY_START = SIGN_KEY_END; | ||
const ENCRYPT_KEY_END = ENCRYPT_KEY_START + ENCRYPT_KEY_SIZE; | ||
const DECRYPT_KEY_START = ENCRYPT_KEY_END; | ||
function signKeyFromSendKey(receiveKey) { | ||
return receiveKey.slice(SIGN_KEY_START, SIGN_KEY_END); | ||
} | ||
function encryptKeyFromSendKey(sendKey) { | ||
return sendKey.slice(ENCRYPT_KEY_START, ENCRYPT_KEY_END); | ||
} | ||
function decryptKeyFromReceiveKey(receiveKey) { | ||
return receiveKey.slice(DECRYPT_KEY_START); | ||
} | ||
function verifyKeyFromSendKey(sendKey) { | ||
return sendKey.slice(VERIFY_KEY_START, VERIFY_KEY_END); | ||
} | ||
function sendKeyFromReceiveKey(receiveKey) { | ||
return receiveKey.slice(VERIFY_KEY_START, ENCRYPT_KEY_END); | ||
} | ||
function setupPrimitives(crypto) { | ||
@@ -29,10 +56,7 @@ class Annonymous { | ||
} | ||
compare(other, force = false) { | ||
if (!(other instanceof Annonymous)) { | ||
compare(other) { | ||
if (isSender_1.isSender(other) || isReceiver_1.isReceiver(other)) { | ||
return 1; | ||
} | ||
if (force) { | ||
return buffer_1.bufferCompare(other.id, this.id); | ||
} | ||
return other.compare(this, true); | ||
return buffer_1.bufferCompare(other.id, this.id); | ||
} | ||
@@ -48,91 +72,141 @@ toJSON() { | ||
async verify(signature, body) { | ||
return crypto.verify(this.id, signature, body); | ||
return await crypto.verify(this.id, signature, body); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/require-await | ||
async verifyMessage(message) { | ||
return this.verify(message.signature, message.body); | ||
return await this.verify(message.signature, message.body); | ||
} | ||
} | ||
class Receiver extends Annonymous { | ||
constructor(opts) { | ||
super({ id: opts.id }); | ||
this[types_1.receiverFlag] = true; | ||
this.receiveKey = buffer_1.toBuffer(opts.receiveKey); | ||
this.signKey = crypto.deriveAnnonymousKeys(this.receiveKey).then(keys => keys.write); | ||
class Sender { | ||
constructor({ id, sendKey }) { | ||
this[types_1.senderFlag] = true; | ||
this.sendKey = buffer_1.toBuffer(sendKey); | ||
if (id !== undefined) { | ||
this._annonymous = new Annonymous({ id }); | ||
} | ||
} | ||
get receiveKeyBase64() { | ||
if (this._receiveKeyBase64 === undefined) { | ||
this._receiveKeyBase64 = buffer_1.bufferToString(this.receiveKey, 'base64'); | ||
get signKey() { | ||
if (this._signKey === undefined) { | ||
this._signKey = signKeyFromSendKey(this.sendKey); | ||
} | ||
return this._receiveKeyBase64; | ||
return this._signKey; | ||
} | ||
newAnnonymous() { | ||
return new Annonymous(this); | ||
get encryptKey() { | ||
if (this._encryptKey === undefined) { | ||
this._encryptKey = encryptKeyFromSendKey(this.sendKey); | ||
} | ||
return this._encryptKey; | ||
} | ||
compare(other, force = false) { | ||
if (!(other instanceof Receiver)) { | ||
return (force ? -1 : 1); | ||
get sendKeyBase64() { | ||
if (this._sendKeyBase64 === undefined) { | ||
this._sendKeyBase64 = buffer_1.bufferToString(this.sendKey, 'base64'); | ||
} | ||
if (force) { | ||
return buffer_1.bufferCompare(other.receiveKey, this.receiveKey); | ||
return this._sendKeyBase64; | ||
} | ||
get sender() { | ||
return this; | ||
} | ||
get id() { | ||
return this.annonymous.id; | ||
} | ||
get idHex() { | ||
return this.annonymous.idHex; | ||
} | ||
get idBase64() { | ||
return this.annonymous.idBase64; | ||
} | ||
get annonymous() { | ||
if (this._annonymous === undefined) { | ||
this._annonymous = new Annonymous({ id: verifyKeyFromSendKey(this.sendKey) }); | ||
} | ||
return other.compare(this, true); | ||
return this._annonymous; | ||
} | ||
equals(other) { | ||
return this.compare(other) === 0; | ||
} | ||
compare(other) { | ||
if (isReceiver_1.isReceiver(other)) { | ||
return 1; | ||
} | ||
if (!isSender_1.isSender(other)) { | ||
return -1; | ||
} | ||
return buffer_1.bufferCompare(other.sendKey, this.sendKey); | ||
} | ||
toJSON() { | ||
return { | ||
id: this.idBase64, | ||
receiveKey: this.receiveKeyBase64 | ||
}; | ||
return { sendKey: this.sendKeyBase64 }; | ||
} | ||
toString() { | ||
return `Receiver[receiveKey=${this.receiveKeyBase64}]`; | ||
return `Sender[sendKey=${this.sendKeyBase64}]`; | ||
} | ||
async sign(data) { | ||
return crypto.sign(await this.signKey, data); | ||
return await crypto.sign(this.signKey, data); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
decrypt(encrypted) { | ||
encrypt(message) { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable_1.cancelable(function* () { | ||
return yield crypto.decryptMessage(this.id, yield this.signKey, this.receiveKey, encrypted); | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return yield crypto.encryptMessage(this.signKey, this.encryptKey, message); | ||
}, this); | ||
} | ||
} | ||
class Sender extends Receiver { | ||
class Receiver { | ||
constructor({ id, sendKey, receiveKey }) { | ||
super({ id, receiveKey }); | ||
this[types_1.senderFlag] = true; | ||
this.sendKey = buffer_1.toBuffer(sendKey); | ||
this[types_1.receiverFlag] = true; | ||
this.receiveKey = buffer_1.toBuffer(receiveKey); | ||
if (sendKey !== undefined) { | ||
this._sender = new Sender({ id, sendKey }); | ||
} | ||
} | ||
get sendKeyBase64() { | ||
if (this._sendKeyBase64 === undefined) { | ||
this._sendKeyBase64 = buffer_1.bufferToString(this.sendKey, 'base64'); | ||
get sender() { | ||
if (this._sender === undefined) { | ||
this._sender = new Sender({ sendKey: sendKeyFromReceiveKey(this.receiveKey) }); | ||
} | ||
return this._sendKeyBase64; | ||
return this._sender; | ||
} | ||
newReceiver() { | ||
return new Receiver(this); | ||
get id() { | ||
return this.sender.id; | ||
} | ||
compare(other, force = false) { | ||
if (!(other instanceof Sender)) { | ||
return (force ? -1 : 1); | ||
get idHex() { | ||
return this.sender.idHex; | ||
} | ||
get idBase64() { | ||
return this.sender.idBase64; | ||
} | ||
get receiver() { | ||
return this; | ||
} | ||
get annonymous() { | ||
return this.sender.annonymous; | ||
} | ||
get decryptKey() { | ||
return decryptKeyFromReceiveKey(this.receiveKey); | ||
} | ||
get receiveKeyBase64() { | ||
if (this._receiveKeyBase64 === undefined) { | ||
this._receiveKeyBase64 = buffer_1.bufferToString(this.receiveKey, 'base64'); | ||
} | ||
if (force) { | ||
return buffer_1.bufferCompare(other.sendKey, this.sendKey); | ||
return this._receiveKeyBase64; | ||
} | ||
equals(other) { | ||
return this.compare(other) === 0; | ||
} | ||
compare(other) { | ||
if (!isReceiver_1.isReceiver(other)) { | ||
return -1; | ||
} | ||
return other.compare(this, true); | ||
return buffer_1.bufferCompare(other.receiveKey, this.receiveKey); | ||
} | ||
toJSON() { | ||
return { | ||
id: this.idBase64, | ||
sendKey: this.sendKeyBase64, | ||
receiveKey: this.receiveKeyBase64 | ||
}; | ||
return { receiveKey: this.receiveKeyBase64 }; | ||
} | ||
toString() { | ||
return `Sender[sendKey=${this.sendKeyBase64}]`; | ||
return `Receiver[receiveKey=${this.receiveKeyBase64}]`; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
encrypt(message) { | ||
decrypt(encrypted) { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable_1.cancelable(function* () { | ||
return yield crypto.encryptMessage(this.id, yield this.signKey, this.sendKey, message); | ||
return yield crypto.decryptMessage(this.annonymous.id, this.sender.encryptKey, this.decryptKey, encrypted); | ||
}, this); | ||
@@ -143,4 +217,4 @@ } | ||
constructor(opts) { | ||
this.receiver = new Receiver(opts.receiver); | ||
this.sender = new Sender(opts.sender); | ||
this.receiver = (opts.receiver instanceof Receiver) ? opts.receiver : new Receiver(opts.receiver); | ||
this.sender = (opts.sender instanceof Sender) ? opts.sender : new Sender(opts.sender); | ||
} | ||
@@ -155,22 +229,15 @@ toJSON() { | ||
return { | ||
async createReceiverFromReceiveKey(receiveKey) { | ||
const syncReceiveKey = buffer_1.toBuffer(receiveKey); | ||
const { read: id } = await crypto.deriveAnnonymousKeys(syncReceiveKey); | ||
return new Receiver({ receiveKey: syncReceiveKey, id }); | ||
async createReceiver() { | ||
const [encrypt, sign] = await Promise.all([ | ||
crypto.createEncryptionKeys(), | ||
crypto.createSignKeys() | ||
]); | ||
const sendKey = buffer_1.Buffer.concat([sign.publicKey, sign.privateKey, encrypt.publicKey]); | ||
const receiver = new Receiver({ | ||
id: sign.publicKey, | ||
sendKey, | ||
receiveKey: buffer_1.Buffer.concat([sendKey, encrypt.privateKey]) | ||
}); | ||
return receiver; | ||
}, | ||
async createSenderFromSendKey(sendKey) { | ||
const sendKeySync = buffer_1.toBuffer(sendKey); | ||
const receiveKey = await crypto.deriveReadKey(sendKeySync); | ||
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey); | ||
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve | ||
const signKey = Promise.resolve(signKeyValue); | ||
return new Sender({ id, signKey, receiveKey, sendKey: sendKeySync }); | ||
}, | ||
async createSender() { | ||
const { read: receiveKey, write: sendKey } = await crypto.createKeys(); | ||
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey); | ||
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve | ||
const signKey = Promise.resolve(signKeyValue); | ||
return new Sender({ id, signKey, receiveKey, sendKey }); | ||
}, | ||
Annonymous, | ||
@@ -177,0 +244,0 @@ Receiver, |
@@ -42,12 +42,14 @@ # @consento/crypto | ||
```javascript | ||
const { createSender } = setup(sodium) | ||
const { createReceiver } = setup(sodium) | ||
``` | ||
You can create a new communication channel by creating a new sender: | ||
You can create a new communication channel by creating a new receiver: | ||
```javascript | ||
const sender = await createSender() | ||
sender.id // public channel id - can be shared with other people - also used to verify if a message was properly sent. | ||
sender.receiveKey // channel reader id - to be used for decrypting sent messages | ||
sender.sendKey // encryption key for messages | ||
const receiver = await createReceiver() | ||
receiver.receiveKey // allows decryption of messages | ||
receiver.sender.sendKey // encryption key for sending messages | ||
receiver.sender.annonymous.id // public channel id - can be shared with other people - also used to verify if a message was properly sent. | ||
receiver.sender.id // shortcut on the sender for the channel id | ||
receiver.id // shortcut on the receiver for the channel id | ||
``` | ||
@@ -57,12 +59,16 @@ | ||
A `Sender` > `Receiver` > `Annonymous` and there are methods to create a receiver/annonymous | ||
A `Receiver` > `Sender` > `Annonymous` and there are methods to create a receiver/annonymous | ||
instance out of a sender instance: | ||
```javascript | ||
const { createSender, toReceiver, toAnnonymous } = setup(sodium) | ||
const sender = await createSender() | ||
const receiver = toReceiver(sender) | ||
const annonymous = toAnnonymous(sender) | ||
const { createReceiver } = setup(sodium) | ||
const receiver = await createReceiver() | ||
``` | ||
you can also destruct each instance: | ||
```javascript | ||
const { receiver, sender, annonymous } = await createReceiver() | ||
``` | ||
Every instance can verify a given message for a channel: | ||
@@ -99,5 +105,5 @@ | ||
```javascript | ||
const { Sender } = setup(sodium) | ||
const senderJson = sender.toJSON() | ||
const restoredSender = new Sender(json) | ||
const { Receiver } = setup(sodium) | ||
const receiverJson = receiver.toJSON() | ||
const restoredReceiver = new Receiver(json) | ||
``` | ||
@@ -144,3 +150,3 @@ | ||
```javascript | ||
const decryptedAcceptMessage = (await decrypt(alice.receiver, acceptMessage)).body | ||
const decryptedAcceptMessage = (await alice.receiver.decryptMessage(acceptMessage)).body | ||
const package = await confirmHandshake(alice, decryptedAcceptMessage) | ||
@@ -165,3 +171,3 @@ const { | ||
```javascript | ||
const { sender: bobToAliceSender, receiver: aliceToBobReceiver } = await finalize(bob, finalMessage) | ||
const { sender: bobToAliceSender, receiver: aliceToBobReceiver } = await bob.finalize(finalMessage) | ||
``` | ||
@@ -168,0 +174,0 @@ |
@@ -10,3 +10,3 @@ import * as sodium from 'sodium-universal' | ||
import { | ||
ICryptoCore, IAnnonymousKeys, IEncryptedMessage, IDecryption, IKeys | ||
ICryptoCore, IEncryptedMessage, IDecryption, EDecryptionError, IRawKeys | ||
} from './types' | ||
@@ -16,9 +16,10 @@ | ||
const { | ||
crypto_kdf_derive_from_key, | ||
randombytes_buf, | ||
crypto_scalarmult_base, | ||
crypto_scalarmult, | ||
crypto_scalarmult_ed25519_BYTES, | ||
crypto_kdf_BYTES_MAX, | ||
crypto_scalarmult_BYTES, | ||
crypto_kdf_CONTEXTBYTES, | ||
crypto_box_seal, | ||
crypto_box_seal_open, | ||
crypto_box_keypair, | ||
crypto_box_SEALBYTES, | ||
@@ -30,10 +31,4 @@ crypto_box_SECRETKEYBYTES, | ||
crypto_sign_BYTES, | ||
crypto_sign_ed25519_sk_to_curve25519, | ||
crypto_sign_ed25519_pk_to_curve25519, | ||
crypto_sign_seed_keypair, | ||
crypto_sign_detached, | ||
crypto_sign_verify_detached, | ||
crypto_sign_ed25519_sk_to_pk, | ||
crypto_box_seal, | ||
crypto_box_seal_open, | ||
crypto_sign_keypair, | ||
@@ -68,28 +63,2 @@ crypto_secretbox_easy, | ||
function boxSecretFromSignSecret (signSecretKey: Uint8Array): Uint8Array { | ||
const encryptSecretKey = sodium_malloc(crypto_box_SECRETKEYBYTES) | ||
crypto_sign_ed25519_sk_to_curve25519(encryptSecretKey, signSecretKey) | ||
return encryptSecretKey | ||
} | ||
function boxPublicFromSignPublic (signPublicKey: Uint8Array): Uint8Array { | ||
const encryptPublicKey = sodium_malloc(crypto_box_PUBLICKEYBYTES) | ||
crypto_sign_ed25519_pk_to_curve25519(encryptPublicKey, signPublicKey) | ||
return encryptPublicKey | ||
} | ||
function decrypt (encryptPublicKey: Uint8Array, encryptSecretKey: Uint8Array, messageEncrypted: Uint8Array): Uint8Array { | ||
const messageDecrypted = sodium_malloc(messageEncrypted.length - crypto_box_SEALBYTES) | ||
const successful = crypto_box_seal_open(messageDecrypted, messageEncrypted, encryptPublicKey, encryptSecretKey) | ||
if (!successful) { | ||
return null | ||
} | ||
return messageDecrypted | ||
} | ||
function encrypt (encryptPublicKey: Uint8Array, message: Uint8Array): Uint8Array { | ||
const messageEncrypted = sodium_malloc(message.length + crypto_box_SEALBYTES) | ||
crypto_box_seal(messageEncrypted, message, encryptPublicKey) | ||
return messageEncrypted | ||
} | ||
function sign (signSecretKey: Uint8Array, body: Uint8Array): Uint8Array { | ||
@@ -106,7 +75,2 @@ const signature = sodium_malloc(crypto_sign_BYTES) | ||
/* eslint @typescript-eslint/require-await: "off" */ | ||
async deriveKdfKey (key: Uint8Array) { | ||
const derivedKey = sodium_malloc(crypto_kdf_BYTES_MAX) | ||
crypto_kdf_derive_from_key(derivedKey, 1, deriveContext, key) | ||
return derivedKey | ||
}, | ||
async sign (signSecretKey: Uint8Array, body: Uint8Array) { | ||
@@ -118,16 +82,2 @@ return sign(signSecretKey, body) | ||
}, | ||
async deriveAnnonymousKeys (readKey: Uint8Array) { | ||
const sign: IAnnonymousKeys = { | ||
annonymous: true, | ||
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
write: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
} | ||
crypto_sign_seed_keypair(sign.read, sign.write, readKey) | ||
return sign | ||
}, | ||
async deriveReadKey (writeKey: Uint8Array) { | ||
const readKey = sodium_malloc(crypto_sign_PUBLICKEYBYTES) | ||
crypto_sign_ed25519_sk_to_pk(readKey, writeKey) | ||
return readKey | ||
}, | ||
async createSecretKey () { | ||
@@ -152,56 +102,55 @@ return randomBuffer(crypto_secretbox_KEYBYTES) | ||
}, | ||
async decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> { | ||
if (!verify(signReadKey, message.signature, message.body)) { | ||
async decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> { | ||
if (!verify(verifyKey, message.signature, message.body)) { | ||
return { | ||
error: 'invalid-channel' | ||
error: EDecryptionError.invalidSignature | ||
} | ||
} | ||
const encryptPublicKey = boxPublicFromSignPublic(signReadKey) | ||
const encryptSecretKey = boxSecretFromSignSecret(signWriteKey) | ||
const decrypted = decrypt(encryptPublicKey, encryptSecretKey, message.body) | ||
if (decrypted === null) { | ||
const messageDecrypted = sodium_malloc(message.body.length - crypto_box_SEALBYTES) | ||
const successful = crypto_box_seal_open(messageDecrypted, message.body, writeKey, readKey) | ||
if (!successful) { | ||
return { | ||
error: 'invalid-encryption' | ||
error: EDecryptionError.invalidEncryption | ||
} | ||
} | ||
const [signature, body] = split(decrypted, crypto_sign_BYTES) | ||
if (!verify(readKey, signature, body)) { | ||
return { | ||
error: 'invalid-owner' | ||
} | ||
} | ||
return { | ||
body: bufferToAny(body) | ||
body: bufferToAny(messageDecrypted) | ||
} | ||
}, | ||
async encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) { | ||
async encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) { | ||
const msgBuffer = anyToBuffer(message) | ||
const signedStandardized = sign(writeKey, msgBuffer) | ||
const secret = Buffer.concat([signedStandardized, msgBuffer]) | ||
const encryptPublicKey = boxPublicFromSignPublic(annonymousReadKey) | ||
const body = encrypt(encryptPublicKey, secret) | ||
const body = sodium_malloc(msgBuffer.length + crypto_box_SEALBYTES) | ||
crypto_box_seal(body, msgBuffer, writeKey) | ||
return { | ||
signature: sign(annonymousWriteKey, body), | ||
signature: sign(signKey, body), | ||
body | ||
} | ||
}, | ||
async initHandshake (): Promise<IKeys> { | ||
const pri = randomBuffer(crypto_scalarmult_ed25519_BYTES) | ||
const pub = sodium_malloc(crypto_scalarmult_ed25519_BYTES) | ||
crypto_scalarmult_base(pub, pri) | ||
return { write: pri, read: pub } | ||
async initHandshake (): Promise<IRawKeys> { | ||
const privateKey = randomBuffer(crypto_scalarmult_BYTES) | ||
const publicKey = sodium_malloc(crypto_scalarmult_BYTES) | ||
crypto_scalarmult_base(publicKey, privateKey) | ||
return { privateKey, publicKey } | ||
}, | ||
async computeSecret (pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> { | ||
const secret = sodium_malloc(crypto_scalarmult_ed25519_BYTES) | ||
crypto_scalarmult(secret, pri, remotePublic) | ||
async computeSecret (privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> { | ||
const secret = sodium_malloc(crypto_scalarmult_BYTES) | ||
crypto_scalarmult(secret, privateKey, remotePublic) | ||
return secret | ||
}, | ||
async createKeys (): Promise<IKeys> { | ||
async createEncryptionKeys (): Promise<IRawKeys> { | ||
const keys = { | ||
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
write: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
publicKey: sodium_malloc(crypto_box_PUBLICKEYBYTES), | ||
privateKey: sodium_malloc(crypto_box_SECRETKEYBYTES) | ||
} | ||
crypto_sign_keypair(keys.read, keys.write) | ||
crypto_box_keypair(keys.publicKey, keys.privateKey) | ||
return keys | ||
}, | ||
async createSignKeys (): Promise<IRawKeys> { | ||
const keys = { | ||
publicKey: sodium_malloc(crypto_sign_PUBLICKEYBYTES), | ||
privateKey: sodium_malloc(crypto_sign_SECRETKEYBYTES) | ||
} | ||
crypto_sign_keypair(keys.publicKey, keys.privateKey) | ||
return keys | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable @typescript-eslint/camelcase */ | ||
import _libsodium from '@consento/libsodium-wrappers-sumo' | ||
@@ -6,3 +7,2 @@ | ||
bufferToAny, | ||
concatUint8Arrays, | ||
IEncodable, | ||
@@ -13,3 +13,3 @@ Buffer | ||
import { | ||
ICryptoCore, IEncryptedMessage, IDecryption | ||
ICryptoCore, IEncryptedMessage, IDecryption, EDecryptionError | ||
} from './types' | ||
@@ -31,28 +31,2 @@ | ||
const deriveContext = 'conotify' | ||
/* eslint @typescript-eslint/camelcase: "off" */ | ||
async function boxSecretFromSignSecret (signSecretKey: Uint8Array): Promise<Uint8Array> { | ||
const { crypto_sign_ed25519_sk_to_curve25519 } = await libsodium | ||
return crypto_sign_ed25519_sk_to_curve25519(assertUint8(signSecretKey)) | ||
} | ||
async function boxPublicFromSignPublic (signPublicKey: Uint8Array): Promise<Uint8Array> { | ||
const { crypto_sign_ed25519_pk_to_curve25519 } = await libsodium | ||
return crypto_sign_ed25519_pk_to_curve25519(assertUint8(signPublicKey)) | ||
} | ||
async function decrypt (signReadKey: Uint8Array, signWriteKey: Uint8Array, messageEncrypted: Uint8Array): Promise<Uint8Array> { | ||
const encryptPublicKey = await boxPublicFromSignPublic(signReadKey) | ||
const encryptSecretKey = await boxSecretFromSignSecret(signWriteKey) | ||
const { crypto_box_seal_open } = await libsodium | ||
return crypto_box_seal_open(assertUint8(messageEncrypted), encryptPublicKey, encryptSecretKey) | ||
} | ||
async function encrypt (signPublicKey: Uint8Array, message: Uint8Array): Promise<Uint8Array> { | ||
const { crypto_box_seal: seal } = await libsodium | ||
const encryptPublicKey = await boxPublicFromSignPublic(assertUint8(signPublicKey)) | ||
return seal(assertUint8(message), encryptPublicKey) | ||
} | ||
function assertUint8 (input: Uint8Array | Buffer): Uint8Array { | ||
@@ -75,44 +49,20 @@ if (!('Buffer' in global) || input instanceof Buffer) { | ||
export const sodium: ICryptoCore = { | ||
async deriveKdfKey (key: Uint8Array) { | ||
const { crypto_kdf_derive_from_key, crypto_kdf_BYTES_MAX } = await libsodium | ||
return crypto_kdf_derive_from_key(crypto_kdf_BYTES_MAX, 1, deriveContext, assertUint8(key)) | ||
}, | ||
sign, | ||
verify, | ||
async deriveAnnonymousKeys (readKey: Uint8Array) { | ||
const { crypto_sign_seed_keypair } = await libsodium | ||
const pair = crypto_sign_seed_keypair(assertUint8(readKey)) | ||
return { | ||
annonymous: true, | ||
read: pair.publicKey, | ||
write: pair.privateKey | ||
} | ||
}, | ||
async deriveReadKey (writeKey: Uint8Array) { | ||
const { crypto_sign_ed25519_sk_to_pk } = await libsodium | ||
return crypto_sign_ed25519_sk_to_pk(assertUint8(writeKey)) | ||
}, | ||
async decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> { | ||
signReadKey = assertUint8(signReadKey) | ||
async decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> { | ||
const bodyIn = assertUint8(message.body) | ||
if (!await verify(signReadKey, message.signature, bodyIn)) { | ||
if (!await verify(verifyKey, message.signature, bodyIn)) { | ||
return { | ||
error: 'invalid-channel' | ||
error: EDecryptionError.invalidSignature | ||
} | ||
} | ||
const decrypted = await decrypt(signReadKey, assertUint8(signWriteKey), bodyIn) | ||
if (decrypted === null) { | ||
const { crypto_box_seal_open } = await libsodium | ||
const messageDecrypted = crypto_box_seal_open(message.body, writeKey, readKey) | ||
if (messageDecrypted === null) { | ||
return { | ||
error: 'invalid-encryption' | ||
error: EDecryptionError.invalidEncryption | ||
} | ||
} | ||
const { crypto_sign_BYTES } = await libsodium | ||
const [signature, body] = split(decrypted, crypto_sign_BYTES) | ||
if (!await verify(assertUint8(readKey), signature, body)) { | ||
return { | ||
error: 'invalid-owner' | ||
} | ||
} | ||
return { | ||
body: bufferToAny(body) | ||
body: bufferToAny(messageDecrypted) | ||
} | ||
@@ -137,9 +87,8 @@ }, | ||
}, | ||
async encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) { | ||
const msgBuffer = assertUint8(anyToBuffer(message)) | ||
const signedStandardized = await sign(assertUint8(writeKey), msgBuffer) | ||
const secret = concatUint8Arrays([signedStandardized, msgBuffer]) | ||
const body = await encrypt(assertUint8(annonymousReadKey), secret) | ||
async encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<IEncryptedMessage> { | ||
const { crypto_box_seal } = await libsodium | ||
const msgBuffer = anyToBuffer(message) | ||
const body = crypto_box_seal(msgBuffer, writeKey) | ||
return { | ||
signature: await sign(assertUint8(annonymousWriteKey), body), | ||
signature: await sign(signKey, body), | ||
body | ||
@@ -150,5 +99,7 @@ } | ||
const { randombytes_buf, crypto_scalarmult_BYTES, crypto_scalarmult_base } = await libsodium | ||
const pri = randombytes_buf(crypto_scalarmult_BYTES) | ||
const pub = crypto_scalarmult_base(pri) | ||
return { write: pri, read: pub } | ||
const privateKey = randombytes_buf(crypto_scalarmult_BYTES) | ||
return { | ||
privateKey, | ||
publicKey: crypto_scalarmult_base(privateKey) | ||
} | ||
}, | ||
@@ -159,10 +110,10 @@ async computeSecret (pri: Uint8Array, remotePublic: Uint8Array) { | ||
}, | ||
async createKeys () { | ||
async createEncryptionKeys () { | ||
const { crypto_box_keypair } = await libsodium | ||
return crypto_box_keypair() | ||
}, | ||
async createSignKeys () { | ||
const { crypto_sign_keypair } = await libsodium | ||
const keyPair = crypto_sign_keypair() | ||
return { | ||
write: keyPair.privateKey, | ||
read: keyPair.publicKey | ||
} | ||
return crypto_sign_keypair() | ||
} | ||
} |
@@ -10,19 +10,15 @@ import { IEncodable } from '../util/buffer' | ||
export interface IKeyPair { | ||
read: Uint8Array | ||
write?: Uint8Array | ||
export interface IRawKeys { | ||
privateKey: Uint8Array | ||
publicKey: Uint8Array | ||
} | ||
export interface IKeys extends IKeyPair { | ||
write: Uint8Array | ||
export enum EDecryptionError { | ||
invalidEncryption = 'invalid-encryption', | ||
invalidSignature = 'invalid-signature' | ||
} | ||
export interface IAnnonymousKeys extends IKeys { | ||
annonymous: true | ||
write: Uint8Array | ||
} | ||
export interface IDecryption { | ||
body?: IEncodable | ||
error?: 'invalid-channel' | 'invalid-encryption' | 'invalid-owner' | ||
error?: EDecryptionError | ||
} | ||
@@ -33,16 +29,14 @@ | ||
verify (signPublicKey: Uint8Array, signature: Uint8Array, body: Uint8Array): Promise<boolean> | ||
deriveKdfKey (key: Uint8Array): Promise<Uint8Array> | ||
deriveAnnonymousKeys (readKey: Uint8Array): Promise<IAnnonymousKeys> | ||
deriveReadKey (writeKey: Uint8Array): Promise<Uint8Array> | ||
decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> | ||
decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> | ||
createSecretKey(): Promise<Uint8Array> | ||
decrypt(secretKey: Uint8Array, encrypted: IEncodable): Promise<IEncodable> | ||
createEncryptionKeys (): Promise<IRawKeys> | ||
createSignKeys (): Promise<IRawKeys> | ||
decrypt(secretKey: Uint8Array, encrypted: Uint8Array): Promise<IEncodable> | ||
encrypt(secretKey: Uint8Array, body: IEncodable): Promise<Uint8Array> | ||
encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{ | ||
encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{ | ||
signature: Uint8Array | ||
body: Uint8Array | ||
}> | ||
initHandshake (): Promise<IKeys> | ||
computeSecret (pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> | ||
createKeys (): Promise<IKeys> | ||
initHandshake (): Promise<IRawKeys> | ||
computeSecret (privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> | ||
} |
@@ -0,4 +1,6 @@ | ||
/* eslint-disable @typescript-eslint/no-throw-literal */ | ||
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841 | ||
import { ICryptoCore } from '../core/types' | ||
import { Buffer, toBuffer, bufferToString, IEncodable } from '../util/buffer' | ||
import { ICryptoHandshake, IHandshakeInit, IReceiver, ICryptoPrimitives, IHandshakeInitOptions, IHandshakeAccept, ISender, IHandshakeAcceptMessage, IHandshakeAcceptOptions, IHandshakeConfirmation, IHandshakeAcceptJSON, IHandshakeConfirmationOptions, IHandshakeConfirmationJSON, IConnection } from '../types' | ||
import { ICryptoHandshake, IHandshakeInit, IReceiver, ICryptoPrimitives, IHandshakeInitOptions, IHandshakeAccept, ISender, IHandshakeAcceptMessage, IHandshakeAcceptOptions, IHandshakeConfirmation, IHandshakeAcceptJSON, IHandshakeConfirmationOptions, IHandshakeConfirmationJSON, IConnection, IHandshakeInitJSON } from '../types' | ||
import { isReceiver } from '../util/isReceiver' | ||
@@ -16,3 +18,3 @@ import { cancelable, ICancelable } from '../util/cancelable' | ||
} | ||
if (msg.length !== 97) { | ||
if (msg.length !== 161) { | ||
throw Object.assign(new Error(`Error while processing handshake: Invalid handshake size: ${msg.length}`), { code: 'invalid-size', size: msg.length }) | ||
@@ -26,19 +28,19 @@ } | ||
export function setupHandshake (crypto: ICryptoCore, { createSender, createSenderFromSendKey, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake { | ||
export function setupHandshake (crypto: ICryptoCore, { createReceiver, Sender, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake { | ||
class HandshakeInit implements IHandshakeInit { | ||
receiver: IReceiver | ||
firstMessage: Uint8Array | ||
confirmKey: Uint8Array | ||
handshakeSecret: Uint8Array | ||
constructor ({ receiver, confirmKey, firstMessage }: IHandshakeInitOptions) { | ||
constructor ({ receiver, handshakeSecret, firstMessage }: IHandshakeInitOptions) { | ||
this.receiver = isReceiver(receiver) ? receiver : new Receiver(receiver) | ||
this.confirmKey = toBuffer(confirmKey) | ||
this.handshakeSecret = toBuffer(handshakeSecret) | ||
this.firstMessage = toBuffer(firstMessage) | ||
} | ||
toJSON (): any { | ||
toJSON (): IHandshakeInitJSON { | ||
return { | ||
receiver: this.receiver.toJSON(), | ||
firstMessage: bufferToString(this.firstMessage, 'base64'), | ||
confirmKey: bufferToString(this.confirmKey, 'base64') | ||
handshakeSecret: bufferToString(this.handshakeSecret, 'base64') | ||
} | ||
@@ -49,5 +51,6 @@ } | ||
confirm (accept: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation> { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable<IHandshakeConfirmation, HandshakeInit>(function * () { | ||
const secretKey = (yield crypto.computeSecret(this.confirmKey, Buffer.from(accept.token, 'base64'))) as Uint8Array | ||
const bob = (yield createSender()) as ISender | ||
const secretKey = (yield crypto.computeSecret(this.handshakeSecret, Buffer.from(accept.token, 'base64'))) as Uint8Array | ||
const bob = (yield createReceiver()) as IReceiver | ||
const sendKey = (yield crypto.decrypt(secretKey, Buffer.from(accept.secret, 'base64'))) as IEncodable | ||
@@ -57,11 +60,13 @@ if (!(sendKey instanceof Uint8Array)) { | ||
} | ||
const sender = (yield createSenderFromSendKey(sendKey)) as ISender | ||
const aliceSender = (yield new Sender({ sendKey })) as ISender | ||
return yield new HandshakeConfirmation({ | ||
connection: new Connection({ | ||
sender, | ||
receiver: bob.newReceiver() | ||
sender: aliceSender, | ||
receiver: bob.receiver | ||
}), | ||
// In case you are wondering why we not just simply return "bob" as sender | ||
// but instead pass it in two messages: the reason is that without this step | ||
finalMessage: bob.sendKey | ||
// the API is clearer. | ||
// TODO: rethink | ||
finalMessage: bob.sender.sendKey | ||
}) | ||
@@ -90,3 +95,3 @@ }, this) | ||
receiver: this.receiver, | ||
sender: await createSenderFromSendKey(message) | ||
sender: new Sender({ sendKey: message }) | ||
}) | ||
@@ -115,12 +120,11 @@ } | ||
async initHandshake (): Promise<HandshakeInit> { | ||
const tempChannel = await createSender() | ||
const receiver = tempChannel.newReceiver() | ||
const { write: confirmKey, read: receiveKey } = await crypto.initHandshake() | ||
const { receiver, sender } = await createReceiver() | ||
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake() | ||
return new HandshakeInit({ | ||
receiver, | ||
confirmKey, | ||
handshakeSecret, | ||
firstMessage: Buffer.concat([ | ||
HANDSHAKE_MSG_VERSION, | ||
receiveKey, | ||
tempChannel.sendKey | ||
handshakePublic, | ||
sender.sendKey | ||
]) | ||
@@ -135,10 +139,10 @@ }) | ||
} = processHandshake(firstMessage) | ||
const keys = await crypto.initHandshake() | ||
const secretKey = await crypto.computeSecret(keys.write, token) | ||
const sender = await createSender() | ||
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake() | ||
const secretKey = await crypto.computeSecret(handshakeSecret, token) | ||
const { receiver, sender } = await createReceiver() | ||
return new HandshakeAccept({ | ||
sender: await createSenderFromSendKey(sendKey), | ||
receiver: sender.newReceiver(), | ||
sender: new Sender({ sendKey }), | ||
receiver, | ||
acceptMessage: { | ||
token: bufferToString(keys.read, 'base64'), | ||
token: bufferToString(handshakePublic, 'base64'), | ||
secret: bufferToString(await crypto.encrypt(secretKey, sender.sendKey), 'base64') | ||
@@ -145,0 +149,0 @@ } |
import { ICryptoCore, IDecryption, IEncryptedMessage } from '../core/types' | ||
import { | ||
IAnnonymous, IAnnonymousOptions, IAnnonymousJSON, annonymousFlag, | ||
IReceiver, IReceiverOptions, IReceiverJSON, receiverFlag, | ||
ISender, ISenderOptions, ISenderJSON, senderFlag, | ||
IReceiver, IReceiverOptions, receiverFlag, | ||
ISender, ISenderOptions, senderFlag, | ||
ICryptoPrimitives, | ||
IConnectionOptions, | ||
IConnectionJSON | ||
IConnectionJSON, | ||
ISenderJSON, | ||
IReceiverJSON | ||
} from '../types' | ||
import { ICancelable, cancelable } from '../util/cancelable' | ||
import { Buffer, bufferToString, bufferCompare, toBuffer, IStringOrBuffer, IEncodable } from '../util/buffer' | ||
import { Buffer, bufferToString, bufferCompare, toBuffer, IEncodable } from '../util/buffer' | ||
import { isReceiver } from '../util/isReceiver' | ||
import { isSender } from '../util/isSender' | ||
const VERIFY_KEY_SIZE = 32 | ||
const VERIFY_KEY_START = 0 | ||
const VERIFY_KEY_END = VERIFY_KEY_SIZE | ||
const SIGN_KEY_SIZE = 64 | ||
const SIGN_KEY_START = VERIFY_KEY_END | ||
const SIGN_KEY_END = SIGN_KEY_START + SIGN_KEY_SIZE | ||
const ENCRYPT_KEY_SIZE = 32 | ||
const ENCRYPT_KEY_START = SIGN_KEY_END | ||
const ENCRYPT_KEY_END = ENCRYPT_KEY_START + ENCRYPT_KEY_SIZE | ||
const DECRYPT_KEY_START = ENCRYPT_KEY_END | ||
function signKeyFromSendKey (receiveKey: Uint8Array): Uint8Array { | ||
return receiveKey.slice(SIGN_KEY_START, SIGN_KEY_END) | ||
} | ||
function encryptKeyFromSendKey (sendKey: Uint8Array): Uint8Array { | ||
return sendKey.slice(ENCRYPT_KEY_START, ENCRYPT_KEY_END) | ||
} | ||
function decryptKeyFromReceiveKey (receiveKey: Uint8Array): Uint8Array { | ||
return receiveKey.slice(DECRYPT_KEY_START) | ||
} | ||
function verifyKeyFromSendKey (sendKey: Uint8Array): Uint8Array { | ||
return sendKey.slice(VERIFY_KEY_START, VERIFY_KEY_END) | ||
} | ||
function sendKeyFromReceiveKey (receiveKey: Uint8Array): Uint8Array { | ||
return receiveKey.slice(VERIFY_KEY_START, ENCRYPT_KEY_END) | ||
} | ||
export function setupPrimitives (crypto: ICryptoCore): ICryptoPrimitives { | ||
@@ -39,14 +74,11 @@ class Annonymous implements IAnnonymous { | ||
equals (other: IAnnonymous): boolean { | ||
equals (other: IAnnonymous | ISender | IReceiver): boolean { | ||
return this.compare(other) === 0 | ||
} | ||
compare (other: IAnnonymous, force: boolean = false): number { | ||
if (!(other instanceof Annonymous)) { | ||
compare (other: IAnnonymous | ISender | IReceiver): number { | ||
if (isSender(other) || isReceiver(other)) { | ||
return 1 | ||
} | ||
if (force) { | ||
return bufferCompare(other.id, this.id) | ||
} | ||
return other.compare(this, true) | ||
return bufferCompare(other.id, this.id) | ||
} | ||
@@ -65,3 +97,3 @@ | ||
async verify (signature: Uint8Array, body: Uint8Array): Promise<boolean> { | ||
return crypto.verify(this.id, signature, body) | ||
return await crypto.verify(this.id, signature, body) | ||
} | ||
@@ -71,63 +103,102 @@ | ||
async verifyMessage (message: IEncryptedMessage): Promise<boolean> { | ||
return this.verify(message.signature, message.body) | ||
return await this.verify(message.signature, message.body) | ||
} | ||
} | ||
class Receiver extends Annonymous implements IReceiver { | ||
[receiverFlag]: true | ||
receiveKey: Uint8Array | ||
signKey: Promise<Uint8Array> | ||
_receiveKeyBase64: string | ||
class Sender implements ISender { | ||
[senderFlag]: true | ||
sendKey: Uint8Array | ||
_sendKeyBase64: string | ||
receiveKeyBase64: any | ||
_annonymous: IAnnonymous | ||
_signKey: Uint8Array | ||
_encryptKey: Uint8Array | ||
constructor (opts: IReceiverOptions) { | ||
super({ id: opts.id }) | ||
this[receiverFlag] = true | ||
this.receiveKey = toBuffer(opts.receiveKey) | ||
this.signKey = crypto.deriveAnnonymousKeys(this.receiveKey).then(keys => keys.write) | ||
constructor ({ id, sendKey }: ISenderOptions) { | ||
this[senderFlag] = true | ||
this.sendKey = toBuffer(sendKey) | ||
if (id !== undefined) { | ||
this._annonymous = new Annonymous({ id }) | ||
} | ||
} | ||
get receiveKeyBase64 (): string { | ||
if (this._receiveKeyBase64 === undefined) { | ||
this._receiveKeyBase64 = bufferToString(this.receiveKey, 'base64') | ||
get signKey (): Uint8Array { | ||
if (this._signKey === undefined) { | ||
this._signKey = signKeyFromSendKey(this.sendKey) | ||
} | ||
return this._receiveKeyBase64 | ||
return this._signKey | ||
} | ||
newAnnonymous (): IAnnonymous { | ||
return new Annonymous(this) | ||
get encryptKey (): Uint8Array { | ||
if (this._encryptKey === undefined) { | ||
this._encryptKey = encryptKeyFromSendKey(this.sendKey) | ||
} | ||
return this._encryptKey | ||
} | ||
compare (other: IAnnonymous, force: boolean = false): number { | ||
if (!(other instanceof Receiver)) { | ||
return (force ? -1 : 1) | ||
get sendKeyBase64 (): string { | ||
if (this._sendKeyBase64 === undefined) { | ||
this._sendKeyBase64 = bufferToString(this.sendKey, 'base64') | ||
} | ||
if (force) { | ||
return bufferCompare(other.receiveKey, this.receiveKey) | ||
return this._sendKeyBase64 | ||
} | ||
get sender (): this { | ||
return this | ||
} | ||
get id (): Uint8Array { | ||
return this.annonymous.id | ||
} | ||
get idHex (): string { | ||
return this.annonymous.idHex | ||
} | ||
get idBase64 (): string { | ||
return this.annonymous.idBase64 | ||
} | ||
get annonymous (): IAnnonymous { | ||
if (this._annonymous === undefined) { | ||
this._annonymous = new Annonymous({ id: verifyKeyFromSendKey(this.sendKey) }) | ||
} | ||
return other.compare(this, true) | ||
return this._annonymous | ||
} | ||
toJSON (): IReceiverJSON { | ||
return { | ||
id: this.idBase64, | ||
receiveKey: this.receiveKeyBase64 | ||
equals (other: IAnnonymous | ISender | IReceiver): boolean { | ||
return this.compare(other) === 0 | ||
} | ||
compare (other: IAnnonymous | ISender | IReceiver): number { | ||
if (isReceiver(other)) { | ||
return 1 | ||
} | ||
if (!isSender(other)) { | ||
return -1 | ||
} | ||
return bufferCompare(other.sendKey, this.sendKey) | ||
} | ||
toJSON (): ISenderJSON { | ||
return { sendKey: this.sendKeyBase64 } | ||
} | ||
toString (): string { | ||
return `Receiver[receiveKey=${this.receiveKeyBase64}]` | ||
return `Sender[sendKey=${this.sendKeyBase64}]` | ||
} | ||
async sign (data: Uint8Array): Promise<Uint8Array> { | ||
return crypto.sign(await this.signKey, data) | ||
return await crypto.sign(this.signKey, data) | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
decrypt (encrypted: IEncryptedMessage): ICancelable<IDecryption> { | ||
return cancelable<IDecryption, Receiver>(function * () { | ||
return yield crypto.decryptMessage( | ||
this.id, | ||
yield this.signKey, | ||
this.receiveKey, | ||
encrypted | ||
encrypt (message: IEncodable): ICancelable<IEncryptedMessage> { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable<IEncryptedMessage, Sender>(function * () { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return yield crypto.encryptMessage( | ||
this.signKey, | ||
this.encryptKey, | ||
message | ||
) | ||
@@ -138,55 +209,83 @@ }, this) | ||
class Sender extends Receiver implements ISender { | ||
[senderFlag]: true | ||
sendKey: Uint8Array | ||
_sendKeyBase64: string | ||
receiveKeyBase64: any | ||
class Receiver implements IReceiver { | ||
[receiverFlag]: true | ||
receiveKey: Uint8Array | ||
_receiveKeyBase64: string | ||
_sender: ISender | ||
_annonymous: IAnnonymous | ||
constructor ({ id, sendKey, receiveKey }: ISenderOptions) { | ||
super({ id, receiveKey }) | ||
this[senderFlag] = true | ||
this.sendKey = toBuffer(sendKey) | ||
constructor ({ id, sendKey, receiveKey }: IReceiverOptions) { | ||
this[receiverFlag] = true | ||
this.receiveKey = toBuffer(receiveKey) | ||
if (sendKey !== undefined) { | ||
this._sender = new Sender({ id, sendKey }) | ||
} | ||
} | ||
get sendKeyBase64 (): string { | ||
if (this._sendKeyBase64 === undefined) { | ||
this._sendKeyBase64 = bufferToString(this.sendKey, 'base64') | ||
get sender (): ISender { | ||
if (this._sender === undefined) { | ||
this._sender = new Sender({ sendKey: sendKeyFromReceiveKey(this.receiveKey) }) | ||
} | ||
return this._sendKeyBase64 | ||
return this._sender | ||
} | ||
newReceiver (): IReceiver { | ||
return new Receiver(this) | ||
get id (): Uint8Array { | ||
return this.sender.id | ||
} | ||
compare (other: any, force: boolean = false): number { | ||
if (!(other instanceof Sender)) { | ||
return (force ? -1 : 1) | ||
get idHex (): string { | ||
return this.sender.idHex | ||
} | ||
get idBase64 (): string { | ||
return this.sender.idBase64 | ||
} | ||
get receiver (): this { | ||
return this | ||
} | ||
get annonymous (): IAnnonymous { | ||
return this.sender.annonymous | ||
} | ||
get decryptKey (): Uint8Array { | ||
return decryptKeyFromReceiveKey(this.receiveKey) | ||
} | ||
get receiveKeyBase64 (): string { | ||
if (this._receiveKeyBase64 === undefined) { | ||
this._receiveKeyBase64 = bufferToString(this.receiveKey, 'base64') | ||
} | ||
if (force) { | ||
return bufferCompare(other.sendKey, this.sendKey) | ||
} | ||
return other.compare(this, true) | ||
return this._receiveKeyBase64 | ||
} | ||
toJSON (): ISenderJSON { | ||
return { | ||
id: this.idBase64, | ||
sendKey: this.sendKeyBase64, | ||
receiveKey: this.receiveKeyBase64 | ||
equals (other: IReceiver | ISender | IAnnonymous): boolean { | ||
return this.compare(other) === 0 | ||
} | ||
compare (other: IReceiver | ISender | IAnnonymous): number { | ||
if (!isReceiver(other)) { | ||
return -1 | ||
} | ||
return bufferCompare(other.receiveKey, this.receiveKey) | ||
} | ||
toJSON (): IReceiverJSON { | ||
return { receiveKey: this.receiveKeyBase64 } | ||
} | ||
toString (): string { | ||
return `Sender[sendKey=${this.sendKeyBase64}]` | ||
return `Receiver[receiveKey=${this.receiveKeyBase64}]` | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
encrypt (message: IEncodable): ICancelable<IEncryptedMessage> { | ||
return cancelable<IEncryptedMessage, Sender>(function * () { | ||
return yield crypto.encryptMessage( | ||
this.id, | ||
yield this.signKey, | ||
this.sendKey, | ||
message | ||
decrypt (encrypted: IEncryptedMessage): ICancelable<IDecryption> { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return cancelable<IDecryption, Receiver>(function * () { | ||
return yield crypto.decryptMessage( | ||
this.annonymous.id, | ||
this.sender.encryptKey, | ||
this.decryptKey, | ||
encrypted | ||
) | ||
@@ -202,4 +301,4 @@ }, this) | ||
constructor (opts: IConnectionOptions) { | ||
this.receiver = new Receiver(opts.receiver) | ||
this.sender = new Sender(opts.sender) | ||
this.receiver = (opts.receiver instanceof Receiver) ? opts.receiver : new Receiver(opts.receiver) | ||
this.sender = (opts.sender instanceof Sender) ? opts.sender : new Sender(opts.sender) | ||
} | ||
@@ -215,22 +314,15 @@ | ||
return { | ||
async createReceiverFromReceiveKey (receiveKey: IStringOrBuffer): Promise<IReceiver> { | ||
const syncReceiveKey = toBuffer(receiveKey) | ||
const { read: id } = await crypto.deriveAnnonymousKeys(syncReceiveKey) | ||
return new Receiver({ receiveKey: syncReceiveKey, id }) | ||
async createReceiver (): Promise<IReceiver> { | ||
const [encrypt, sign] = await Promise.all([ | ||
crypto.createEncryptionKeys(), | ||
crypto.createSignKeys() | ||
]) | ||
const sendKey = Buffer.concat([sign.publicKey, sign.privateKey, encrypt.publicKey]) | ||
const receiver = new Receiver({ | ||
id: sign.publicKey, | ||
sendKey, | ||
receiveKey: Buffer.concat([sendKey, encrypt.privateKey]) | ||
}) | ||
return receiver | ||
}, | ||
async createSenderFromSendKey (sendKey: IStringOrBuffer): Promise<ISender> { | ||
const sendKeySync = toBuffer(sendKey) | ||
const receiveKey = await crypto.deriveReadKey(sendKeySync) | ||
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey) | ||
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve | ||
const signKey = Promise.resolve(signKeyValue) | ||
return new Sender({ id, signKey, receiveKey, sendKey: sendKeySync }) | ||
}, | ||
async createSender (): Promise<ISender> { | ||
const { read: receiveKey, write: sendKey } = await crypto.createKeys() | ||
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey) | ||
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve | ||
const signKey = Promise.resolve(signKeyValue) | ||
return new Sender({ id, signKey, receiveKey, sendKey }) | ||
}, | ||
Annonymous, | ||
@@ -237,0 +329,0 @@ Receiver, |
@@ -21,9 +21,15 @@ import { IEncryptedMessage, IDecryption } from './core/types' | ||
export interface IAnnonymous { | ||
export interface IComparable<Base> { | ||
equals(other: Base): boolean | ||
compare(other: Base): number | ||
} | ||
export interface IChannelId { | ||
readonly id: Uint8Array | ||
readonly idBase64: string | ||
readonly idHex: string | ||
} | ||
export interface IAnnonymous extends IComparable<IAnnonymous>, IChannelId { | ||
[annonymousFlag]: true | ||
id: Uint8Array | ||
idBase64: string | ||
readonly idHex: string | ||
equals(other: IAnnonymous): boolean | ||
compare(other: IAnnonymous, _?: boolean): number | ||
toJSON(): IAnnonymousJSON | ||
@@ -34,35 +40,41 @@ verify(signature: Uint8Array, body: Uint8Array): Promise<boolean> | ||
export interface IReceiverJSON extends IAnnonymousJSON { | ||
receiveKey: string | ||
export interface ISenderJSON { | ||
sendKey: string | ||
} | ||
export interface IReceiverOptions extends IAnnonymousOptions { | ||
receiveKey: IStringOrBuffer | ||
signKey?: Promise<Uint8Array> | ||
export interface ISenderOptions { | ||
id?: IStringOrBuffer | ||
sendKey: IStringOrBuffer | ||
} | ||
export interface IReceiver extends IAnnonymous { | ||
[receiverFlag]: true | ||
receiveKey: Uint8Array | ||
signKey: Promise<Uint8Array> | ||
toJSON(): IReceiverJSON | ||
newAnnonymous(): IAnnonymous | ||
export interface ISender extends IComparable<ISender>, IChannelId { | ||
[senderFlag]: true | ||
toJSON(): ISenderJSON | ||
readonly sendKey: Uint8Array | ||
readonly encryptKey: Uint8Array | ||
readonly signKey: Uint8Array | ||
readonly sender: this | ||
readonly annonymous: IAnnonymous | ||
sign(data: Uint8Array): Promise<Uint8Array> | ||
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption> | ||
encrypt(message: IEncodable): ICancelable<IEncryptedMessage> | ||
} | ||
export interface ISenderJSON extends IReceiverJSON { | ||
sendKey: string | ||
export interface IReceiverJSON { | ||
receiveKey: string | ||
} | ||
export interface ISenderOptions extends IReceiverOptions { | ||
sendKey: IStringOrBuffer | ||
export interface IReceiverOptions { | ||
id?: IStringOrBuffer | ||
sendKey?: IStringOrBuffer | ||
receiveKey: IStringOrBuffer | ||
} | ||
export interface ISender extends IReceiver { | ||
[senderFlag]: true | ||
sendKey: Uint8Array | ||
toJSON(): ISenderJSON | ||
newReceiver(): IReceiver | ||
encrypt(message: IEncodable): ICancelable<IEncryptedMessage> | ||
export interface IReceiver extends IComparable<IReceiver>, IChannelId { | ||
[receiverFlag]: true | ||
readonly receiveKey: Uint8Array | ||
readonly receiver: this | ||
readonly sender: ISender | ||
readonly annonymous: IAnnonymous | ||
toJSON(): IReceiverJSON | ||
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption> | ||
} | ||
@@ -89,3 +101,3 @@ | ||
firstMessage: string | ||
confirmKey: string | ||
handshakeSecret: string | ||
} | ||
@@ -96,3 +108,3 @@ | ||
firstMessage: IStringOrBuffer | ||
confirmKey: IStringOrBuffer | ||
handshakeSecret: IStringOrBuffer | ||
} | ||
@@ -103,3 +115,3 @@ | ||
firstMessage: Uint8Array | ||
confirmKey: Uint8Array | ||
handshakeSecret: Uint8Array | ||
toJSON(): IHandshakeInitJSON | ||
@@ -145,5 +157,3 @@ confirm(acceptMessage: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation> | ||
export interface ICryptoPrimitives { | ||
createReceiverFromReceiveKey (receiveKey: IStringOrBuffer): Promise<IReceiver> | ||
createSenderFromSendKey (sendKey: IStringOrBuffer): Promise<ISender> | ||
createSender(): Promise<ISender> | ||
createReceiver(): Promise<IReceiver> | ||
Annonymous: new (opts: IAnnonymousOptions) => IAnnonymous | ||
@@ -150,0 +160,0 @@ Receiver: new (opts: IReceiverOptions) => IReceiver |
@@ -13,18 +13,16 @@ declare module 'sodium-universal' { | ||
readonly crypto_sign_BYTES: number | ||
readonly crypto_scalarmult_ed25519_BYTES: number | ||
readonly crypto_secretbox_NONCEBYTES: number | ||
readonly crypto_secretbox_KEYBYTES: number | ||
readonly crypto_secretbox_MACBYTES: number | ||
readonly crypto_scalarmult_BYTES: number | ||
crypto_kdf_derive_from_key(derivedKey: Uint8Array, index: number, deriveContext: Uint8Array, key: Uint8Array): void | ||
crypto_scalarmult_base(pk: Uint8Array, sk: Uint8Array): void | ||
crypto_scalarmult(secret: Uint8Array, sk: Uint8Array, remotePk: Uint8Array): void | ||
crypto_sign_ed25519_sk_to_curve25519(sk: Uint8Array, pk: Uint8Array): void | ||
crypto_sign_ed25519_pk_to_curve25519(pk: Uint8Array, sk: Uint8Array): void | ||
crypto_sign_seed_keypair(pk: Uint8Array, sk: Uint8Array, readKey: Uint8Array): void | ||
crypto_sign_detached(signature: Uint8Array, body: Uint8Array, signSecretKey: Uint8Array): void | ||
crypto_sign_verify_detached(signature: Uint8Array, body: Uint8Array, signPublicKey: Uint8Array): boolean | ||
crypto_sign_ed25519_sk_to_pk(sk: Uint8Array, pk: Uint8Array): void | ||
crypto_box_seal(messageEncrypted: Uint8Array, message: Uint8Array, pk: Uint8Array): void | ||
crypto_box_seal_open(messageDecrypted: Uint8Array, messageEncrypted: Uint8Array, pk: Uint8Array, sk: Uint8Array): boolean | ||
crypto_sign_keypair(pk: Uint8Array, sk: Uint8Array): void | ||
crypto_box_keypair(pk: Uint8Array, sk: Uint8Array): void | ||
randombytes_buf(buffer: Buffer): void | ||
@@ -31,0 +29,0 @@ crypto_secretbox_easy(ciphertext: Uint8Array, message: Uint8Array, nonce: Uint8Array, secretKey: Uint8Array): void |
@@ -0,1 +1,3 @@ | ||
/* eslint-disable @typescript-eslint/no-throw-literal */ | ||
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841 | ||
import { Buffer } from 'buffer' | ||
@@ -2,0 +4,0 @@ export { Buffer } from 'buffer' |
@@ -0,1 +1,3 @@ | ||
/* eslint-disable @typescript-eslint/promise-function-async */ | ||
/* eslint-disable @typescript-eslint/return-await */ | ||
export interface ICancelable <T = any> extends Promise<T> { | ||
@@ -128,3 +130,2 @@ name?: string | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
then <TResult3 = TReturn, TResult4 = never> (onfulfilled?: ((value: TReturn) => TResult3 | PromiseLike<TResult3>) | undefined | null, onrejected?: ((reason: any) => TResult4 | PromiseLike<TResult4>) | undefined | null): ICancelable<TResult3 | TResult4> { | ||
@@ -143,3 +144,3 @@ const next = new CancelableWrap(onfulfilled, onrejected) | ||
} | ||
next.cancel = async (): Promise<void> => this.cancel() | ||
next.cancel = (): Promise<void> => this.cancel() | ||
} else if (this._done === TDone.ok) { | ||
@@ -153,9 +154,6 @@ next._receiveData(this._data) | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
catch <TResult3> (onrejected?: ((reason: any) => TResult3 | PromiseLike<TResult3>) | undefined | null): ICancelable<TResult3> { | ||
// @ts-ignore TS2322 | ||
return this.then(null, onrejected) | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
finally (onfinally?: (() => void | PromiseLike<void>) | undefined | null): ICancelable<TReturn> { | ||
@@ -182,5 +180,3 @@ if (typeof onfinally !== 'function') { | ||
return res.then( | ||
// @ts-ignore | ||
async () => Promise.reject(error), | ||
// @ts-ignore | ||
async () => Promise.reject(error) | ||
@@ -268,3 +264,2 @@ ) | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
export function cancelable <TReturn = any, TScope = undefined, T = any> (generator: TCancelable<TReturn, TScope, T>, scope?: TScope, name?: string): ICancelable<TReturn> { | ||
@@ -279,3 +274,2 @@ return new Cancelable(generator, scope, name) | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
iter = generator.call(scope, (child: ICancelable): ICancelable => { | ||
@@ -300,3 +294,2 @@ if (this._done !== TDone.not) { | ||
if (this._done !== TDone.not) return | ||
// @ts-ignore TS2314 | ||
let data: IteratorResult<T, TReturn> | ||
@@ -328,7 +321,5 @@ try { | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
export function abortCancelable <T> (template: (signal: AbortSignal) => Promise<T>, name?: string): ICancelable<T> { | ||
const controller = new AbortController() | ||
return new SplitCancelable({ | ||
// eslint-disable-next-line @typescript-eslint/require-await | ||
cancel: async (): Promise<void> => controller.abort(), | ||
@@ -340,3 +331,2 @@ promise: template(controller.signal), | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
export function splitCancelable <T> (split: ISplitCancelable<T>): ICancelable<T> { | ||
@@ -343,0 +333,0 @@ return new SplitCancelable(split) |
@@ -16,3 +16,4 @@ export interface IExtPromise<T> extends Promise<T> { | ||
result._reject = _reject | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return result | ||
} |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable @typescript-eslint/return-await */ | ||
import { isPromiseLike } from './isPromiseLike' | ||
@@ -6,5 +7,14 @@ import { isObject } from './isObject' | ||
export function toPromise<T> (input: T | PromiseLike<T>): PromiseLike<T> { | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
export function toPromise<T> (input: T | PromiseLike<T>): Promise<T> { | ||
if (isPromiseLike(input)) { | ||
return input | ||
if (input instanceof Promise) { | ||
return input | ||
} | ||
let promise = cache.get(input) | ||
if (promise === undefined) { | ||
promise = new Promise((resolve, reject) => { input.then(resolve, reject) }) | ||
cache.set(input, promise) | ||
} | ||
return promise | ||
} | ||
@@ -11,0 +21,0 @@ if (isObject(input)) { |
@@ -15,9 +15,13 @@ import { IEncryptedMessage, IDecryption } from './core/types'; | ||
} | ||
export interface IAnnonymous { | ||
export interface IComparable<Base> { | ||
equals(other: Base): boolean; | ||
compare(other: Base): number; | ||
} | ||
export interface IChannelId { | ||
readonly id: Uint8Array; | ||
readonly idBase64: string; | ||
readonly idHex: string; | ||
} | ||
export interface IAnnonymous extends IComparable<IAnnonymous>, IChannelId { | ||
[annonymousFlag]: true; | ||
id: Uint8Array; | ||
idBase64: string; | ||
readonly idHex: string; | ||
equals(other: IAnnonymous): boolean; | ||
compare(other: IAnnonymous, _?: boolean): number; | ||
toJSON(): IAnnonymousJSON; | ||
@@ -27,31 +31,37 @@ verify(signature: Uint8Array, body: Uint8Array): Promise<boolean>; | ||
} | ||
export interface IReceiverJSON extends IAnnonymousJSON { | ||
export interface ISenderJSON { | ||
sendKey: string; | ||
} | ||
export interface ISenderOptions { | ||
id?: IStringOrBuffer; | ||
sendKey: IStringOrBuffer; | ||
} | ||
export interface ISender extends IComparable<ISender>, IChannelId { | ||
[senderFlag]: true; | ||
toJSON(): ISenderJSON; | ||
readonly sendKey: Uint8Array; | ||
readonly encryptKey: Uint8Array; | ||
readonly signKey: Uint8Array; | ||
readonly sender: this; | ||
readonly annonymous: IAnnonymous; | ||
sign(data: Uint8Array): Promise<Uint8Array>; | ||
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>; | ||
} | ||
export interface IReceiverJSON { | ||
receiveKey: string; | ||
} | ||
export interface IReceiverOptions extends IAnnonymousOptions { | ||
export interface IReceiverOptions { | ||
id?: IStringOrBuffer; | ||
sendKey?: IStringOrBuffer; | ||
receiveKey: IStringOrBuffer; | ||
signKey?: Promise<Uint8Array>; | ||
} | ||
export interface IReceiver extends IAnnonymous { | ||
export interface IReceiver extends IComparable<IReceiver>, IChannelId { | ||
[receiverFlag]: true; | ||
receiveKey: Uint8Array; | ||
signKey: Promise<Uint8Array>; | ||
readonly receiveKey: Uint8Array; | ||
readonly receiver: this; | ||
readonly sender: ISender; | ||
readonly annonymous: IAnnonymous; | ||
toJSON(): IReceiverJSON; | ||
newAnnonymous(): IAnnonymous; | ||
sign(data: Uint8Array): Promise<Uint8Array>; | ||
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption>; | ||
} | ||
export interface ISenderJSON extends IReceiverJSON { | ||
sendKey: string; | ||
} | ||
export interface ISenderOptions extends IReceiverOptions { | ||
sendKey: IStringOrBuffer; | ||
} | ||
export interface ISender extends IReceiver { | ||
[senderFlag]: true; | ||
sendKey: Uint8Array; | ||
toJSON(): ISenderJSON; | ||
newReceiver(): IReceiver; | ||
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>; | ||
} | ||
export interface IConnectionJSON { | ||
@@ -73,3 +83,3 @@ receiver: IReceiverJSON; | ||
firstMessage: string; | ||
confirmKey: string; | ||
handshakeSecret: string; | ||
} | ||
@@ -79,3 +89,3 @@ export interface IHandshakeInitOptions { | ||
firstMessage: IStringOrBuffer; | ||
confirmKey: IStringOrBuffer; | ||
handshakeSecret: IStringOrBuffer; | ||
} | ||
@@ -85,3 +95,3 @@ export interface IHandshakeInit { | ||
firstMessage: Uint8Array; | ||
confirmKey: Uint8Array; | ||
handshakeSecret: Uint8Array; | ||
toJSON(): IHandshakeInitJSON; | ||
@@ -119,5 +129,3 @@ confirm(acceptMessage: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation>; | ||
export interface ICryptoPrimitives { | ||
createReceiverFromReceiveKey(receiveKey: IStringOrBuffer): Promise<IReceiver>; | ||
createSenderFromSendKey(sendKey: IStringOrBuffer): Promise<ISender>; | ||
createSender(): Promise<ISender>; | ||
createReceiver(): Promise<IReceiver>; | ||
Annonymous: new (opts: IAnnonymousOptions) => IAnnonymous; | ||
@@ -124,0 +132,0 @@ Receiver: new (opts: IReceiverOptions) => IReceiver; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable @typescript-eslint/no-throw-literal */ | ||
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841 | ||
const buffer_1 = require("buffer"); | ||
@@ -4,0 +6,0 @@ var buffer_2 = require("buffer"); |
@@ -102,3 +102,2 @@ "use strict"; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
then(onfulfilled, onrejected) { | ||
@@ -119,3 +118,3 @@ const next = new CancelableWrap(onfulfilled, onrejected); | ||
} | ||
next.cancel = async () => this.cancel(); | ||
next.cancel = () => this.cancel(); | ||
} | ||
@@ -130,8 +129,5 @@ else if (this._done === TDone.ok) { | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
catch(onrejected) { | ||
// @ts-ignore TS2322 | ||
return this.then(null, onrejected); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
finally(onfinally) { | ||
@@ -156,7 +152,3 @@ if (typeof onfinally !== 'function') { | ||
if (isPromiseLike(res)) { | ||
return res.then( | ||
// @ts-ignore | ||
async () => Promise.reject(error), | ||
// @ts-ignore | ||
async () => Promise.reject(error)); | ||
return res.then(async () => Promise.reject(error), async () => Promise.reject(error)); | ||
} | ||
@@ -235,3 +227,2 @@ throw error; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
function cancelable(generator, scope, name) { | ||
@@ -246,3 +237,2 @@ return new Cancelable(generator, scope, name); | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
iter = generator.call(scope, (child) => { | ||
@@ -269,3 +259,2 @@ if (this._done !== TDone.not) { | ||
return; | ||
// @ts-ignore TS2314 | ||
let data; | ||
@@ -297,7 +286,5 @@ try { | ||
} | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
function abortCancelable(template, name) { | ||
const controller = new AbortController(); | ||
return new SplitCancelable({ | ||
// eslint-disable-next-line @typescript-eslint/require-await | ||
cancel: async () => controller.abort(), | ||
@@ -309,3 +296,2 @@ promise: template(controller.signal), | ||
exports.abortCancelable = abortCancelable; | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
function splitCancelable(split) { | ||
@@ -312,0 +298,0 @@ return new SplitCancelable(split); |
@@ -13,2 +13,3 @@ "use strict"; | ||
result._reject = _reject; | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return result; | ||
@@ -15,0 +16,0 @@ } |
@@ -1,1 +0,1 @@ | ||
export declare function toPromise<T>(input: T | PromiseLike<T>): PromiseLike<T>; | ||
export declare function toPromise<T>(input: T | PromiseLike<T>): Promise<T>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable @typescript-eslint/return-await */ | ||
const isPromiseLike_1 = require("./isPromiseLike"); | ||
const isObject_1 = require("./isObject"); | ||
const cache = new WeakMap(); | ||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
function toPromise(input) { | ||
if (isPromiseLike_1.isPromiseLike(input)) { | ||
return input; | ||
if (input instanceof Promise) { | ||
return input; | ||
} | ||
let promise = cache.get(input); | ||
if (promise === undefined) { | ||
promise = new Promise((resolve, reject) => { input.then(resolve, reject); }); | ||
cache.set(input, promise); | ||
} | ||
return promise; | ||
} | ||
@@ -10,0 +20,0 @@ if (isObject_1.isObject(input)) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
180
142885
2760
Updatedbuffer@^5.6.0