Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fbea5a8f8 | ||
|
|
6a5805234f | ||
|
|
de6728487e | ||
|
|
f5a838f1cc | ||
|
|
af5f9653d6 | ||
|
|
d6e55c2e33 | ||
|
|
a80285cc83 | ||
|
|
d08705329a | ||
|
|
5679fe7a49 | ||
|
|
c95f5882a9 | ||
|
|
b5514743fb | ||
|
|
cd2042f9ce | ||
|
|
a39e38038a | ||
|
|
f1e22f66a3 | ||
|
|
6154353cd9 | ||
|
|
dbf8c26967 | ||
|
|
beb11f0292 | ||
|
|
70eb5c5494 | ||
|
|
5d579e93fc | ||
|
|
3d72df72c0 | ||
|
|
b6c3093945 | ||
|
|
f308236941 | ||
|
|
1fe18c3384 | ||
|
|
b65f69af6e | ||
|
|
cee3b82317 | ||
|
|
e68e17c861 | ||
|
|
2657f00c98 | ||
|
|
b45ace4d58 | ||
|
|
ee00f080f4 | ||
|
|
63d2536263 | ||
|
|
b0ed2e5e4f | ||
|
|
3607679e93 | ||
|
|
b77842c30e | ||
|
|
b01ac22eb9 | ||
|
|
3c0d6dc24b | ||
|
|
963a424451 | ||
|
|
17fdde0091 | ||
|
|
538c7aecce | ||
|
|
8334fa5699 | ||
|
|
7bc356ac15 | ||
|
|
861fc80580 | ||
|
|
8df967ab64 | ||
|
|
34eeb93470 |
@ -1,10 +1,10 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '6'
|
||||
install:
|
||||
- npm install
|
||||
- npm install
|
||||
script:
|
||||
- npm test
|
||||
- npm test
|
||||
env:
|
||||
global:
|
||||
- secure: rdRRKiD0Ndfcy66gFOJP/8FZhx9bVk1VDUnMnavyLMbOKKV2jH4qkoFlYqr73D/EDADL8QepsKdGc51VtYewED2Ki98KNv+CmoXPfURqj97mAH3HycV4soinqC46elEpcIbhoOL2skyBRv8F2VwRyWzQiHKTlXrkL4anxzfF0xyVAo07Sy010AOgCLHU+j+kg1VTSwKtUSHJY5zunX+oNDJVQTPGKtWJ4eODggLv4eSRI8+fu9Z/AA+tV5BBU1d7Ey3GY9TD0Ady4HMZmvGGIQ76M6ULb++cXlAOGLR9Vv4YeCS1TnhLoZQGEJ+UFRR1hpVF4m3ignhqSkJ5+lvpFQAAKg0gS0GwNseR2XFNGusLwyUazQRk7u00s808lJ5GutL+rLGM2eZCAZprwe2SMxrAW5GLm6u/YMZycxGyBA/ikP11X9v5Zx1m6bNRJdRmfRiPFD5Il+Q29i1DWVVawvjkrcRH9GPtNxES64jS0K7hU28DQYq2vgWEP5AY6Uwsz2bK0wEswfffk4VDFps73cx39EMRH3xP4PpIRxsGddfYejcBH+9rGH+eaHzpQ8Q3zNsn7muYjZXcVPIu6Pze5mUmsox++Kq2llTXTy/WJ6MeDv2E/6AE7ArXs61E1lKDb+vcciWRBuD9gy5SaFQ6RJ/3cn4QLCWXNw4TUabeYrE=
|
||||
|
||||
15
README.md
15
README.md
@ -1,7 +1,12 @@
|
||||
#libsignal-protocol-javascript
|
||||
**Deprecation Warning**: It is recommended that the TypeScript interface of [libsignal-client](https://github.com/signalapp/libsignal-client) be used for all new applications. This library is no longer used by us or maintained.
|
||||
|
||||
# libsignal-protocol-javascript
|
||||
|
||||
[](https://travis-ci.org/signalapp/libsignal-protocol-javascript)
|
||||
|
||||
|
||||
Signal Protocol implementation for the browser based on
|
||||
[libsignal-protocol-java](https://github.com/WhisperSystems/libsignal-protocol-java).
|
||||
[libsignal-protocol-java](https://github.com/signalapp/libsignal-protocol-java).
|
||||
|
||||
```
|
||||
/dist # Distributables
|
||||
@ -112,7 +117,7 @@ var store = new MySignalProtocolStore();
|
||||
var address = new libsignal.SignalProtocolAddress(recipientId, deviceId);
|
||||
|
||||
// Instantiate a SessionBuilder for a remote recipientId + deviceId tuple.
|
||||
SessionBuilder sessionBuilder = new libsignal.SessionBuilder(store, address);
|
||||
var sessionBuilder = new libsignal.SessionBuilder(store, address);
|
||||
|
||||
// Process a prekey fetched from the server. Returns a promise that resolves
|
||||
// once a session is created and saved in the store, or rejects if the
|
||||
@ -181,7 +186,7 @@ sessionCipher.decryptWhisperMessage(ciphertext).then(function(plaintext) {
|
||||
|
||||
## Building
|
||||
|
||||
To compile curve25519 from C souce files in `/native`, install
|
||||
To compile curve25519 from C source files in `/native`, install
|
||||
[emscripten](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html).
|
||||
|
||||
```
|
||||
@ -190,6 +195,6 @@ grunt compile
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2015-2016 Open Whisper Systems
|
||||
Copyright 2015-2018 Open Whisper Systems
|
||||
|
||||
Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
@ -47,21 +47,18 @@
|
||||
/**
|
||||
* The low 32 bits as a signed value.
|
||||
* @type {number}
|
||||
* @expose
|
||||
*/
|
||||
this.low = low | 0;
|
||||
|
||||
/**
|
||||
* The high 32 bits as a signed value.
|
||||
* @type {number}
|
||||
* @expose
|
||||
*/
|
||||
this.high = high | 0;
|
||||
|
||||
/**
|
||||
* Whether unsigned or not.
|
||||
* @type {boolean}
|
||||
* @expose
|
||||
*/
|
||||
this.unsigned = !!unsigned;
|
||||
}
|
||||
@ -87,10 +84,9 @@
|
||||
* An indicator used to reliably determine if an object is a Long or not.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
* @expose
|
||||
* @private
|
||||
*/
|
||||
Long.__isLong__;
|
||||
Long.prototype.__isLong__;
|
||||
|
||||
Object.defineProperty(Long.prototype, "__isLong__", {
|
||||
value: true,
|
||||
@ -113,7 +109,6 @@
|
||||
* @function
|
||||
* @param {*} obj Object
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
Long.isLong = isLong;
|
||||
|
||||
@ -170,7 +165,6 @@
|
||||
* @param {number} value The 32 bit integer in question
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromInt = fromInt;
|
||||
|
||||
@ -205,7 +199,6 @@
|
||||
* @param {number} value The number in question
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromNumber = fromNumber;
|
||||
|
||||
@ -228,7 +221,6 @@
|
||||
* @param {number} highBits The high 32 bits
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromBits = fromBits;
|
||||
|
||||
@ -298,7 +290,6 @@
|
||||
* @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @param {number=} radix The radix in which the text is written (2-36), defaults to 10
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromString = fromString;
|
||||
|
||||
@ -324,7 +315,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.fromValue = fromValue;
|
||||
|
||||
@ -382,7 +372,6 @@
|
||||
/**
|
||||
* Signed zero.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.ZERO = ZERO;
|
||||
|
||||
@ -395,7 +384,6 @@
|
||||
/**
|
||||
* Unsigned zero.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.UZERO = UZERO;
|
||||
|
||||
@ -408,7 +396,6 @@
|
||||
/**
|
||||
* Signed one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.ONE = ONE;
|
||||
|
||||
@ -421,7 +408,6 @@
|
||||
/**
|
||||
* Unsigned one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.UONE = UONE;
|
||||
|
||||
@ -434,7 +420,6 @@
|
||||
/**
|
||||
* Signed negative one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.NEG_ONE = NEG_ONE;
|
||||
|
||||
@ -447,7 +432,6 @@
|
||||
/**
|
||||
* Maximum signed value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MAX_VALUE = MAX_VALUE;
|
||||
|
||||
@ -460,7 +444,6 @@
|
||||
/**
|
||||
* Maximum unsigned value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
|
||||
|
||||
@ -473,7 +456,6 @@
|
||||
/**
|
||||
* Minimum signed value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MIN_VALUE = MIN_VALUE;
|
||||
|
||||
@ -486,7 +468,6 @@
|
||||
/**
|
||||
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toInt = function toInt() {
|
||||
return this.unsigned ? this.low >>> 0 : this.low;
|
||||
@ -495,7 +476,6 @@
|
||||
/**
|
||||
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toNumber = function toNumber() {
|
||||
if (this.unsigned)
|
||||
@ -509,7 +489,6 @@
|
||||
* @returns {string}
|
||||
* @override
|
||||
* @throws {RangeError} If `radix` is out of range
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toString = function toString(radix) {
|
||||
radix = radix || 10;
|
||||
@ -552,7 +531,6 @@
|
||||
/**
|
||||
* Gets the high 32 bits as a signed integer.
|
||||
* @returns {number} Signed high bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getHighBits = function getHighBits() {
|
||||
return this.high;
|
||||
@ -561,7 +539,6 @@
|
||||
/**
|
||||
* Gets the high 32 bits as an unsigned integer.
|
||||
* @returns {number} Unsigned high bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
|
||||
return this.high >>> 0;
|
||||
@ -570,7 +547,6 @@
|
||||
/**
|
||||
* Gets the low 32 bits as a signed integer.
|
||||
* @returns {number} Signed low bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getLowBits = function getLowBits() {
|
||||
return this.low;
|
||||
@ -579,7 +555,6 @@
|
||||
/**
|
||||
* Gets the low 32 bits as an unsigned integer.
|
||||
* @returns {number} Unsigned low bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
|
||||
return this.low >>> 0;
|
||||
@ -588,7 +563,6 @@
|
||||
/**
|
||||
* Gets the number of bits needed to represent the absolute value of this Long.
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
|
||||
if (this.isNegative()) // Unsigned Longs are never negative
|
||||
@ -603,7 +577,6 @@
|
||||
/**
|
||||
* Tests if this Long's value equals zero.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isZero = function isZero() {
|
||||
return this.high === 0 && this.low === 0;
|
||||
@ -612,7 +585,6 @@
|
||||
/**
|
||||
* Tests if this Long's value is negative.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isNegative = function isNegative() {
|
||||
return !this.unsigned && this.high < 0;
|
||||
@ -621,7 +593,6 @@
|
||||
/**
|
||||
* Tests if this Long's value is positive.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isPositive = function isPositive() {
|
||||
return this.unsigned || this.high >= 0;
|
||||
@ -630,7 +601,6 @@
|
||||
/**
|
||||
* Tests if this Long's value is odd.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isOdd = function isOdd() {
|
||||
return (this.low & 1) === 1;
|
||||
@ -639,7 +609,6 @@
|
||||
/**
|
||||
* Tests if this Long's value is even.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isEven = function isEven() {
|
||||
return (this.low & 1) === 0;
|
||||
@ -649,7 +618,6 @@
|
||||
* Tests if this Long's value equals the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.equals = function equals(other) {
|
||||
if (!isLong(other))
|
||||
@ -664,7 +632,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.eq = LongPrototype.equals;
|
||||
|
||||
@ -672,7 +639,6 @@
|
||||
* Tests if this Long's value differs from the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.notEquals = function notEquals(other) {
|
||||
return !this.eq(/* validates */ other);
|
||||
@ -683,7 +649,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.neq = LongPrototype.notEquals;
|
||||
|
||||
@ -691,7 +656,6 @@
|
||||
* Tests if this Long's value is less than the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lessThan = function lessThan(other) {
|
||||
return this.comp(/* validates */ other) < 0;
|
||||
@ -702,7 +666,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lt = LongPrototype.lessThan;
|
||||
|
||||
@ -710,7 +673,6 @@
|
||||
* Tests if this Long's value is less than or equal the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
|
||||
return this.comp(/* validates */ other) <= 0;
|
||||
@ -721,7 +683,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lte = LongPrototype.lessThanOrEqual;
|
||||
|
||||
@ -729,7 +690,6 @@
|
||||
* Tests if this Long's value is greater than the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.greaterThan = function greaterThan(other) {
|
||||
return this.comp(/* validates */ other) > 0;
|
||||
@ -740,7 +700,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.gt = LongPrototype.greaterThan;
|
||||
|
||||
@ -748,7 +707,6 @@
|
||||
* Tests if this Long's value is greater than or equal the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
|
||||
return this.comp(/* validates */ other) >= 0;
|
||||
@ -759,7 +717,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.gte = LongPrototype.greaterThanOrEqual;
|
||||
|
||||
@ -768,7 +725,6 @@
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
|
||||
* if the given one is greater
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.compare = function compare(other) {
|
||||
if (!isLong(other))
|
||||
@ -794,14 +750,12 @@
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
|
||||
* if the given one is greater
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.comp = LongPrototype.compare;
|
||||
|
||||
/**
|
||||
* Negates this Long's value.
|
||||
* @returns {!Long} Negated Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.negate = function negate() {
|
||||
if (!this.unsigned && this.eq(MIN_VALUE))
|
||||
@ -813,7 +767,6 @@
|
||||
* Negates this Long's value. This is an alias of {@link Long#negate}.
|
||||
* @function
|
||||
* @returns {!Long} Negated Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.neg = LongPrototype.negate;
|
||||
|
||||
@ -821,7 +774,6 @@
|
||||
* Returns the sum of this and the specified Long.
|
||||
* @param {!Long|number|string} addend Addend
|
||||
* @returns {!Long} Sum
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.add = function add(addend) {
|
||||
if (!isLong(addend))
|
||||
@ -858,7 +810,6 @@
|
||||
* Returns the difference of this and the specified Long.
|
||||
* @param {!Long|number|string} subtrahend Subtrahend
|
||||
* @returns {!Long} Difference
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.subtract = function subtract(subtrahend) {
|
||||
if (!isLong(subtrahend))
|
||||
@ -871,7 +822,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} subtrahend Subtrahend
|
||||
* @returns {!Long} Difference
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.sub = LongPrototype.subtract;
|
||||
|
||||
@ -879,7 +829,6 @@
|
||||
* Returns the product of this and the specified Long.
|
||||
* @param {!Long|number|string} multiplier Multiplier
|
||||
* @returns {!Long} Product
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.multiply = function multiply(multiplier) {
|
||||
if (this.isZero())
|
||||
@ -947,7 +896,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} multiplier Multiplier
|
||||
* @returns {!Long} Product
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.mul = LongPrototype.multiply;
|
||||
|
||||
@ -956,7 +904,6 @@
|
||||
* unsigned if this Long is unsigned.
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Quotient
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.divide = function divide(divisor) {
|
||||
if (!isLong(divisor))
|
||||
@ -967,6 +914,8 @@
|
||||
return this.unsigned ? UZERO : ZERO;
|
||||
var approx, rem, res;
|
||||
if (!this.unsigned) {
|
||||
// This section is only relevant for signed longs and is derived from the
|
||||
// closure library as a whole.
|
||||
if (this.eq(MIN_VALUE)) {
|
||||
if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
|
||||
return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
|
||||
@ -992,19 +941,18 @@
|
||||
return this.neg().div(divisor).neg();
|
||||
} else if (divisor.isNegative())
|
||||
return this.div(divisor.neg()).neg();
|
||||
} else if (!divisor.unsigned)
|
||||
divisor = divisor.toUnsigned();
|
||||
|
||||
// The algorithm below has not been made for unsigned longs. It's therefore
|
||||
// required to take special care of the MSB prior to running it.
|
||||
if (this.unsigned) {
|
||||
res = ZERO;
|
||||
} else {
|
||||
// The algorithm below has not been made for unsigned longs. It's therefore
|
||||
// required to take special care of the MSB prior to running it.
|
||||
if (!divisor.unsigned)
|
||||
divisor = divisor.toUnsigned();
|
||||
if (divisor.gt(this))
|
||||
return UZERO;
|
||||
if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
|
||||
return UONE;
|
||||
res = UZERO;
|
||||
} else
|
||||
res = ZERO;
|
||||
}
|
||||
|
||||
// Repeat the following until the remainder is less than other: find a
|
||||
// floating-point that approximates remainder / other *from below*, add this
|
||||
@ -1048,7 +996,6 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Quotient
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.div = LongPrototype.divide;
|
||||
|
||||
@ -1056,7 +1003,6 @@
|
||||
* Returns this Long modulo the specified.
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Remainder
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.modulo = function modulo(divisor) {
|
||||
if (!isLong(divisor))
|
||||
@ -1069,14 +1015,12 @@
|
||||
* @function
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Remainder
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.mod = LongPrototype.modulo;
|
||||
|
||||
/**
|
||||
* Returns the bitwise NOT of this Long.
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.not = function not() {
|
||||
return fromBits(~this.low, ~this.high, this.unsigned);
|
||||
@ -1086,7 +1030,6 @@
|
||||
* Returns the bitwise AND of this Long and the specified.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.and = function and(other) {
|
||||
if (!isLong(other))
|
||||
@ -1098,7 +1041,6 @@
|
||||
* Returns the bitwise OR of this Long and the specified.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.or = function or(other) {
|
||||
if (!isLong(other))
|
||||
@ -1110,7 +1052,6 @@
|
||||
* Returns the bitwise XOR of this Long and the given one.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.xor = function xor(other) {
|
||||
if (!isLong(other))
|
||||
@ -1122,7 +1063,6 @@
|
||||
* Returns this Long with bits shifted to the left by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftLeft = function shiftLeft(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -1140,7 +1080,6 @@
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shl = LongPrototype.shiftLeft;
|
||||
|
||||
@ -1148,7 +1087,6 @@
|
||||
* Returns this Long with bits arithmetically shifted to the right by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftRight = function shiftRight(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -1166,7 +1104,6 @@
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shr = LongPrototype.shiftRight;
|
||||
|
||||
@ -1174,7 +1111,6 @@
|
||||
* Returns this Long with bits logically shifted to the right by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -1199,14 +1135,12 @@
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shru = LongPrototype.shiftRightUnsigned;
|
||||
|
||||
/**
|
||||
* Converts this Long to signed.
|
||||
* @returns {!Long} Signed long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toSigned = function toSigned() {
|
||||
if (!this.unsigned)
|
||||
@ -1217,7 +1151,6 @@
|
||||
/**
|
||||
* Converts this Long to unsigned.
|
||||
* @returns {!Long} Unsigned long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toUnsigned = function toUnsigned() {
|
||||
if (this.unsigned)
|
||||
@ -1225,6 +1158,53 @@
|
||||
return fromBits(this.low, this.high, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this Long to its byte representation.
|
||||
* @param {boolean=} le Whether little or big endian, defaults to big endian
|
||||
* @returns {!Array.<number>} Byte representation
|
||||
*/
|
||||
LongPrototype.toBytes = function(le) {
|
||||
return le ? this.toBytesLE() : this.toBytesBE();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this Long to its little endian byte representation.
|
||||
* @returns {!Array.<number>} Little endian byte representation
|
||||
*/
|
||||
LongPrototype.toBytesLE = function() {
|
||||
var hi = this.high,
|
||||
lo = this.low;
|
||||
return [
|
||||
lo & 0xff,
|
||||
(lo >>> 8) & 0xff,
|
||||
(lo >>> 16) & 0xff,
|
||||
(lo >>> 24) & 0xff,
|
||||
hi & 0xff,
|
||||
(hi >>> 8) & 0xff,
|
||||
(hi >>> 16) & 0xff,
|
||||
(hi >>> 24) & 0xff
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this Long to its big endian byte representation.
|
||||
* @returns {!Array.<number>} Big endian byte representation
|
||||
*/
|
||||
LongPrototype.toBytesBE = function() {
|
||||
var hi = this.high,
|
||||
lo = this.low;
|
||||
return [
|
||||
(hi >>> 24) & 0xff,
|
||||
(hi >>> 16) & 0xff,
|
||||
(hi >>> 8) & 0xff,
|
||||
hi & 0xff,
|
||||
(lo >>> 24) & 0xff,
|
||||
(lo >>> 16) & 0xff,
|
||||
(lo >>> 8) & 0xff,
|
||||
lo & 0xff
|
||||
];
|
||||
}
|
||||
|
||||
return Long;
|
||||
});
|
||||
|
||||
|
||||
321
dist/libsignal-protocol.js
vendored
321
dist/libsignal-protocol.js
vendored
@ -25399,21 +25399,18 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* The low 32 bits as a signed value.
|
||||
* @type {number}
|
||||
* @expose
|
||||
*/
|
||||
this.low = low | 0;
|
||||
|
||||
/**
|
||||
* The high 32 bits as a signed value.
|
||||
* @type {number}
|
||||
* @expose
|
||||
*/
|
||||
this.high = high | 0;
|
||||
|
||||
/**
|
||||
* Whether unsigned or not.
|
||||
* @type {boolean}
|
||||
* @expose
|
||||
*/
|
||||
this.unsigned = !!unsigned;
|
||||
}
|
||||
@ -25439,10 +25436,9 @@ Curve25519Worker.prototype = {
|
||||
* An indicator used to reliably determine if an object is a Long or not.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
* @expose
|
||||
* @private
|
||||
*/
|
||||
Long.__isLong__;
|
||||
Long.prototype.__isLong__;
|
||||
|
||||
Object.defineProperty(Long.prototype, "__isLong__", {
|
||||
value: true,
|
||||
@ -25465,7 +25461,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {*} obj Object
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
Long.isLong = isLong;
|
||||
|
||||
@ -25522,7 +25517,6 @@ Curve25519Worker.prototype = {
|
||||
* @param {number} value The 32 bit integer in question
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromInt = fromInt;
|
||||
|
||||
@ -25557,7 +25551,6 @@ Curve25519Worker.prototype = {
|
||||
* @param {number} value The number in question
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromNumber = fromNumber;
|
||||
|
||||
@ -25580,7 +25573,6 @@ Curve25519Worker.prototype = {
|
||||
* @param {number} highBits The high 32 bits
|
||||
* @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromBits = fromBits;
|
||||
|
||||
@ -25650,7 +25642,6 @@ Curve25519Worker.prototype = {
|
||||
* @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
|
||||
* @param {number=} radix The radix in which the text is written (2-36), defaults to 10
|
||||
* @returns {!Long} The corresponding Long value
|
||||
* @expose
|
||||
*/
|
||||
Long.fromString = fromString;
|
||||
|
||||
@ -25676,7 +25667,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.fromValue = fromValue;
|
||||
|
||||
@ -25734,7 +25724,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Signed zero.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.ZERO = ZERO;
|
||||
|
||||
@ -25747,7 +25736,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Unsigned zero.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.UZERO = UZERO;
|
||||
|
||||
@ -25760,7 +25748,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Signed one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.ONE = ONE;
|
||||
|
||||
@ -25773,7 +25760,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Unsigned one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.UONE = UONE;
|
||||
|
||||
@ -25786,7 +25772,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Signed negative one.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.NEG_ONE = NEG_ONE;
|
||||
|
||||
@ -25799,7 +25784,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Maximum signed value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MAX_VALUE = MAX_VALUE;
|
||||
|
||||
@ -25812,7 +25796,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Maximum unsigned value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
|
||||
|
||||
@ -25825,7 +25808,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Minimum signed value.
|
||||
* @type {!Long}
|
||||
* @expose
|
||||
*/
|
||||
Long.MIN_VALUE = MIN_VALUE;
|
||||
|
||||
@ -25838,7 +25820,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toInt = function toInt() {
|
||||
return this.unsigned ? this.low >>> 0 : this.low;
|
||||
@ -25847,7 +25828,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toNumber = function toNumber() {
|
||||
if (this.unsigned)
|
||||
@ -25861,7 +25841,6 @@ Curve25519Worker.prototype = {
|
||||
* @returns {string}
|
||||
* @override
|
||||
* @throws {RangeError} If `radix` is out of range
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toString = function toString(radix) {
|
||||
radix = radix || 10;
|
||||
@ -25904,7 +25883,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Gets the high 32 bits as a signed integer.
|
||||
* @returns {number} Signed high bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getHighBits = function getHighBits() {
|
||||
return this.high;
|
||||
@ -25913,7 +25891,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Gets the high 32 bits as an unsigned integer.
|
||||
* @returns {number} Unsigned high bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
|
||||
return this.high >>> 0;
|
||||
@ -25922,7 +25899,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Gets the low 32 bits as a signed integer.
|
||||
* @returns {number} Signed low bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getLowBits = function getLowBits() {
|
||||
return this.low;
|
||||
@ -25931,7 +25907,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Gets the low 32 bits as an unsigned integer.
|
||||
* @returns {number} Unsigned low bits
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
|
||||
return this.low >>> 0;
|
||||
@ -25940,7 +25915,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Gets the number of bits needed to represent the absolute value of this Long.
|
||||
* @returns {number}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
|
||||
if (this.isNegative()) // Unsigned Longs are never negative
|
||||
@ -25955,7 +25929,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Tests if this Long's value equals zero.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isZero = function isZero() {
|
||||
return this.high === 0 && this.low === 0;
|
||||
@ -25964,7 +25937,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Tests if this Long's value is negative.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isNegative = function isNegative() {
|
||||
return !this.unsigned && this.high < 0;
|
||||
@ -25973,7 +25945,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Tests if this Long's value is positive.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isPositive = function isPositive() {
|
||||
return this.unsigned || this.high >= 0;
|
||||
@ -25982,7 +25953,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Tests if this Long's value is odd.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isOdd = function isOdd() {
|
||||
return (this.low & 1) === 1;
|
||||
@ -25991,7 +25961,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Tests if this Long's value is even.
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.isEven = function isEven() {
|
||||
return (this.low & 1) === 0;
|
||||
@ -26001,7 +25970,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value equals the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.equals = function equals(other) {
|
||||
if (!isLong(other))
|
||||
@ -26016,7 +25984,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.eq = LongPrototype.equals;
|
||||
|
||||
@ -26024,7 +25991,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value differs from the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.notEquals = function notEquals(other) {
|
||||
return !this.eq(/* validates */ other);
|
||||
@ -26035,7 +26001,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.neq = LongPrototype.notEquals;
|
||||
|
||||
@ -26043,7 +26008,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value is less than the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lessThan = function lessThan(other) {
|
||||
return this.comp(/* validates */ other) < 0;
|
||||
@ -26054,7 +26018,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lt = LongPrototype.lessThan;
|
||||
|
||||
@ -26062,7 +26025,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value is less than or equal the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
|
||||
return this.comp(/* validates */ other) <= 0;
|
||||
@ -26073,7 +26035,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.lte = LongPrototype.lessThanOrEqual;
|
||||
|
||||
@ -26081,7 +26042,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value is greater than the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.greaterThan = function greaterThan(other) {
|
||||
return this.comp(/* validates */ other) > 0;
|
||||
@ -26092,7 +26052,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.gt = LongPrototype.greaterThan;
|
||||
|
||||
@ -26100,7 +26059,6 @@ Curve25519Worker.prototype = {
|
||||
* Tests if this Long's value is greater than or equal the specified's.
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
|
||||
return this.comp(/* validates */ other) >= 0;
|
||||
@ -26111,7 +26069,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {boolean}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.gte = LongPrototype.greaterThanOrEqual;
|
||||
|
||||
@ -26120,7 +26077,6 @@ Curve25519Worker.prototype = {
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
|
||||
* if the given one is greater
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.compare = function compare(other) {
|
||||
if (!isLong(other))
|
||||
@ -26146,14 +26102,12 @@ Curve25519Worker.prototype = {
|
||||
* @param {!Long|number|string} other Other value
|
||||
* @returns {number} 0 if they are the same, 1 if the this is greater and -1
|
||||
* if the given one is greater
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.comp = LongPrototype.compare;
|
||||
|
||||
/**
|
||||
* Negates this Long's value.
|
||||
* @returns {!Long} Negated Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.negate = function negate() {
|
||||
if (!this.unsigned && this.eq(MIN_VALUE))
|
||||
@ -26165,7 +26119,6 @@ Curve25519Worker.prototype = {
|
||||
* Negates this Long's value. This is an alias of {@link Long#negate}.
|
||||
* @function
|
||||
* @returns {!Long} Negated Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.neg = LongPrototype.negate;
|
||||
|
||||
@ -26173,7 +26126,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the sum of this and the specified Long.
|
||||
* @param {!Long|number|string} addend Addend
|
||||
* @returns {!Long} Sum
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.add = function add(addend) {
|
||||
if (!isLong(addend))
|
||||
@ -26210,7 +26162,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the difference of this and the specified Long.
|
||||
* @param {!Long|number|string} subtrahend Subtrahend
|
||||
* @returns {!Long} Difference
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.subtract = function subtract(subtrahend) {
|
||||
if (!isLong(subtrahend))
|
||||
@ -26223,7 +26174,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} subtrahend Subtrahend
|
||||
* @returns {!Long} Difference
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.sub = LongPrototype.subtract;
|
||||
|
||||
@ -26231,7 +26181,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the product of this and the specified Long.
|
||||
* @param {!Long|number|string} multiplier Multiplier
|
||||
* @returns {!Long} Product
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.multiply = function multiply(multiplier) {
|
||||
if (this.isZero())
|
||||
@ -26299,7 +26248,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} multiplier Multiplier
|
||||
* @returns {!Long} Product
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.mul = LongPrototype.multiply;
|
||||
|
||||
@ -26308,7 +26256,6 @@ Curve25519Worker.prototype = {
|
||||
* unsigned if this Long is unsigned.
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Quotient
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.divide = function divide(divisor) {
|
||||
if (!isLong(divisor))
|
||||
@ -26319,6 +26266,8 @@ Curve25519Worker.prototype = {
|
||||
return this.unsigned ? UZERO : ZERO;
|
||||
var approx, rem, res;
|
||||
if (!this.unsigned) {
|
||||
// This section is only relevant for signed longs and is derived from the
|
||||
// closure library as a whole.
|
||||
if (this.eq(MIN_VALUE)) {
|
||||
if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
|
||||
return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
|
||||
@ -26344,19 +26293,18 @@ Curve25519Worker.prototype = {
|
||||
return this.neg().div(divisor).neg();
|
||||
} else if (divisor.isNegative())
|
||||
return this.div(divisor.neg()).neg();
|
||||
} else if (!divisor.unsigned)
|
||||
divisor = divisor.toUnsigned();
|
||||
|
||||
// The algorithm below has not been made for unsigned longs. It's therefore
|
||||
// required to take special care of the MSB prior to running it.
|
||||
if (this.unsigned) {
|
||||
res = ZERO;
|
||||
} else {
|
||||
// The algorithm below has not been made for unsigned longs. It's therefore
|
||||
// required to take special care of the MSB prior to running it.
|
||||
if (!divisor.unsigned)
|
||||
divisor = divisor.toUnsigned();
|
||||
if (divisor.gt(this))
|
||||
return UZERO;
|
||||
if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
|
||||
return UONE;
|
||||
res = UZERO;
|
||||
} else
|
||||
res = ZERO;
|
||||
}
|
||||
|
||||
// Repeat the following until the remainder is less than other: find a
|
||||
// floating-point that approximates remainder / other *from below*, add this
|
||||
@ -26400,7 +26348,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Quotient
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.div = LongPrototype.divide;
|
||||
|
||||
@ -26408,7 +26355,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns this Long modulo the specified.
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Remainder
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.modulo = function modulo(divisor) {
|
||||
if (!isLong(divisor))
|
||||
@ -26421,14 +26367,12 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {!Long|number|string} divisor Divisor
|
||||
* @returns {!Long} Remainder
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.mod = LongPrototype.modulo;
|
||||
|
||||
/**
|
||||
* Returns the bitwise NOT of this Long.
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.not = function not() {
|
||||
return fromBits(~this.low, ~this.high, this.unsigned);
|
||||
@ -26438,7 +26382,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the bitwise AND of this Long and the specified.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.and = function and(other) {
|
||||
if (!isLong(other))
|
||||
@ -26450,7 +26393,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the bitwise OR of this Long and the specified.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.or = function or(other) {
|
||||
if (!isLong(other))
|
||||
@ -26462,7 +26404,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns the bitwise XOR of this Long and the given one.
|
||||
* @param {!Long|number|string} other Other Long
|
||||
* @returns {!Long}
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.xor = function xor(other) {
|
||||
if (!isLong(other))
|
||||
@ -26474,7 +26415,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns this Long with bits shifted to the left by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftLeft = function shiftLeft(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -26492,7 +26432,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shl = LongPrototype.shiftLeft;
|
||||
|
||||
@ -26500,7 +26439,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns this Long with bits arithmetically shifted to the right by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftRight = function shiftRight(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -26518,7 +26456,6 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shr = LongPrototype.shiftRight;
|
||||
|
||||
@ -26526,7 +26463,6 @@ Curve25519Worker.prototype = {
|
||||
* Returns this Long with bits logically shifted to the right by the given amount.
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
|
||||
if (isLong(numBits))
|
||||
@ -26551,14 +26487,12 @@ Curve25519Worker.prototype = {
|
||||
* @function
|
||||
* @param {number|!Long} numBits Number of bits
|
||||
* @returns {!Long} Shifted Long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.shru = LongPrototype.shiftRightUnsigned;
|
||||
|
||||
/**
|
||||
* Converts this Long to signed.
|
||||
* @returns {!Long} Signed long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toSigned = function toSigned() {
|
||||
if (!this.unsigned)
|
||||
@ -26569,7 +26503,6 @@ Curve25519Worker.prototype = {
|
||||
/**
|
||||
* Converts this Long to unsigned.
|
||||
* @returns {!Long} Unsigned long
|
||||
* @expose
|
||||
*/
|
||||
LongPrototype.toUnsigned = function toUnsigned() {
|
||||
if (this.unsigned)
|
||||
@ -26577,6 +26510,53 @@ Curve25519Worker.prototype = {
|
||||
return fromBits(this.low, this.high, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this Long to its byte representation.
|
||||
* @param {boolean=} le Whether little or big endian, defaults to big endian
|
||||
* @returns {!Array.<number>} Byte representation
|
||||
*/
|
||||
LongPrototype.toBytes = function(le) {
|
||||
return le ? this.toBytesLE() : this.toBytesBE();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this Long to its little endian byte representation.
|
||||
* @returns {!Array.<number>} Little endian byte representation
|
||||
*/
|
||||
LongPrototype.toBytesLE = function() {
|
||||
var hi = this.high,
|
||||
lo = this.low;
|
||||
return [
|
||||
lo & 0xff,
|
||||
(lo >>> 8) & 0xff,
|
||||
(lo >>> 16) & 0xff,
|
||||
(lo >>> 24) & 0xff,
|
||||
hi & 0xff,
|
||||
(hi >>> 8) & 0xff,
|
||||
(hi >>> 16) & 0xff,
|
||||
(hi >>> 24) & 0xff
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this Long to its big endian byte representation.
|
||||
* @returns {!Array.<number>} Big endian byte representation
|
||||
*/
|
||||
LongPrototype.toBytesBE = function() {
|
||||
var hi = this.high,
|
||||
lo = this.low;
|
||||
return [
|
||||
(hi >>> 24) & 0xff,
|
||||
(hi >>> 16) & 0xff,
|
||||
(hi >>> 8) & 0xff,
|
||||
hi & 0xff,
|
||||
(lo >>> 24) & 0xff,
|
||||
(lo >>> 16) & 0xff,
|
||||
(lo >>> 8) & 0xff,
|
||||
lo & 0xff
|
||||
];
|
||||
}
|
||||
|
||||
return Long;
|
||||
});
|
||||
|
||||
@ -35311,8 +35291,6 @@ var Internal = Internal || {};
|
||||
result = result | (a[i] ^ b[i]);
|
||||
}
|
||||
if (result !== 0) {
|
||||
console.log('Our MAC ', dcodeIO.ByteBuffer.wrap(calculated_mac).toHex());
|
||||
console.log('Their MAC', dcodeIO.ByteBuffer.wrap(mac).toHex());
|
||||
throw new Error("Bad MAC");
|
||||
}
|
||||
});
|
||||
@ -35515,6 +35493,7 @@ Internal.ChainType = {
|
||||
Internal.SessionRecord = function() {
|
||||
'use strict';
|
||||
var ARCHIVED_STATES_MAX_LENGTH = 40;
|
||||
var OLD_RATCHETS_MAX_LENGTH = 10;
|
||||
var SESSION_RECORD_VERSION = 'v1';
|
||||
|
||||
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
|
||||
@ -35541,7 +35520,12 @@ Internal.SessionRecord = function() {
|
||||
} else if (thing === Object(thing)) {
|
||||
var obj = {};
|
||||
for (var key in thing) {
|
||||
obj[key] = ensureStringed(thing[key]);
|
||||
try {
|
||||
obj[key] = ensureStringed(thing[key]);
|
||||
} catch (ex) {
|
||||
console.log('Error serializing key', key);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
} else if (thing === null) {
|
||||
@ -35560,12 +35544,21 @@ Internal.SessionRecord = function() {
|
||||
version: 'v1',
|
||||
migrate: function migrateV1(data) {
|
||||
var sessions = data.sessions;
|
||||
var key;
|
||||
if (data.registrationId) {
|
||||
for (var key in sessions) {
|
||||
for (key in sessions) {
|
||||
if (!sessions[key].registrationId) {
|
||||
sessions[key].registrationId = data.registrationId;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (key in sessions) {
|
||||
if (sessions[key].indexInfo.closed === -1) {
|
||||
console.log('V1 session storage migration error: registrationId',
|
||||
data.registrationId, 'for open session version',
|
||||
data.version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35586,7 +35579,7 @@ Internal.SessionRecord = function() {
|
||||
}
|
||||
|
||||
var SessionRecord = function() {
|
||||
this._sessions = {};
|
||||
this.sessions = {};
|
||||
this.version = SESSION_RECORD_VERSION;
|
||||
};
|
||||
|
||||
@ -35595,8 +35588,8 @@ Internal.SessionRecord = function() {
|
||||
if (data.version !== SESSION_RECORD_VERSION) { migrate(data); }
|
||||
|
||||
var record = new SessionRecord();
|
||||
record._sessions = data.sessions;
|
||||
if (record._sessions === undefined || record._sessions === null || typeof record._sessions !== "object" || Array.isArray(record._sessions)) {
|
||||
record.sessions = data.sessions;
|
||||
if (record.sessions === undefined || record.sessions === null || typeof record.sessions !== "object" || Array.isArray(record.sessions)) {
|
||||
throw new Error("Error deserializing SessionRecord");
|
||||
}
|
||||
return record;
|
||||
@ -35605,16 +35598,17 @@ Internal.SessionRecord = function() {
|
||||
SessionRecord.prototype = {
|
||||
serialize: function() {
|
||||
return jsonThing({
|
||||
sessions : this._sessions,
|
||||
sessions : this.sessions,
|
||||
version : this.version
|
||||
});
|
||||
},
|
||||
haveOpenSession: function() {
|
||||
return this.getOpenSession() !== undefined;
|
||||
var openSession = this.getOpenSession();
|
||||
return (!!openSession && typeof openSession.registrationId === 'number');
|
||||
},
|
||||
|
||||
getSessionByBaseKey: function(baseKey) {
|
||||
var session = this._sessions[util.toString(baseKey)];
|
||||
var session = this.sessions[util.toString(baseKey)];
|
||||
if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) {
|
||||
console.log("Tried to lookup a session using our basekey");
|
||||
return undefined;
|
||||
@ -35623,7 +35617,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) {
|
||||
this.detectDuplicateOpenSessions();
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
|
||||
var searchKey = util.toString(remoteEphemeralKey);
|
||||
|
||||
@ -35643,7 +35637,7 @@ Internal.SessionRecord = function() {
|
||||
return undefined;
|
||||
},
|
||||
getOpenSession: function() {
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
if (sessions === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@ -35659,7 +35653,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
detectDuplicateOpenSessions: function() {
|
||||
var openSession;
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
for (var key in sessions) {
|
||||
if (sessions[key].indexInfo.closed == -1) {
|
||||
if (openSession !== undefined) {
|
||||
@ -35670,7 +35664,7 @@ Internal.SessionRecord = function() {
|
||||
}
|
||||
},
|
||||
updateSessionState: function(session) {
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
|
||||
this.removeOldChains(session);
|
||||
|
||||
@ -35684,11 +35678,11 @@ Internal.SessionRecord = function() {
|
||||
// followed by the open session
|
||||
var list = [];
|
||||
var openSession;
|
||||
for (var k in this._sessions) {
|
||||
if (this._sessions[k].indexInfo.closed === -1) {
|
||||
openSession = this._sessions[k];
|
||||
for (var k in this.sessions) {
|
||||
if (this.sessions[k].indexInfo.closed === -1) {
|
||||
openSession = this.sessions[k];
|
||||
} else {
|
||||
list.push(this._sessions[k]);
|
||||
list.push(this.sessions[k]);
|
||||
}
|
||||
}
|
||||
list = list.sort(function(s1, s2) {
|
||||
@ -35702,38 +35696,20 @@ Internal.SessionRecord = function() {
|
||||
archiveCurrentState: function() {
|
||||
var open_session = this.getOpenSession();
|
||||
if (open_session !== undefined) {
|
||||
this.closeSession(open_session);
|
||||
console.log('closing session');
|
||||
open_session.indexInfo.closed = Date.now();
|
||||
this.updateSessionState(open_session);
|
||||
}
|
||||
},
|
||||
closeSession: function(session) {
|
||||
if (session.indexInfo.closed > -1) {
|
||||
return;
|
||||
}
|
||||
console.log('closing session', session.indexInfo.baseKey);
|
||||
|
||||
// After this has run, we can still receive messages on ratchet chains which
|
||||
// were already open (unless we know we dont need them),
|
||||
// but we cannot send messages or step the ratchet
|
||||
|
||||
// Delete current sending ratchet
|
||||
delete session[util.toString(session.currentRatchet.ephemeralKeyPair.pubKey)];
|
||||
// Move all receive ratchets to the oldRatchetList to mark them for deletion
|
||||
for (var i in session) {
|
||||
if (session[i].chainKey !== undefined && session[i].chainKey.key !== undefined) {
|
||||
session.oldRatchetList[session.oldRatchetList.length] = {
|
||||
added: Date.now(), ephemeralKey: i
|
||||
};
|
||||
}
|
||||
}
|
||||
session.indexInfo.closed = Date.now();
|
||||
this.removeOldChains(session);
|
||||
promoteState: function(session) {
|
||||
console.log('promoting session');
|
||||
session.indexInfo.closed = -1;
|
||||
},
|
||||
removeOldChains: function(session) {
|
||||
// Sending ratchets are always removed when we step because we never need them again
|
||||
// Receiving ratchets are added to the oldRatchetList, which we parse
|
||||
// here and remove all but the last five.
|
||||
while (session.oldRatchetList.length > 5) {
|
||||
// here and remove all but the last ten.
|
||||
while (session.oldRatchetList.length > OLD_RATCHETS_MAX_LENGTH) {
|
||||
var index = 0;
|
||||
var oldest = session.oldRatchetList[0];
|
||||
for (var i = 0; i < session.oldRatchetList.length; i++) {
|
||||
@ -35749,7 +35725,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
removeOldSessions: function() {
|
||||
// Retain only the last 20 sessions
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
var oldestBaseKey, oldestSession;
|
||||
while (Object.keys(sessions).length > ARCHIVED_STATES_MAX_LENGTH) {
|
||||
for (var key in sessions) {
|
||||
@ -35764,6 +35740,10 @@ Internal.SessionRecord = function() {
|
||||
delete sessions[util.toString(oldestBaseKey)];
|
||||
}
|
||||
},
|
||||
deleteAllSessions: function() {
|
||||
// Used primarily in session reset scenarios, where we really delete sessions
|
||||
this.sessions = {};
|
||||
}
|
||||
};
|
||||
|
||||
return SessionRecord;
|
||||
@ -35815,7 +35795,7 @@ SessionBuilder.prototype = {
|
||||
processPreKey: function(device) {
|
||||
return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), device.identityKey
|
||||
this.remoteAddress.getName(), device.identityKey, this.storage.Direction.SENDING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
@ -35829,15 +35809,20 @@ SessionBuilder.prototype = {
|
||||
}).then(function() {
|
||||
return Internal.crypto.createKeyPair();
|
||||
}).then(function(baseKey) {
|
||||
var devicePreKey = (device.preKey.publicKey);
|
||||
var devicePreKey;
|
||||
if (device.preKey) {
|
||||
devicePreKey = device.preKey.publicKey;
|
||||
}
|
||||
return this.initSession(true, baseKey, undefined, device.identityKey,
|
||||
devicePreKey, device.signedPreKey.publicKey, device.registrationId
|
||||
).then(function(session) {
|
||||
session.pendingPreKey = {
|
||||
preKeyId : device.preKey.keyId,
|
||||
signedKeyId : device.signedPreKey.keyId,
|
||||
baseKey : baseKey.pubKey
|
||||
};
|
||||
if (device.preKey) {
|
||||
session.pendingPreKey.preKeyId = device.preKey.keyId;
|
||||
}
|
||||
return session;
|
||||
});
|
||||
}.bind(this)).then(function(session) {
|
||||
@ -35851,10 +35836,10 @@ SessionBuilder.prototype = {
|
||||
}
|
||||
|
||||
record.archiveCurrentState();
|
||||
record.updateSessionState(session, device.registrationId);
|
||||
record.updateSessionState(session);
|
||||
return Promise.all([
|
||||
this.storage.storeSession(address, record.serialize()),
|
||||
this.storage.saveIdentity(this.remoteAddress.getName(), session.indexInfo.remoteIdentityKey)
|
||||
this.storage.saveIdentity(this.remoteAddress.toString(), session.indexInfo.remoteIdentityKey)
|
||||
]);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
@ -35863,7 +35848,7 @@ SessionBuilder.prototype = {
|
||||
processV3: function(record, message) {
|
||||
var preKeyPair, signedPreKeyPair, session;
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), message.identityKey.toArrayBuffer()
|
||||
this.remoteAddress.getName(), message.identityKey.toArrayBuffer(), this.storage.Direction.RECEIVING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
var e = new Error('Unknown identity key');
|
||||
@ -35910,8 +35895,8 @@ SessionBuilder.prototype = {
|
||||
// Note that the session is not actually saved until the very
|
||||
// end of decryptWhisperMessage ... to ensure that the sender
|
||||
// actually holds the private keys for all reported pubkeys
|
||||
record.updateSessionState(new_session, message.registrationId);
|
||||
return this.storage.saveIdentity(this.remoteAddress.getName(), message.identityKey.toArrayBuffer()).then(function() {
|
||||
record.updateSessionState(new_session);
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), message.identityKey.toArrayBuffer()).then(function() {
|
||||
return message.preKeyId;
|
||||
});
|
||||
}.bind(this));
|
||||
@ -36107,10 +36092,20 @@ SessionCipher.prototype = {
|
||||
result.set(new Uint8Array(encodedMsg), 1);
|
||||
result.set(new Uint8Array(mac, 0, 8), encodedMsg.byteLength + 1);
|
||||
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result;
|
||||
});
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), util.toArrayBuffer(session.indexInfo.remoteIdentityKey), this.storage.Direction.SENDING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
}
|
||||
}).then(function() {
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), session.indexInfo.remoteIdentityKey);
|
||||
}.bind(this)).then(function() {
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result;
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this)).then(function(message) {
|
||||
@ -36120,7 +36115,9 @@ SessionCipher.prototype = {
|
||||
preKeyMsg.registrationId = myRegistrationId;
|
||||
|
||||
preKeyMsg.baseKey = util.toArrayBuffer(session.pendingPreKey.baseKey);
|
||||
preKeyMsg.preKeyId = session.pendingPreKey.preKeyId;
|
||||
if (session.pendingPreKey.preKeyId) {
|
||||
preKeyMsg.preKeyId = session.pendingPreKey.preKeyId;
|
||||
}
|
||||
preKeyMsg.signedPreKeyId = session.pendingPreKey.signedKeyId;
|
||||
|
||||
preKeyMsg.message = message;
|
||||
@ -36153,6 +36150,10 @@ SessionCipher.prototype = {
|
||||
return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) {
|
||||
return { plaintext: plaintext, session: session };
|
||||
}).catch(function(e) {
|
||||
if (e.name === 'MessageCounterError') {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
errors.push(e);
|
||||
return this.decryptWithSessionList(buffer, sessionList, errors);
|
||||
}.bind(this));
|
||||
@ -36168,10 +36169,25 @@ SessionCipher.prototype = {
|
||||
var errors = [];
|
||||
return this.decryptWithSessionList(buffer, record.getSessions(), errors).then(function(result) {
|
||||
return this.getRecord(address).then(function(record) {
|
||||
record.updateSessionState(result.session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result.plaintext;
|
||||
});
|
||||
if (result.session.indexInfo.baseKey !== record.getOpenSession().indexInfo.baseKey) {
|
||||
record.archiveCurrentState();
|
||||
record.promoteState(result.session);
|
||||
}
|
||||
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), util.toArrayBuffer(result.session.indexInfo.remoteIdentityKey), this.storage.Direction.RECEIVING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
}
|
||||
}).then(function() {
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), result.session.indexInfo.remoteIdentityKey);
|
||||
}.bind(this)).then(function() {
|
||||
record.updateSessionState(result.session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result.plaintext;
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
@ -36196,6 +36212,7 @@ SessionCipher.prototype = {
|
||||
);
|
||||
}
|
||||
var builder = new SessionBuilder(this.storage, this.remoteAddress);
|
||||
// isTrustedIdentity is called within processV3, no need to call it here
|
||||
return builder.processV3(record, preKeyProto).then(function(preKeyId) {
|
||||
var session = record.getSessionByBaseKey(preKeyProto.baseKey);
|
||||
return this.doDecryptWhisperMessage(
|
||||
@ -36203,7 +36220,7 @@ SessionCipher.prototype = {
|
||||
).then(function(plaintext) {
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
if (preKeyId !== undefined) {
|
||||
if (preKeyId !== undefined && preKeyId !== null) {
|
||||
return this.storage.removePreKey(preKeyId);
|
||||
}
|
||||
}.bind(this)).then(function() {
|
||||
@ -36215,7 +36232,7 @@ SessionCipher.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
doDecryptWhisperMessage: function(messageBytes, session) {
|
||||
if (!messageBytes instanceof ArrayBuffer) {
|
||||
if (!(messageBytes instanceof ArrayBuffer)) {
|
||||
throw new Error("Expected messageBytes to be an ArrayBuffer");
|
||||
}
|
||||
var version = (new Uint8Array(messageBytes))[0];
|
||||
@ -36270,15 +36287,14 @@ SessionCipher.prototype = {
|
||||
});
|
||||
},
|
||||
fillMessageKeys: function(chain, counter) {
|
||||
if (Object.keys(chain.messageKeys).length >= 1000) {
|
||||
console.log("Too many message keys for chain");
|
||||
return Promise.resolve(); // Stalker, much?
|
||||
}
|
||||
|
||||
if (chain.chainKey.counter >= counter) {
|
||||
return Promise.resolve(); // Already calculated
|
||||
}
|
||||
|
||||
if (counter - chain.chainKey.counter > 2000) {
|
||||
throw new Error('Over 2000 messages into the future!');
|
||||
}
|
||||
|
||||
if (chain.chainKey.key === undefined) {
|
||||
throw new Error("Got invalid request to extend chain after it was already closed");
|
||||
}
|
||||
@ -36390,6 +36406,20 @@ SessionCipher.prototype = {
|
||||
return this.storage.storeSession(address, record.serialize());
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
deleteAllSessionsForDevice: function() {
|
||||
// Used in session reset scenarios, where we really need to delete
|
||||
var address = this.remoteAddress.toString();
|
||||
return Internal.SessionLock.queueJobForNumber(address, function() {
|
||||
return this.getRecord(address).then(function(record) {
|
||||
if (record === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
record.deleteAllSessions();
|
||||
return this.storage.storeSession(address, record.serialize());
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
@ -36409,6 +36439,7 @@ libsignal.SessionCipher = function(storage, remoteAddress) {
|
||||
this.getRemoteRegistrationId = cipher.getRemoteRegistrationId.bind(cipher);
|
||||
this.hasOpenSession = cipher.hasOpenSession.bind(cipher);
|
||||
this.closeOpenSessionForDevice = cipher.closeOpenSessionForDevice.bind(cipher);
|
||||
this.deleteAllSessionsForDevice = cipher.deleteAllSessionsForDevice.bind(cipher);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "libsignal-protocol",
|
||||
"repository": "https://github.com/WhisperSystems/libsignal-protocol-javascript.git",
|
||||
"version": "1.1.2",
|
||||
"version": "1.3.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"long": "^3.1.0",
|
||||
@ -15,7 +15,7 @@
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-concat": "^0.5.0",
|
||||
"grunt-contrib-connect": "^0.9.0",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-jshint": "^1.1.0",
|
||||
"grunt-contrib-sass": "^0.8.1",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-jscs": "^1.1.0",
|
||||
|
||||
@ -7,7 +7,7 @@ SessionBuilder.prototype = {
|
||||
processPreKey: function(device) {
|
||||
return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), device.identityKey
|
||||
this.remoteAddress.getName(), device.identityKey, this.storage.Direction.SENDING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
@ -21,15 +21,20 @@ SessionBuilder.prototype = {
|
||||
}).then(function() {
|
||||
return Internal.crypto.createKeyPair();
|
||||
}).then(function(baseKey) {
|
||||
var devicePreKey = (device.preKey.publicKey);
|
||||
var devicePreKey;
|
||||
if (device.preKey) {
|
||||
devicePreKey = device.preKey.publicKey;
|
||||
}
|
||||
return this.initSession(true, baseKey, undefined, device.identityKey,
|
||||
devicePreKey, device.signedPreKey.publicKey, device.registrationId
|
||||
).then(function(session) {
|
||||
session.pendingPreKey = {
|
||||
preKeyId : device.preKey.keyId,
|
||||
signedKeyId : device.signedPreKey.keyId,
|
||||
baseKey : baseKey.pubKey
|
||||
};
|
||||
if (device.preKey) {
|
||||
session.pendingPreKey.preKeyId = device.preKey.keyId;
|
||||
}
|
||||
return session;
|
||||
});
|
||||
}.bind(this)).then(function(session) {
|
||||
@ -43,10 +48,10 @@ SessionBuilder.prototype = {
|
||||
}
|
||||
|
||||
record.archiveCurrentState();
|
||||
record.updateSessionState(session, device.registrationId);
|
||||
record.updateSessionState(session);
|
||||
return Promise.all([
|
||||
this.storage.storeSession(address, record.serialize()),
|
||||
this.storage.saveIdentity(this.remoteAddress.getName(), session.indexInfo.remoteIdentityKey)
|
||||
this.storage.saveIdentity(this.remoteAddress.toString(), session.indexInfo.remoteIdentityKey)
|
||||
]);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
@ -55,7 +60,7 @@ SessionBuilder.prototype = {
|
||||
processV3: function(record, message) {
|
||||
var preKeyPair, signedPreKeyPair, session;
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), message.identityKey.toArrayBuffer()
|
||||
this.remoteAddress.getName(), message.identityKey.toArrayBuffer(), this.storage.Direction.RECEIVING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
var e = new Error('Unknown identity key');
|
||||
@ -102,8 +107,8 @@ SessionBuilder.prototype = {
|
||||
// Note that the session is not actually saved until the very
|
||||
// end of decryptWhisperMessage ... to ensure that the sender
|
||||
// actually holds the private keys for all reported pubkeys
|
||||
record.updateSessionState(new_session, message.registrationId);
|
||||
return this.storage.saveIdentity(this.remoteAddress.getName(), message.identityKey.toArrayBuffer()).then(function() {
|
||||
record.updateSessionState(new_session);
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), message.identityKey.toArrayBuffer()).then(function() {
|
||||
return message.preKeyId;
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
@ -76,10 +76,20 @@ SessionCipher.prototype = {
|
||||
result.set(new Uint8Array(encodedMsg), 1);
|
||||
result.set(new Uint8Array(mac, 0, 8), encodedMsg.byteLength + 1);
|
||||
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result;
|
||||
});
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), util.toArrayBuffer(session.indexInfo.remoteIdentityKey), this.storage.Direction.SENDING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
}
|
||||
}).then(function() {
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), session.indexInfo.remoteIdentityKey);
|
||||
}.bind(this)).then(function() {
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result;
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this)).then(function(message) {
|
||||
@ -89,7 +99,9 @@ SessionCipher.prototype = {
|
||||
preKeyMsg.registrationId = myRegistrationId;
|
||||
|
||||
preKeyMsg.baseKey = util.toArrayBuffer(session.pendingPreKey.baseKey);
|
||||
preKeyMsg.preKeyId = session.pendingPreKey.preKeyId;
|
||||
if (session.pendingPreKey.preKeyId) {
|
||||
preKeyMsg.preKeyId = session.pendingPreKey.preKeyId;
|
||||
}
|
||||
preKeyMsg.signedPreKeyId = session.pendingPreKey.signedKeyId;
|
||||
|
||||
preKeyMsg.message = message;
|
||||
@ -122,6 +134,10 @@ SessionCipher.prototype = {
|
||||
return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) {
|
||||
return { plaintext: plaintext, session: session };
|
||||
}).catch(function(e) {
|
||||
if (e.name === 'MessageCounterError') {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
errors.push(e);
|
||||
return this.decryptWithSessionList(buffer, sessionList, errors);
|
||||
}.bind(this));
|
||||
@ -137,10 +153,25 @@ SessionCipher.prototype = {
|
||||
var errors = [];
|
||||
return this.decryptWithSessionList(buffer, record.getSessions(), errors).then(function(result) {
|
||||
return this.getRecord(address).then(function(record) {
|
||||
record.updateSessionState(result.session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result.plaintext;
|
||||
});
|
||||
if (result.session.indexInfo.baseKey !== record.getOpenSession().indexInfo.baseKey) {
|
||||
record.archiveCurrentState();
|
||||
record.promoteState(result.session);
|
||||
}
|
||||
|
||||
return this.storage.isTrustedIdentity(
|
||||
this.remoteAddress.getName(), util.toArrayBuffer(result.session.indexInfo.remoteIdentityKey), this.storage.Direction.RECEIVING
|
||||
).then(function(trusted) {
|
||||
if (!trusted) {
|
||||
throw new Error('Identity key changed');
|
||||
}
|
||||
}).then(function() {
|
||||
return this.storage.saveIdentity(this.remoteAddress.toString(), result.session.indexInfo.remoteIdentityKey);
|
||||
}.bind(this)).then(function() {
|
||||
record.updateSessionState(result.session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
return result.plaintext;
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
@ -165,6 +196,7 @@ SessionCipher.prototype = {
|
||||
);
|
||||
}
|
||||
var builder = new SessionBuilder(this.storage, this.remoteAddress);
|
||||
// isTrustedIdentity is called within processV3, no need to call it here
|
||||
return builder.processV3(record, preKeyProto).then(function(preKeyId) {
|
||||
var session = record.getSessionByBaseKey(preKeyProto.baseKey);
|
||||
return this.doDecryptWhisperMessage(
|
||||
@ -172,7 +204,7 @@ SessionCipher.prototype = {
|
||||
).then(function(plaintext) {
|
||||
record.updateSessionState(session);
|
||||
return this.storage.storeSession(address, record.serialize()).then(function() {
|
||||
if (preKeyId !== undefined) {
|
||||
if (preKeyId !== undefined && preKeyId !== null) {
|
||||
return this.storage.removePreKey(preKeyId);
|
||||
}
|
||||
}.bind(this)).then(function() {
|
||||
@ -184,7 +216,7 @@ SessionCipher.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
doDecryptWhisperMessage: function(messageBytes, session) {
|
||||
if (!messageBytes instanceof ArrayBuffer) {
|
||||
if (!(messageBytes instanceof ArrayBuffer)) {
|
||||
throw new Error("Expected messageBytes to be an ArrayBuffer");
|
||||
}
|
||||
var version = (new Uint8Array(messageBytes))[0];
|
||||
@ -239,15 +271,14 @@ SessionCipher.prototype = {
|
||||
});
|
||||
},
|
||||
fillMessageKeys: function(chain, counter) {
|
||||
if (Object.keys(chain.messageKeys).length >= 1000) {
|
||||
console.log("Too many message keys for chain");
|
||||
return Promise.resolve(); // Stalker, much?
|
||||
}
|
||||
|
||||
if (chain.chainKey.counter >= counter) {
|
||||
return Promise.resolve(); // Already calculated
|
||||
}
|
||||
|
||||
if (counter - chain.chainKey.counter > 2000) {
|
||||
throw new Error('Over 2000 messages into the future!');
|
||||
}
|
||||
|
||||
if (chain.chainKey.key === undefined) {
|
||||
throw new Error("Got invalid request to extend chain after it was already closed");
|
||||
}
|
||||
@ -359,6 +390,20 @@ SessionCipher.prototype = {
|
||||
return this.storage.storeSession(address, record.serialize());
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
deleteAllSessionsForDevice: function() {
|
||||
// Used in session reset scenarios, where we really need to delete
|
||||
var address = this.remoteAddress.toString();
|
||||
return Internal.SessionLock.queueJobForNumber(address, function() {
|
||||
return this.getRecord(address).then(function(record) {
|
||||
if (record === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
record.deleteAllSessions();
|
||||
return this.storage.storeSession(address, record.serialize());
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
@ -378,4 +423,5 @@ libsignal.SessionCipher = function(storage, remoteAddress) {
|
||||
this.getRemoteRegistrationId = cipher.getRemoteRegistrationId.bind(cipher);
|
||||
this.hasOpenSession = cipher.hasOpenSession.bind(cipher);
|
||||
this.closeOpenSessionForDevice = cipher.closeOpenSessionForDevice.bind(cipher);
|
||||
this.deleteAllSessionsForDevice = cipher.deleteAllSessionsForDevice.bind(cipher);
|
||||
};
|
||||
|
||||
@ -16,6 +16,7 @@ Internal.ChainType = {
|
||||
Internal.SessionRecord = function() {
|
||||
'use strict';
|
||||
var ARCHIVED_STATES_MAX_LENGTH = 40;
|
||||
var OLD_RATCHETS_MAX_LENGTH = 10;
|
||||
var SESSION_RECORD_VERSION = 'v1';
|
||||
|
||||
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
|
||||
@ -42,7 +43,12 @@ Internal.SessionRecord = function() {
|
||||
} else if (thing === Object(thing)) {
|
||||
var obj = {};
|
||||
for (var key in thing) {
|
||||
obj[key] = ensureStringed(thing[key]);
|
||||
try {
|
||||
obj[key] = ensureStringed(thing[key]);
|
||||
} catch (ex) {
|
||||
console.log('Error serializing key', key);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
} else if (thing === null) {
|
||||
@ -61,12 +67,21 @@ Internal.SessionRecord = function() {
|
||||
version: 'v1',
|
||||
migrate: function migrateV1(data) {
|
||||
var sessions = data.sessions;
|
||||
var key;
|
||||
if (data.registrationId) {
|
||||
for (var key in sessions) {
|
||||
for (key in sessions) {
|
||||
if (!sessions[key].registrationId) {
|
||||
sessions[key].registrationId = data.registrationId;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (key in sessions) {
|
||||
if (sessions[key].indexInfo.closed === -1) {
|
||||
console.log('V1 session storage migration error: registrationId',
|
||||
data.registrationId, 'for open session version',
|
||||
data.version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +102,7 @@ Internal.SessionRecord = function() {
|
||||
}
|
||||
|
||||
var SessionRecord = function() {
|
||||
this._sessions = {};
|
||||
this.sessions = {};
|
||||
this.version = SESSION_RECORD_VERSION;
|
||||
};
|
||||
|
||||
@ -96,8 +111,8 @@ Internal.SessionRecord = function() {
|
||||
if (data.version !== SESSION_RECORD_VERSION) { migrate(data); }
|
||||
|
||||
var record = new SessionRecord();
|
||||
record._sessions = data.sessions;
|
||||
if (record._sessions === undefined || record._sessions === null || typeof record._sessions !== "object" || Array.isArray(record._sessions)) {
|
||||
record.sessions = data.sessions;
|
||||
if (record.sessions === undefined || record.sessions === null || typeof record.sessions !== "object" || Array.isArray(record.sessions)) {
|
||||
throw new Error("Error deserializing SessionRecord");
|
||||
}
|
||||
return record;
|
||||
@ -106,16 +121,17 @@ Internal.SessionRecord = function() {
|
||||
SessionRecord.prototype = {
|
||||
serialize: function() {
|
||||
return jsonThing({
|
||||
sessions : this._sessions,
|
||||
sessions : this.sessions,
|
||||
version : this.version
|
||||
});
|
||||
},
|
||||
haveOpenSession: function() {
|
||||
return this.getOpenSession() !== undefined;
|
||||
var openSession = this.getOpenSession();
|
||||
return (!!openSession && typeof openSession.registrationId === 'number');
|
||||
},
|
||||
|
||||
getSessionByBaseKey: function(baseKey) {
|
||||
var session = this._sessions[util.toString(baseKey)];
|
||||
var session = this.sessions[util.toString(baseKey)];
|
||||
if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) {
|
||||
console.log("Tried to lookup a session using our basekey");
|
||||
return undefined;
|
||||
@ -124,7 +140,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) {
|
||||
this.detectDuplicateOpenSessions();
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
|
||||
var searchKey = util.toString(remoteEphemeralKey);
|
||||
|
||||
@ -144,7 +160,7 @@ Internal.SessionRecord = function() {
|
||||
return undefined;
|
||||
},
|
||||
getOpenSession: function() {
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
if (sessions === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@ -160,7 +176,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
detectDuplicateOpenSessions: function() {
|
||||
var openSession;
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
for (var key in sessions) {
|
||||
if (sessions[key].indexInfo.closed == -1) {
|
||||
if (openSession !== undefined) {
|
||||
@ -171,7 +187,7 @@ Internal.SessionRecord = function() {
|
||||
}
|
||||
},
|
||||
updateSessionState: function(session) {
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
|
||||
this.removeOldChains(session);
|
||||
|
||||
@ -185,11 +201,11 @@ Internal.SessionRecord = function() {
|
||||
// followed by the open session
|
||||
var list = [];
|
||||
var openSession;
|
||||
for (var k in this._sessions) {
|
||||
if (this._sessions[k].indexInfo.closed === -1) {
|
||||
openSession = this._sessions[k];
|
||||
for (var k in this.sessions) {
|
||||
if (this.sessions[k].indexInfo.closed === -1) {
|
||||
openSession = this.sessions[k];
|
||||
} else {
|
||||
list.push(this._sessions[k]);
|
||||
list.push(this.sessions[k]);
|
||||
}
|
||||
}
|
||||
list = list.sort(function(s1, s2) {
|
||||
@ -203,38 +219,20 @@ Internal.SessionRecord = function() {
|
||||
archiveCurrentState: function() {
|
||||
var open_session = this.getOpenSession();
|
||||
if (open_session !== undefined) {
|
||||
this.closeSession(open_session);
|
||||
console.log('closing session');
|
||||
open_session.indexInfo.closed = Date.now();
|
||||
this.updateSessionState(open_session);
|
||||
}
|
||||
},
|
||||
closeSession: function(session) {
|
||||
if (session.indexInfo.closed > -1) {
|
||||
return;
|
||||
}
|
||||
console.log('closing session', session.indexInfo.baseKey);
|
||||
|
||||
// After this has run, we can still receive messages on ratchet chains which
|
||||
// were already open (unless we know we dont need them),
|
||||
// but we cannot send messages or step the ratchet
|
||||
|
||||
// Delete current sending ratchet
|
||||
delete session[util.toString(session.currentRatchet.ephemeralKeyPair.pubKey)];
|
||||
// Move all receive ratchets to the oldRatchetList to mark them for deletion
|
||||
for (var i in session) {
|
||||
if (session[i].chainKey !== undefined && session[i].chainKey.key !== undefined) {
|
||||
session.oldRatchetList[session.oldRatchetList.length] = {
|
||||
added: Date.now(), ephemeralKey: i
|
||||
};
|
||||
}
|
||||
}
|
||||
session.indexInfo.closed = Date.now();
|
||||
this.removeOldChains(session);
|
||||
promoteState: function(session) {
|
||||
console.log('promoting session');
|
||||
session.indexInfo.closed = -1;
|
||||
},
|
||||
removeOldChains: function(session) {
|
||||
// Sending ratchets are always removed when we step because we never need them again
|
||||
// Receiving ratchets are added to the oldRatchetList, which we parse
|
||||
// here and remove all but the last five.
|
||||
while (session.oldRatchetList.length > 5) {
|
||||
// here and remove all but the last ten.
|
||||
while (session.oldRatchetList.length > OLD_RATCHETS_MAX_LENGTH) {
|
||||
var index = 0;
|
||||
var oldest = session.oldRatchetList[0];
|
||||
for (var i = 0; i < session.oldRatchetList.length; i++) {
|
||||
@ -250,7 +248,7 @@ Internal.SessionRecord = function() {
|
||||
},
|
||||
removeOldSessions: function() {
|
||||
// Retain only the last 20 sessions
|
||||
var sessions = this._sessions;
|
||||
var sessions = this.sessions;
|
||||
var oldestBaseKey, oldestSession;
|
||||
while (Object.keys(sessions).length > ARCHIVED_STATES_MAX_LENGTH) {
|
||||
for (var key in sessions) {
|
||||
@ -265,6 +263,10 @@ Internal.SessionRecord = function() {
|
||||
delete sessions[util.toString(oldestBaseKey)];
|
||||
}
|
||||
},
|
||||
deleteAllSessions: function() {
|
||||
// Used primarily in session reset scenarios, where we really delete sessions
|
||||
this.sessions = {};
|
||||
}
|
||||
};
|
||||
|
||||
return SessionRecord;
|
||||
|
||||
@ -101,8 +101,6 @@ var Internal = Internal || {};
|
||||
result = result | (a[i] ^ b[i]);
|
||||
}
|
||||
if (result !== 0) {
|
||||
console.log('Our MAC ', dcodeIO.ByteBuffer.wrap(calculated_mac).toHex());
|
||||
console.log('Their MAC', dcodeIO.ByteBuffer.wrap(mac).toHex());
|
||||
throw new Error("Bad MAC");
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
function testIdentityKeyStore(store, registrationId, identityKey) {
|
||||
describe('IdentityKeyStore', function() {
|
||||
var number = '+5558675309';
|
||||
var address = new libsignal.SignalProtocolAddress('+5558675309', 1);
|
||||
var testKey;
|
||||
before(function(done) {
|
||||
Internal.crypto.createKeyPair().then(function(keyPair) {
|
||||
@ -25,7 +26,7 @@ function testIdentityKeyStore(store, registrationId, identityKey) {
|
||||
});
|
||||
describe('saveIdentity', function() {
|
||||
it('stores identity keys', function(done) {
|
||||
store.saveIdentity(number, testKey.pubKey).then(function() {
|
||||
store.saveIdentity(address.toString(), testKey.pubKey).then(function() {
|
||||
return store.loadIdentityKey(number).then(function(key) {
|
||||
assertEqualArrayBuffers(key, testKey.pubKey);
|
||||
});
|
||||
@ -34,7 +35,7 @@ function testIdentityKeyStore(store, registrationId, identityKey) {
|
||||
});
|
||||
describe('isTrustedIdentity', function() {
|
||||
it('returns true if a key is trusted', function(done) {
|
||||
store.saveIdentity(number, testKey.pubKey).then(function() {
|
||||
store.saveIdentity(address.toString(), testKey.pubKey).then(function() {
|
||||
store.isTrustedIdentity(number, testKey.pubKey).then(function(trusted) {
|
||||
if (trusted) {
|
||||
done();
|
||||
@ -46,7 +47,7 @@ function testIdentityKeyStore(store, registrationId, identityKey) {
|
||||
});
|
||||
it('returns false if a key is untrusted', function(done) {
|
||||
var newIdentity = libsignal.crypto.getRandomBytes(33);
|
||||
store.saveIdentity(number, testKey.pubKey).then(function() {
|
||||
store.saveIdentity(address.toString(), testKey.pubKey).then(function() {
|
||||
store.isTrustedIdentity(number, newIdentity).then(function(trusted) {
|
||||
if (trusted) {
|
||||
done(new Error('Wrong value for untrusted key'));
|
||||
|
||||
@ -1,96 +1,112 @@
|
||||
function SignalProtocolStore() {
|
||||
this.store = {};
|
||||
function SignalProtocolStore() {
|
||||
this.store = {};
|
||||
}
|
||||
|
||||
SignalProtocolStore.prototype = {
|
||||
getIdentityKeyPair: function() {
|
||||
return Promise.resolve(this.get('identityKey'));
|
||||
},
|
||||
getLocalRegistrationId: function() {
|
||||
return Promise.resolve(this.get('registrationId'));
|
||||
},
|
||||
put: function(key, value) {
|
||||
if (key === undefined || value === undefined || key === null || value === null)
|
||||
throw new Error("Tried to store undefined/null");
|
||||
this.store[key] = value;
|
||||
},
|
||||
get: function(key, defaultValue) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error("Tried to get value for undefined/null key");
|
||||
if (key in this.store) {
|
||||
return this.store[key];
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
},
|
||||
remove: function(key) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error("Tried to remove value for undefined/null key");
|
||||
delete this.store[key];
|
||||
},
|
||||
Direction: {
|
||||
SENDING: 1,
|
||||
RECEIVING: 2,
|
||||
},
|
||||
|
||||
isTrustedIdentity: function(identifier, identityKey) {
|
||||
if (identifier === null || identifier === undefined) {
|
||||
throw new Error("tried to check identity key for undefined/null key");
|
||||
getIdentityKeyPair: function() {
|
||||
return Promise.resolve(this.get('identityKey'));
|
||||
},
|
||||
getLocalRegistrationId: function() {
|
||||
return Promise.resolve(this.get('registrationId'));
|
||||
},
|
||||
put: function(key, value) {
|
||||
if (key === undefined || value === undefined || key === null || value === null)
|
||||
throw new Error("Tried to store undefined/null");
|
||||
this.store[key] = value;
|
||||
},
|
||||
get: function(key, defaultValue) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error("Tried to get value for undefined/null key");
|
||||
if (key in this.store) {
|
||||
return this.store[key];
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
if (!(identityKey instanceof ArrayBuffer)) {
|
||||
throw new Error("Expected identityKey to be an ArrayBuffer");
|
||||
},
|
||||
remove: function(key) {
|
||||
if (key === null || key === undefined)
|
||||
throw new Error("Tried to remove value for undefined/null key");
|
||||
delete this.store[key];
|
||||
},
|
||||
|
||||
isTrustedIdentity: function(identifier, identityKey, direction) {
|
||||
if (identifier === null || identifier === undefined) {
|
||||
throw new Error("tried to check identity key for undefined/null key");
|
||||
}
|
||||
var trusted = this.get('identityKey' + identifier);
|
||||
if (!(identityKey instanceof ArrayBuffer)) {
|
||||
throw new Error("Expected identityKey to be an ArrayBuffer");
|
||||
}
|
||||
var trusted = this.get('identityKey' + identifier);
|
||||
if (trusted === undefined) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return Promise.resolve(util.toString(identityKey) === util.toString(trusted));
|
||||
},
|
||||
loadIdentityKey: function(identifier) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error("Tried to get identity key for undefined/null key");
|
||||
return Promise.resolve(this.get('identityKey' + identifier));
|
||||
},
|
||||
saveIdentity: function(identifier, identityKey) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error("Tried to put identity key for undefined/null key");
|
||||
return Promise.resolve(this.put('identityKey' + identifier, identityKey));
|
||||
},
|
||||
},
|
||||
loadIdentityKey: function(identifier) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error("Tried to get identity key for undefined/null key");
|
||||
return Promise.resolve(this.get('identityKey' + identifier));
|
||||
},
|
||||
saveIdentity: function(identifier, identityKey) {
|
||||
if (identifier === null || identifier === undefined)
|
||||
throw new Error("Tried to put identity key for undefined/null key");
|
||||
|
||||
/* Returns a prekeypair object or undefined */
|
||||
loadPreKey: function(keyId) {
|
||||
var address = new libsignal.SignalProtocolAddress.fromString(identifier);
|
||||
|
||||
var existing = this.get('identityKey' + address.getName());
|
||||
this.put('identityKey' + address.getName(), identityKey)
|
||||
|
||||
if (existing && util.toString(identityKey) !== util.toString(existing)) {
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/* Returns a prekeypair object or undefined */
|
||||
loadPreKey: function(keyId) {
|
||||
var res = this.get('25519KeypreKey' + keyId);
|
||||
if (res !== undefined) {
|
||||
res = { pubKey: res.pubKey, privKey: res.privKey };
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
},
|
||||
storePreKey: function(keyId, keyPair) {
|
||||
return Promise.resolve(this.put('25519KeypreKey' + keyId, keyPair));
|
||||
},
|
||||
removePreKey: function(keyId) {
|
||||
return Promise.resolve(this.remove('25519KeypreKey' + keyId));
|
||||
},
|
||||
},
|
||||
storePreKey: function(keyId, keyPair) {
|
||||
return Promise.resolve(this.put('25519KeypreKey' + keyId, keyPair));
|
||||
},
|
||||
removePreKey: function(keyId) {
|
||||
return Promise.resolve(this.remove('25519KeypreKey' + keyId));
|
||||
},
|
||||
|
||||
/* Returns a signed keypair object or undefined */
|
||||
loadSignedPreKey: function(keyId) {
|
||||
/* Returns a signed keypair object or undefined */
|
||||
loadSignedPreKey: function(keyId) {
|
||||
var res = this.get('25519KeysignedKey' + keyId);
|
||||
if (res !== undefined) {
|
||||
res = { pubKey: res.pubKey, privKey: res.privKey };
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
},
|
||||
storeSignedPreKey: function(keyId, keyPair) {
|
||||
return Promise.resolve(this.put('25519KeysignedKey' + keyId, keyPair));
|
||||
},
|
||||
removeSignedPreKey: function(keyId) {
|
||||
return Promise.resolve(this.remove('25519KeysignedKey' + keyId));
|
||||
},
|
||||
},
|
||||
storeSignedPreKey: function(keyId, keyPair) {
|
||||
return Promise.resolve(this.put('25519KeysignedKey' + keyId, keyPair));
|
||||
},
|
||||
removeSignedPreKey: function(keyId) {
|
||||
return Promise.resolve(this.remove('25519KeysignedKey' + keyId));
|
||||
},
|
||||
|
||||
loadSession: function(identifier) {
|
||||
return Promise.resolve(this.get('session' + identifier));
|
||||
},
|
||||
storeSession: function(identifier, record) {
|
||||
return Promise.resolve(this.put('session' + identifier, record));
|
||||
},
|
||||
loadSession: function(identifier) {
|
||||
return Promise.resolve(this.get('session' + identifier));
|
||||
},
|
||||
storeSession: function(identifier, record) {
|
||||
return Promise.resolve(this.put('session' + identifier, record));
|
||||
},
|
||||
removeSession: function(identifier) {
|
||||
return Promise.resolve(this.remove('session' + identifier));
|
||||
return Promise.resolve(this.remove('session' + identifier));
|
||||
},
|
||||
removeAllSessions: function(identifier) {
|
||||
for (var id in this.store) {
|
||||
|
||||
@ -1,51 +1,5 @@
|
||||
describe('SessionBuilder', function() {
|
||||
this.timeout(5000);
|
||||
var KeyHelper = libsignal.KeyHelper;
|
||||
|
||||
function generateIdentity(store) {
|
||||
return Promise.all([
|
||||
KeyHelper.generateIdentityKeyPair(),
|
||||
KeyHelper.generateRegistrationId(),
|
||||
]).then(function(result) {
|
||||
store.put('identityKey', result[0]);
|
||||
store.put('registrationId', result[1]);
|
||||
});
|
||||
}
|
||||
|
||||
function generatePreKeyBundle(store, preKeyId, signedPreKeyId) {
|
||||
return Promise.all([
|
||||
store.getIdentityKeyPair(),
|
||||
store.getLocalRegistrationId()
|
||||
]).then(function(result) {
|
||||
var identity = result[0];
|
||||
var registrationId = result[1];
|
||||
|
||||
return Promise.all([
|
||||
KeyHelper.generatePreKey(preKeyId),
|
||||
KeyHelper.generateSignedPreKey(identity, signedPreKeyId),
|
||||
]).then(function(keys) {
|
||||
var preKey = keys[0]
|
||||
var signedPreKey = keys[1];
|
||||
|
||||
store.storePreKey(preKeyId, preKey.keyPair);
|
||||
store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair);
|
||||
|
||||
return {
|
||||
identityKey: identity.pubKey,
|
||||
registrationId : registrationId,
|
||||
preKey: {
|
||||
keyId : preKeyId,
|
||||
publicKey : preKey.keyPair.pubKey
|
||||
},
|
||||
signedPreKey: {
|
||||
keyId : signedPreKeyId,
|
||||
publicKey : signedPreKey.keyPair.pubKey,
|
||||
signature : signedPreKey.signature
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var ALICE_ADDRESS = new SignalProtocolAddress("+14151111111", 1);
|
||||
var BOB_ADDRESS = new SignalProtocolAddress("+14152222222", 1);
|
||||
@ -142,4 +96,99 @@ describe('SessionBuilder', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("basic v3 NO PREKEY", function() {
|
||||
var aliceStore = new SignalProtocolStore();
|
||||
|
||||
var bobStore = new SignalProtocolStore();
|
||||
var bobPreKeyId = 1337;
|
||||
var bobSignedKeyId = 1;
|
||||
|
||||
var Curve = libsignal.Curve;
|
||||
|
||||
before(function(done) {
|
||||
Promise.all([
|
||||
generateIdentity(aliceStore),
|
||||
generateIdentity(bobStore),
|
||||
]).then(function() {
|
||||
return generatePreKeyBundle(bobStore, bobPreKeyId, bobSignedKeyId);
|
||||
}).then(function(preKeyBundle) {
|
||||
delete preKeyBundle.preKey;
|
||||
var builder = new libsignal.SessionBuilder(aliceStore, BOB_ADDRESS);
|
||||
return builder.processPreKey(preKeyBundle).then(function() {
|
||||
done();
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
var originalMessage = util.toArrayBuffer("L'homme est condamné à être libre");
|
||||
var aliceSessionCipher = new libsignal.SessionCipher(aliceStore, BOB_ADDRESS);
|
||||
var bobSessionCipher = new libsignal.SessionCipher(bobStore, ALICE_ADDRESS);
|
||||
|
||||
it('creates a session', function(done) {
|
||||
return aliceStore.loadSession(BOB_ADDRESS.toString()).then(function(record) {
|
||||
assert.isDefined(record);
|
||||
var sessionRecord = Internal.SessionRecord.deserialize(record);
|
||||
assert.isTrue(sessionRecord.haveOpenSession());
|
||||
assert.isDefined(sessionRecord.getOpenSession());
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
it('the session can encrypt', function(done) {
|
||||
aliceSessionCipher.encrypt(originalMessage).then(function(ciphertext) {
|
||||
|
||||
assert.strictEqual(ciphertext.type, 3); // PREKEY_BUNDLE
|
||||
|
||||
return bobSessionCipher.decryptPreKeyWhisperMessage(ciphertext.body, 'binary');
|
||||
|
||||
}).then(function(plaintext) {
|
||||
|
||||
assertEqualArrayBuffers(plaintext, originalMessage);
|
||||
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
it('the session can decrypt', function(done) {
|
||||
bobSessionCipher.encrypt(originalMessage).then(function(ciphertext) {
|
||||
|
||||
return aliceSessionCipher.decryptWhisperMessage(ciphertext.body, 'binary');
|
||||
|
||||
}).then(function(plaintext) {
|
||||
|
||||
assertEqualArrayBuffers(plaintext, originalMessage);
|
||||
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
it('accepts a new preKey with the same identity', function(done) {
|
||||
generatePreKeyBundle(bobStore, bobPreKeyId + 1, bobSignedKeyId + 1).then(function(preKeyBundle) {
|
||||
delete preKeyBundle.preKey;
|
||||
var builder = new libsignal.SessionBuilder(aliceStore, BOB_ADDRESS);
|
||||
return builder.processPreKey(preKeyBundle).then(function() {
|
||||
return aliceStore.loadSession(BOB_ADDRESS.toString()).then(function(record) {
|
||||
assert.isDefined(record);
|
||||
var sessionRecord = Internal.SessionRecord.deserialize(record);
|
||||
assert.isTrue(sessionRecord.haveOpenSession());
|
||||
assert.isDefined(sessionRecord.getOpenSession());
|
||||
done();
|
||||
});
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('rejects untrusted identity keys', function(done) {
|
||||
KeyHelper.generateIdentityKeyPair().then(function(newIdentity) {
|
||||
var builder = new libsignal.SessionBuilder(aliceStore, BOB_ADDRESS);
|
||||
return builder.processPreKey({
|
||||
identityKey: newIdentity.pubKey,
|
||||
registrationId : 12356
|
||||
}).then(function(e) {
|
||||
assert.fail('should not be trusted');
|
||||
}).catch(function(e) {
|
||||
assert.strictEqual(e.message, 'Identity key changed');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -365,4 +365,68 @@ describe('SessionCipher', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("key changes", function() {
|
||||
var ALICE_ADDRESS = new SignalProtocolAddress("+14151111111", 1);
|
||||
var BOB_ADDRESS = new SignalProtocolAddress("+14152222222", 1);
|
||||
var originalMessage = util.toArrayBuffer("L'homme est condamné à être libre");
|
||||
|
||||
var aliceStore = new SignalProtocolStore();
|
||||
|
||||
var bobStore = new SignalProtocolStore();
|
||||
var bobPreKeyId = 1337;
|
||||
var bobSignedKeyId = 1;
|
||||
|
||||
var Curve = libsignal.Curve;
|
||||
|
||||
var bobSessionCipher = new libsignal.SessionCipher(bobStore, ALICE_ADDRESS);
|
||||
|
||||
before(function(done) {
|
||||
Promise.all(
|
||||
[aliceStore, bobStore].map(generateIdentity)
|
||||
).then(function() {
|
||||
return generatePreKeyBundle(bobStore, bobPreKeyId, bobSignedKeyId);
|
||||
}).then(function(preKeyBundle) {
|
||||
var builder = new libsignal.SessionBuilder(aliceStore, BOB_ADDRESS);
|
||||
return builder.processPreKey(preKeyBundle).then(function() {
|
||||
var aliceSessionCipher = new libsignal.SessionCipher(aliceStore, BOB_ADDRESS);
|
||||
return aliceSessionCipher.encrypt(originalMessage);
|
||||
}).then(function(ciphertext) {
|
||||
return bobSessionCipher.decryptPreKeyWhisperMessage(ciphertext.body, 'binary');
|
||||
}).then(function() {
|
||||
done();
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
|
||||
describe("When bob's identity changes", function() {
|
||||
var messageFromBob;
|
||||
before(function(done) {
|
||||
return bobSessionCipher.encrypt(originalMessage).then(function(ciphertext) {
|
||||
messageFromBob = ciphertext;
|
||||
}).then(function() {
|
||||
return generateIdentity(bobStore);
|
||||
}).then(function() {
|
||||
return aliceStore.saveIdentity(BOB_ADDRESS.toString(), bobStore.get('identityKey').pubKey);
|
||||
}).then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('alice cannot encrypt with the old session', function(done) {
|
||||
var aliceSessionCipher = new libsignal.SessionCipher(aliceStore, BOB_ADDRESS);
|
||||
return aliceSessionCipher.encrypt(originalMessage).catch(function(e) {
|
||||
assert.strictEqual(e.message, 'Identity key changed');
|
||||
}).then(done,done);
|
||||
});
|
||||
|
||||
it('alice cannot decrypt from the old session', function(done) {
|
||||
var aliceSessionCipher = new libsignal.SessionCipher(aliceStore, BOB_ADDRESS);
|
||||
return aliceSessionCipher.decryptWhisperMessage(messageFromBob.body, 'binary').catch(function(e) {
|
||||
assert.strictEqual(e.message, 'Identity key changed');
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -52,3 +52,50 @@ function hexToArrayBuffer(str) {
|
||||
array[i] = parseInt(str.substr(i*2, 2), 16);
|
||||
return ret;
|
||||
};
|
||||
|
||||
var KeyHelper = libsignal.KeyHelper;
|
||||
|
||||
function generateIdentity(store) {
|
||||
return Promise.all([
|
||||
KeyHelper.generateIdentityKeyPair(),
|
||||
KeyHelper.generateRegistrationId(),
|
||||
]).then(function(result) {
|
||||
store.put('identityKey', result[0]);
|
||||
store.put('registrationId', result[1]);
|
||||
});
|
||||
}
|
||||
|
||||
function generatePreKeyBundle(store, preKeyId, signedPreKeyId) {
|
||||
return Promise.all([
|
||||
store.getIdentityKeyPair(),
|
||||
store.getLocalRegistrationId()
|
||||
]).then(function(result) {
|
||||
var identity = result[0];
|
||||
var registrationId = result[1];
|
||||
|
||||
return Promise.all([
|
||||
KeyHelper.generatePreKey(preKeyId),
|
||||
KeyHelper.generateSignedPreKey(identity, signedPreKeyId),
|
||||
]).then(function(keys) {
|
||||
var preKey = keys[0]
|
||||
var signedPreKey = keys[1];
|
||||
|
||||
store.storePreKey(preKeyId, preKey.keyPair);
|
||||
store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair);
|
||||
|
||||
return {
|
||||
identityKey: identity.pubKey,
|
||||
registrationId : registrationId,
|
||||
preKey: {
|
||||
keyId : preKeyId,
|
||||
publicKey : preKey.keyPair.pubKey
|
||||
},
|
||||
signedPreKey: {
|
||||
keyId : signedPreKeyId,
|
||||
publicKey : signedPreKey.keyPair.pubKey,
|
||||
signature : signedPreKey.signature
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
47
test/test.js
47
test/test.js
@ -34453,3 +34453,50 @@ function hexToArrayBuffer(str) {
|
||||
array[i] = parseInt(str.substr(i*2, 2), 16);
|
||||
return ret;
|
||||
};
|
||||
|
||||
var KeyHelper = libsignal.KeyHelper;
|
||||
|
||||
function generateIdentity(store) {
|
||||
return Promise.all([
|
||||
KeyHelper.generateIdentityKeyPair(),
|
||||
KeyHelper.generateRegistrationId(),
|
||||
]).then(function(result) {
|
||||
store.put('identityKey', result[0]);
|
||||
store.put('registrationId', result[1]);
|
||||
});
|
||||
}
|
||||
|
||||
function generatePreKeyBundle(store, preKeyId, signedPreKeyId) {
|
||||
return Promise.all([
|
||||
store.getIdentityKeyPair(),
|
||||
store.getLocalRegistrationId()
|
||||
]).then(function(result) {
|
||||
var identity = result[0];
|
||||
var registrationId = result[1];
|
||||
|
||||
return Promise.all([
|
||||
KeyHelper.generatePreKey(preKeyId),
|
||||
KeyHelper.generateSignedPreKey(identity, signedPreKeyId),
|
||||
]).then(function(keys) {
|
||||
var preKey = keys[0]
|
||||
var signedPreKey = keys[1];
|
||||
|
||||
store.storePreKey(preKeyId, preKey.keyPair);
|
||||
store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair);
|
||||
|
||||
return {
|
||||
identityKey: identity.pubKey,
|
||||
registrationId : registrationId,
|
||||
preKey: {
|
||||
keyId : preKeyId,
|
||||
publicKey : preKey.keyPair.pubKey
|
||||
},
|
||||
signedPreKey: {
|
||||
keyId : signedPreKeyId,
|
||||
publicKey : signedPreKey.keyPair.pubKey,
|
||||
signature : signedPreKey.signature
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user