@unknownncat/swt-libsignal 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base_key_type.d.ts +5 -0
- package/dist/base_key_type.js +4 -0
- package/dist/chain_type.d.ts +5 -0
- package/dist/chain_type.js +4 -0
- package/dist/crypto.d.ts +2 -0
- package/dist/crypto.js +95 -0
- package/dist/curve.d.ts +5 -0
- package/dist/curve.js +67 -0
- package/dist/fingerprint.d.ts +5 -0
- package/dist/fingerprint.js +76 -0
- package/dist/generated/WhisperTextProtocol.d.ts +49 -0
- package/dist/generated/WhisperTextProtocol.js +199 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +13 -0
- package/dist/job_queue.d.ts +3 -0
- package/dist/job_queue.js +48 -0
- package/dist/key-helper.d.ts +14 -0
- package/dist/key-helper.js +42 -0
- package/dist/protobuf.d.ts +1 -0
- package/dist/protobuf.js +2 -0
- package/dist/protocol_address.d.ts +9 -0
- package/dist/protocol_address.js +50 -0
- package/dist/session/builder/index.d.ts +2 -0
- package/dist/session/builder/index.js +2 -0
- package/dist/session/builder/session-builder.d.ts +13 -0
- package/dist/session/builder/session-builder.js +148 -0
- package/dist/session/builder/types.d.ts +38 -0
- package/dist/session/builder/types.js +1 -0
- package/dist/session/cipher/encoding.d.ts +13 -0
- package/dist/session/cipher/encoding.js +135 -0
- package/dist/session/cipher/index.d.ts +3 -0
- package/dist/session/cipher/index.js +3 -0
- package/dist/session/cipher/session-cipher.d.ts +26 -0
- package/dist/session/cipher/session-cipher.js +300 -0
- package/dist/session/cipher/types.d.ts +47 -0
- package/dist/session/cipher/types.js +1 -0
- package/dist/session/constants.d.ts +3 -0
- package/dist/session/constants.js +3 -0
- package/dist/session/index.d.ts +3 -0
- package/dist/session/index.js +3 -0
- package/dist/session/record/index.d.ts +3 -0
- package/dist/session/record/index.js +3 -0
- package/dist/session/record/session-entry.d.ts +20 -0
- package/dist/session/record/session-entry.js +146 -0
- package/dist/session/record/session-record.d.ts +21 -0
- package/dist/session/record/session-record.js +95 -0
- package/dist/session/record/types.d.ts +71 -0
- package/dist/session/record/types.js +1 -0
- package/dist/session/utils.d.ts +7 -0
- package/dist/session/utils.js +18 -0
- package/dist/signal-errors.d.ts +18 -0
- package/dist/signal-errors.js +24 -0
- package/dist/teste.d.ts +1 -0
- package/dist/teste.js +18 -0
- package/package.json +40 -0
package/dist/crypto.d.ts
ADDED
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHmac, createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
const EMPTY_BUFFER = Buffer.alloc(0);
|
|
3
|
+
function toBuffer(data) {
|
|
4
|
+
return Buffer.isBuffer(data)
|
|
5
|
+
? data
|
|
6
|
+
: Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
7
|
+
}
|
|
8
|
+
function toUint8(data) {
|
|
9
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
10
|
+
}
|
|
11
|
+
async function encrypt(key, plaintext, options) {
|
|
12
|
+
const k = toBuffer(key);
|
|
13
|
+
if (k.length !== 32) {
|
|
14
|
+
throw new Error('Key must be 32 bytes');
|
|
15
|
+
}
|
|
16
|
+
const iv = options?.iv
|
|
17
|
+
? toBuffer(options.iv)
|
|
18
|
+
: randomBytes(12);
|
|
19
|
+
const cipher = createCipheriv('aes-256-gcm', k, iv);
|
|
20
|
+
if (options?.aad) {
|
|
21
|
+
cipher.setAAD(toBuffer(options.aad));
|
|
22
|
+
}
|
|
23
|
+
const plainBuf = toBuffer(plaintext);
|
|
24
|
+
const encrypted = cipher.update(plainBuf);
|
|
25
|
+
const final = cipher.final();
|
|
26
|
+
const ciphertext = encrypted.length === 0
|
|
27
|
+
? final
|
|
28
|
+
: encrypted.length === final.length
|
|
29
|
+
? Buffer.concat([encrypted, final], encrypted.length + final.length)
|
|
30
|
+
: Buffer.concat([encrypted, final]);
|
|
31
|
+
const tag = cipher.getAuthTag();
|
|
32
|
+
return {
|
|
33
|
+
ciphertext: toUint8(ciphertext),
|
|
34
|
+
iv: toUint8(iv),
|
|
35
|
+
tag: toUint8(tag)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function decrypt(key, data, options) {
|
|
39
|
+
const k = toBuffer(key);
|
|
40
|
+
const decipher = createDecipheriv('aes-256-gcm', k, toBuffer(data.iv));
|
|
41
|
+
if (options?.aad) {
|
|
42
|
+
decipher.setAAD(toBuffer(options.aad));
|
|
43
|
+
}
|
|
44
|
+
decipher.setAuthTag(toBuffer(data.tag));
|
|
45
|
+
const cipherBuf = toBuffer(data.ciphertext);
|
|
46
|
+
const decrypted = decipher.update(cipherBuf);
|
|
47
|
+
const final = decipher.final();
|
|
48
|
+
const plaintext = decrypted.length === 0
|
|
49
|
+
? final
|
|
50
|
+
: decrypted.length === final.length
|
|
51
|
+
? Buffer.concat([decrypted, final], decrypted.length + final.length)
|
|
52
|
+
: Buffer.concat([decrypted, final]);
|
|
53
|
+
return toUint8(plaintext);
|
|
54
|
+
}
|
|
55
|
+
function hkdf(ikm, salt, info, options) {
|
|
56
|
+
const length = options.length;
|
|
57
|
+
const hashLen = 32;
|
|
58
|
+
const blocksNeeded = Math.ceil(length / hashLen);
|
|
59
|
+
const prk = createHmac('sha256', toBuffer(salt))
|
|
60
|
+
.update(toBuffer(ikm))
|
|
61
|
+
.digest();
|
|
62
|
+
const output = Buffer.allocUnsafe(length);
|
|
63
|
+
const infoBuf = toBuffer(info);
|
|
64
|
+
let prev = EMPTY_BUFFER;
|
|
65
|
+
const infoWithCounter = Buffer.allocUnsafe(infoBuf.length + 1);
|
|
66
|
+
infoBuf.copy(infoWithCounter, 0);
|
|
67
|
+
for (let i = 0; i < blocksNeeded; i++) {
|
|
68
|
+
const hmac = createHmac('sha256', prk);
|
|
69
|
+
if (prev.length)
|
|
70
|
+
hmac.update(prev);
|
|
71
|
+
hmac.update(infoWithCounter.subarray(0, infoBuf.length));
|
|
72
|
+
infoWithCounter[infoBuf.length] = i + 1;
|
|
73
|
+
prev = hmac.digest();
|
|
74
|
+
const copyLen = Math.min(hashLen, length - i * hashLen);
|
|
75
|
+
prev.copy(output, i * hashLen, 0, copyLen);
|
|
76
|
+
}
|
|
77
|
+
return toUint8(output);
|
|
78
|
+
}
|
|
79
|
+
function sha512(data) {
|
|
80
|
+
return toUint8(createHash('sha512')
|
|
81
|
+
.update(toBuffer(data))
|
|
82
|
+
.digest());
|
|
83
|
+
}
|
|
84
|
+
function hmacSha256(key, data) {
|
|
85
|
+
return toUint8(createHmac('sha256', toBuffer(key))
|
|
86
|
+
.update(toBuffer(data))
|
|
87
|
+
.digest());
|
|
88
|
+
}
|
|
89
|
+
export const crypto = {
|
|
90
|
+
encrypt,
|
|
91
|
+
decrypt,
|
|
92
|
+
hkdf,
|
|
93
|
+
sha512,
|
|
94
|
+
hmacSha256
|
|
95
|
+
};
|
package/dist/curve.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DHKeyPair, SignalAsymmetricAPI } from '../types/asymmetric.js';
|
|
2
|
+
declare function generateKeyPair(): Promise<DHKeyPair>;
|
|
3
|
+
declare function calculateSignature(identityPrivateKey: Uint8Array, data: Uint8Array): Uint8Array<ArrayBufferLike>;
|
|
4
|
+
export declare const signalCrypto: SignalAsymmetricAPI;
|
|
5
|
+
export { generateKeyPair, calculateSignature };
|
package/dist/curve.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import libsodium from 'libsodium-wrappers';
|
|
2
|
+
let sodiumReady = null;
|
|
3
|
+
function ensureReady() {
|
|
4
|
+
if (!sodiumReady) {
|
|
5
|
+
sodiumReady = libsodium.ready;
|
|
6
|
+
}
|
|
7
|
+
return sodiumReady;
|
|
8
|
+
}
|
|
9
|
+
function assertLength(data, expected, name) {
|
|
10
|
+
if (data.length !== expected) {
|
|
11
|
+
throw new Error(`${name} must be ${expected} bytes`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async function generateIdentityKeyPair() {
|
|
15
|
+
await ensureReady();
|
|
16
|
+
const kp = libsodium.crypto_sign_keypair();
|
|
17
|
+
return {
|
|
18
|
+
publicKey: kp.publicKey,
|
|
19
|
+
privateKey: kp.privateKey
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function sign(privateKey, message) {
|
|
23
|
+
assertLength(privateKey, 64, 'Ed25519 private key');
|
|
24
|
+
return libsodium.crypto_sign_detached(message, privateKey);
|
|
25
|
+
}
|
|
26
|
+
function verify(publicKey, message, signature) {
|
|
27
|
+
assertLength(publicKey, 32, 'Ed25519 public key');
|
|
28
|
+
assertLength(signature, 64, 'Signature');
|
|
29
|
+
return libsodium.crypto_sign_verify_detached(signature, message, publicKey);
|
|
30
|
+
}
|
|
31
|
+
async function generateDHKeyPair() {
|
|
32
|
+
await ensureReady();
|
|
33
|
+
const kp = libsodium.crypto_kx_keypair();
|
|
34
|
+
return {
|
|
35
|
+
publicKey: kp.publicKey,
|
|
36
|
+
privateKey: kp.privateKey
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function calculateAgreement(publicKey, privateKey) {
|
|
40
|
+
assertLength(publicKey, 32, 'X25519 public key');
|
|
41
|
+
assertLength(privateKey, 32, 'X25519 private key');
|
|
42
|
+
return libsodium.crypto_scalarmult(privateKey, publicKey);
|
|
43
|
+
}
|
|
44
|
+
function convertIdentityPublicToX25519(edPublicKey) {
|
|
45
|
+
assertLength(edPublicKey, 32, 'Ed25519 public key');
|
|
46
|
+
return libsodium.crypto_sign_ed25519_pk_to_curve25519(edPublicKey);
|
|
47
|
+
}
|
|
48
|
+
function convertIdentityPrivateToX25519(edPrivateKey) {
|
|
49
|
+
assertLength(edPrivateKey, 64, 'Ed25519 private key');
|
|
50
|
+
return libsodium.crypto_sign_ed25519_sk_to_curve25519(edPrivateKey);
|
|
51
|
+
}
|
|
52
|
+
async function generateKeyPair() {
|
|
53
|
+
return generateDHKeyPair();
|
|
54
|
+
}
|
|
55
|
+
function calculateSignature(identityPrivateKey, data) {
|
|
56
|
+
return sign(identityPrivateKey, data);
|
|
57
|
+
}
|
|
58
|
+
export const signalCrypto = {
|
|
59
|
+
generateIdentityKeyPair,
|
|
60
|
+
sign,
|
|
61
|
+
verify,
|
|
62
|
+
generateDHKeyPair,
|
|
63
|
+
calculateAgreement,
|
|
64
|
+
convertIdentityPublicToX25519,
|
|
65
|
+
convertIdentityPrivateToX25519
|
|
66
|
+
};
|
|
67
|
+
export { generateKeyPair, calculateSignature };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { crypto } from './crypto.js';
|
|
2
|
+
const VERSION = 0;
|
|
3
|
+
function numberToUint16BE(num) {
|
|
4
|
+
const out = new Uint8Array(2);
|
|
5
|
+
out[0] = num >> 8;
|
|
6
|
+
out[1] = num & 0xff;
|
|
7
|
+
return out;
|
|
8
|
+
}
|
|
9
|
+
function concatBytes(...arrays) {
|
|
10
|
+
const total = arrays.reduce((sum, a) => sum + (a?.length ?? 0), 0);
|
|
11
|
+
const result = new Uint8Array(total);
|
|
12
|
+
let offset = 0;
|
|
13
|
+
for (const arr of arrays) {
|
|
14
|
+
if (arr) {
|
|
15
|
+
result.set(arr, offset);
|
|
16
|
+
offset += arr.length;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function stringToUtf8(str) {
|
|
22
|
+
return new TextEncoder().encode(str);
|
|
23
|
+
}
|
|
24
|
+
function iterateHash(data, key, count) {
|
|
25
|
+
let result = data;
|
|
26
|
+
for (let i = 0; i < count; i++) {
|
|
27
|
+
result = crypto.sha512(concatBytes(result, key));
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function getEncodedChunk(hash, offset) {
|
|
32
|
+
if (hash.length < offset + 5) {
|
|
33
|
+
throw new Error('Hash output too small');
|
|
34
|
+
}
|
|
35
|
+
const chunk = (hash[offset] * 2 ** 32 +
|
|
36
|
+
hash[offset + 1] * 2 ** 24 +
|
|
37
|
+
hash[offset + 2] * 2 ** 16 +
|
|
38
|
+
hash[offset + 3] * 2 ** 8 +
|
|
39
|
+
hash[offset + 4]) % 100000;
|
|
40
|
+
return chunk.toString().padStart(5, '0');
|
|
41
|
+
}
|
|
42
|
+
function getDisplayStringFor(identifier, key, iterations) {
|
|
43
|
+
const versionBytes = numberToUint16BE(VERSION);
|
|
44
|
+
const combined = concatBytes(versionBytes, key, stringToUtf8(identifier));
|
|
45
|
+
const output = iterateHash(combined, key, iterations);
|
|
46
|
+
return (getEncodedChunk(output, 0) +
|
|
47
|
+
getEncodedChunk(output, 5) +
|
|
48
|
+
getEncodedChunk(output, 10) +
|
|
49
|
+
getEncodedChunk(output, 15) +
|
|
50
|
+
getEncodedChunk(output, 20) +
|
|
51
|
+
getEncodedChunk(output, 25));
|
|
52
|
+
}
|
|
53
|
+
export class FingerprintGenerator {
|
|
54
|
+
iterations;
|
|
55
|
+
constructor(iterations) {
|
|
56
|
+
if (!Number.isInteger(iterations) || iterations <= 0) {
|
|
57
|
+
throw new Error('iterations must be a positive integer');
|
|
58
|
+
}
|
|
59
|
+
this.iterations = iterations;
|
|
60
|
+
}
|
|
61
|
+
createFor(localIdentifier, localIdentityKey, remoteIdentifier, remoteIdentityKey) {
|
|
62
|
+
if (typeof localIdentifier !== 'string' ||
|
|
63
|
+
typeof remoteIdentifier !== 'string') {
|
|
64
|
+
throw new Error('Identifiers must be strings');
|
|
65
|
+
}
|
|
66
|
+
if (!(localIdentityKey instanceof Uint8Array) ||
|
|
67
|
+
!(remoteIdentityKey instanceof Uint8Array)) {
|
|
68
|
+
throw new Error('Identity keys must be Uint8Array');
|
|
69
|
+
}
|
|
70
|
+
const localFp = getDisplayStringFor(localIdentifier, localIdentityKey, this.iterations);
|
|
71
|
+
const remoteFp = getDisplayStringFor(remoteIdentifier, remoteIdentityKey, this.iterations);
|
|
72
|
+
return [localFp, remoteFp]
|
|
73
|
+
.sort()
|
|
74
|
+
.join('');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
|
2
|
+
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
|
3
|
+
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
|
4
|
+
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
|
5
|
+
import type { PartialMessage } from "@protobuf-ts/runtime";
|
|
6
|
+
import { MessageType } from "@protobuf-ts/runtime";
|
|
7
|
+
export interface WhisperMessage {
|
|
8
|
+
ephemeralKey?: Uint8Array;
|
|
9
|
+
counter?: number;
|
|
10
|
+
previousCounter?: number;
|
|
11
|
+
ciphertext?: Uint8Array;
|
|
12
|
+
}
|
|
13
|
+
export interface PreKeyWhisperMessage {
|
|
14
|
+
registrationId?: number;
|
|
15
|
+
preKeyId?: number;
|
|
16
|
+
signedPreKeyId?: number;
|
|
17
|
+
baseKey?: Uint8Array;
|
|
18
|
+
identityKey?: Uint8Array;
|
|
19
|
+
message?: Uint8Array;
|
|
20
|
+
}
|
|
21
|
+
export interface KeyExchangeMessage {
|
|
22
|
+
id?: number;
|
|
23
|
+
baseKey?: Uint8Array;
|
|
24
|
+
ephemeralKey?: Uint8Array;
|
|
25
|
+
identityKey?: Uint8Array;
|
|
26
|
+
baseKeySignature?: Uint8Array;
|
|
27
|
+
}
|
|
28
|
+
declare class WhisperMessage$Type extends MessageType<WhisperMessage> {
|
|
29
|
+
constructor();
|
|
30
|
+
create(value?: PartialMessage<WhisperMessage>): WhisperMessage;
|
|
31
|
+
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WhisperMessage): WhisperMessage;
|
|
32
|
+
internalBinaryWrite(message: WhisperMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
33
|
+
}
|
|
34
|
+
export declare const WhisperMessage: WhisperMessage$Type;
|
|
35
|
+
declare class PreKeyWhisperMessage$Type extends MessageType<PreKeyWhisperMessage> {
|
|
36
|
+
constructor();
|
|
37
|
+
create(value?: PartialMessage<PreKeyWhisperMessage>): PreKeyWhisperMessage;
|
|
38
|
+
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PreKeyWhisperMessage): PreKeyWhisperMessage;
|
|
39
|
+
internalBinaryWrite(message: PreKeyWhisperMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
40
|
+
}
|
|
41
|
+
export declare const PreKeyWhisperMessage: PreKeyWhisperMessage$Type;
|
|
42
|
+
declare class KeyExchangeMessage$Type extends MessageType<KeyExchangeMessage> {
|
|
43
|
+
constructor();
|
|
44
|
+
create(value?: PartialMessage<KeyExchangeMessage>): KeyExchangeMessage;
|
|
45
|
+
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: KeyExchangeMessage): KeyExchangeMessage;
|
|
46
|
+
internalBinaryWrite(message: KeyExchangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
47
|
+
}
|
|
48
|
+
export declare const KeyExchangeMessage: KeyExchangeMessage$Type;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { WireType } from "@protobuf-ts/runtime";
|
|
2
|
+
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
|
3
|
+
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
|
4
|
+
import { MessageType } from "@protobuf-ts/runtime";
|
|
5
|
+
class WhisperMessage$Type extends MessageType {
|
|
6
|
+
constructor() {
|
|
7
|
+
super("textsecure.WhisperMessage", [
|
|
8
|
+
{ no: 1, name: "ephemeral_key", kind: "scalar", opt: true, T: 12 },
|
|
9
|
+
{ no: 2, name: "counter", kind: "scalar", opt: true, T: 13 },
|
|
10
|
+
{ no: 3, name: "previous_counter", kind: "scalar", opt: true, T: 13 },
|
|
11
|
+
{ no: 4, name: "ciphertext", kind: "scalar", opt: true, T: 12 }
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
create(value) {
|
|
15
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
16
|
+
if (value !== undefined)
|
|
17
|
+
reflectionMergePartial(this, message, value);
|
|
18
|
+
return message;
|
|
19
|
+
}
|
|
20
|
+
internalBinaryRead(reader, length, options, target) {
|
|
21
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
22
|
+
while (reader.pos < end) {
|
|
23
|
+
let [fieldNo, wireType] = reader.tag();
|
|
24
|
+
switch (fieldNo) {
|
|
25
|
+
case 1:
|
|
26
|
+
message.ephemeralKey = reader.bytes();
|
|
27
|
+
break;
|
|
28
|
+
case 2:
|
|
29
|
+
message.counter = reader.uint32();
|
|
30
|
+
break;
|
|
31
|
+
case 3:
|
|
32
|
+
message.previousCounter = reader.uint32();
|
|
33
|
+
break;
|
|
34
|
+
case 4:
|
|
35
|
+
message.ciphertext = reader.bytes();
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
let u = options.readUnknownField;
|
|
39
|
+
if (u === "throw")
|
|
40
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
41
|
+
let d = reader.skip(wireType);
|
|
42
|
+
if (u !== false)
|
|
43
|
+
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return message;
|
|
47
|
+
}
|
|
48
|
+
internalBinaryWrite(message, writer, options) {
|
|
49
|
+
if (message.ephemeralKey !== undefined)
|
|
50
|
+
writer.tag(1, WireType.LengthDelimited).bytes(message.ephemeralKey);
|
|
51
|
+
if (message.counter !== undefined)
|
|
52
|
+
writer.tag(2, WireType.Varint).uint32(message.counter);
|
|
53
|
+
if (message.previousCounter !== undefined)
|
|
54
|
+
writer.tag(3, WireType.Varint).uint32(message.previousCounter);
|
|
55
|
+
if (message.ciphertext !== undefined)
|
|
56
|
+
writer.tag(4, WireType.LengthDelimited).bytes(message.ciphertext);
|
|
57
|
+
let u = options.writeUnknownFields;
|
|
58
|
+
if (u !== false)
|
|
59
|
+
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
60
|
+
return writer;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export const WhisperMessage = new WhisperMessage$Type();
|
|
64
|
+
class PreKeyWhisperMessage$Type extends MessageType {
|
|
65
|
+
constructor() {
|
|
66
|
+
super("textsecure.PreKeyWhisperMessage", [
|
|
67
|
+
{ no: 5, name: "registration_id", kind: "scalar", opt: true, T: 13 },
|
|
68
|
+
{ no: 1, name: "pre_key_id", kind: "scalar", opt: true, T: 13 },
|
|
69
|
+
{ no: 6, name: "signed_pre_key_id", kind: "scalar", opt: true, T: 13 },
|
|
70
|
+
{ no: 2, name: "base_key", kind: "scalar", opt: true, T: 12 },
|
|
71
|
+
{ no: 3, name: "identity_key", kind: "scalar", opt: true, T: 12 },
|
|
72
|
+
{ no: 4, name: "message", kind: "scalar", opt: true, T: 12 }
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
create(value) {
|
|
76
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
77
|
+
if (value !== undefined)
|
|
78
|
+
reflectionMergePartial(this, message, value);
|
|
79
|
+
return message;
|
|
80
|
+
}
|
|
81
|
+
internalBinaryRead(reader, length, options, target) {
|
|
82
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
83
|
+
while (reader.pos < end) {
|
|
84
|
+
let [fieldNo, wireType] = reader.tag();
|
|
85
|
+
switch (fieldNo) {
|
|
86
|
+
case 5:
|
|
87
|
+
message.registrationId = reader.uint32();
|
|
88
|
+
break;
|
|
89
|
+
case 1:
|
|
90
|
+
message.preKeyId = reader.uint32();
|
|
91
|
+
break;
|
|
92
|
+
case 6:
|
|
93
|
+
message.signedPreKeyId = reader.uint32();
|
|
94
|
+
break;
|
|
95
|
+
case 2:
|
|
96
|
+
message.baseKey = reader.bytes();
|
|
97
|
+
break;
|
|
98
|
+
case 3:
|
|
99
|
+
message.identityKey = reader.bytes();
|
|
100
|
+
break;
|
|
101
|
+
case 4:
|
|
102
|
+
message.message = reader.bytes();
|
|
103
|
+
break;
|
|
104
|
+
default:
|
|
105
|
+
let u = options.readUnknownField;
|
|
106
|
+
if (u === "throw")
|
|
107
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
108
|
+
let d = reader.skip(wireType);
|
|
109
|
+
if (u !== false)
|
|
110
|
+
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return message;
|
|
114
|
+
}
|
|
115
|
+
internalBinaryWrite(message, writer, options) {
|
|
116
|
+
if (message.preKeyId !== undefined)
|
|
117
|
+
writer.tag(1, WireType.Varint).uint32(message.preKeyId);
|
|
118
|
+
if (message.baseKey !== undefined)
|
|
119
|
+
writer.tag(2, WireType.LengthDelimited).bytes(message.baseKey);
|
|
120
|
+
if (message.identityKey !== undefined)
|
|
121
|
+
writer.tag(3, WireType.LengthDelimited).bytes(message.identityKey);
|
|
122
|
+
if (message.message !== undefined)
|
|
123
|
+
writer.tag(4, WireType.LengthDelimited).bytes(message.message);
|
|
124
|
+
if (message.registrationId !== undefined)
|
|
125
|
+
writer.tag(5, WireType.Varint).uint32(message.registrationId);
|
|
126
|
+
if (message.signedPreKeyId !== undefined)
|
|
127
|
+
writer.tag(6, WireType.Varint).uint32(message.signedPreKeyId);
|
|
128
|
+
let u = options.writeUnknownFields;
|
|
129
|
+
if (u !== false)
|
|
130
|
+
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
131
|
+
return writer;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export const PreKeyWhisperMessage = new PreKeyWhisperMessage$Type();
|
|
135
|
+
class KeyExchangeMessage$Type extends MessageType {
|
|
136
|
+
constructor() {
|
|
137
|
+
super("textsecure.KeyExchangeMessage", [
|
|
138
|
+
{ no: 1, name: "id", kind: "scalar", opt: true, T: 13 },
|
|
139
|
+
{ no: 2, name: "base_key", kind: "scalar", opt: true, T: 12 },
|
|
140
|
+
{ no: 3, name: "ephemeral_key", kind: "scalar", opt: true, T: 12 },
|
|
141
|
+
{ no: 4, name: "identity_key", kind: "scalar", opt: true, T: 12 },
|
|
142
|
+
{ no: 5, name: "base_key_signature", kind: "scalar", opt: true, T: 12 }
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
create(value) {
|
|
146
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
147
|
+
if (value !== undefined)
|
|
148
|
+
reflectionMergePartial(this, message, value);
|
|
149
|
+
return message;
|
|
150
|
+
}
|
|
151
|
+
internalBinaryRead(reader, length, options, target) {
|
|
152
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
153
|
+
while (reader.pos < end) {
|
|
154
|
+
let [fieldNo, wireType] = reader.tag();
|
|
155
|
+
switch (fieldNo) {
|
|
156
|
+
case 1:
|
|
157
|
+
message.id = reader.uint32();
|
|
158
|
+
break;
|
|
159
|
+
case 2:
|
|
160
|
+
message.baseKey = reader.bytes();
|
|
161
|
+
break;
|
|
162
|
+
case 3:
|
|
163
|
+
message.ephemeralKey = reader.bytes();
|
|
164
|
+
break;
|
|
165
|
+
case 4:
|
|
166
|
+
message.identityKey = reader.bytes();
|
|
167
|
+
break;
|
|
168
|
+
case 5:
|
|
169
|
+
message.baseKeySignature = reader.bytes();
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
let u = options.readUnknownField;
|
|
173
|
+
if (u === "throw")
|
|
174
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
175
|
+
let d = reader.skip(wireType);
|
|
176
|
+
if (u !== false)
|
|
177
|
+
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return message;
|
|
181
|
+
}
|
|
182
|
+
internalBinaryWrite(message, writer, options) {
|
|
183
|
+
if (message.id !== undefined)
|
|
184
|
+
writer.tag(1, WireType.Varint).uint32(message.id);
|
|
185
|
+
if (message.baseKey !== undefined)
|
|
186
|
+
writer.tag(2, WireType.LengthDelimited).bytes(message.baseKey);
|
|
187
|
+
if (message.ephemeralKey !== undefined)
|
|
188
|
+
writer.tag(3, WireType.LengthDelimited).bytes(message.ephemeralKey);
|
|
189
|
+
if (message.identityKey !== undefined)
|
|
190
|
+
writer.tag(4, WireType.LengthDelimited).bytes(message.identityKey);
|
|
191
|
+
if (message.baseKeySignature !== undefined)
|
|
192
|
+
writer.tag(5, WireType.LengthDelimited).bytes(message.baseKeySignature);
|
|
193
|
+
let u = options.writeUnknownFields;
|
|
194
|
+
if (u !== false)
|
|
195
|
+
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
196
|
+
return writer;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export const KeyExchangeMessage = new KeyExchangeMessage$Type();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { ProtocolAddress } from './protocol_address.js';
|
|
2
|
+
export { SessionRecord, SessionEntry } from './session/record/index.js';
|
|
3
|
+
export type { ChainKey, ChainState, CurrentRatchet, IndexInfo } from './session/record/index.js';
|
|
4
|
+
export { SessionCipher } from './session/cipher/index.js';
|
|
5
|
+
export type { EncryptResult, DecryptResult, DecryptWithSessionResult, SessionCipherStorage } from './session/cipher/index.js';
|
|
6
|
+
export { SessionBuilder } from './session/builder/session-builder.js';
|
|
7
|
+
export type { PreKeyBundle, SessionBuilderStorage, KeyPair, IdentityKeyPair } from './session/builder/index.js';
|
|
8
|
+
export { crypto } from './crypto.js';
|
|
9
|
+
export { signalCrypto, generateKeyPair, calculateSignature } from './curve.js';
|
|
10
|
+
export type { CryptoAPI } from '../types/crypto.js';
|
|
11
|
+
export type { SignalAsymmetricAPI, IdentityKeyPair as AsymIdentityKeyPair, DHKeyPair } from '../types/asymmetric.js';
|
|
12
|
+
export { generateIdentityKeyPair, generateRegistrationId, generateSignedPreKey, generatePreKey } from './key-helper.js';
|
|
13
|
+
export type { SignedPreKey, PreKey } from './key-helper.js';
|
|
14
|
+
export { FingerprintGenerator } from './fingerprint.js';
|
|
15
|
+
export { SignalError, UntrustedIdentityKeyError, SessionError, MessageCounterError, PreKeyError } from './signal-errors.js';
|
|
16
|
+
export { ChainType } from './chain_type.js';
|
|
17
|
+
export { BaseKeyType } from './base_key_type.js';
|
|
18
|
+
export type { BaseKeyType as BaseKeyTypeValue } from './base_key_type.js';
|
|
19
|
+
export { PreKeyWhisperMessage, WhisperMessage } from './protobuf.js';
|
|
20
|
+
export { enqueue } from './job_queue.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { ProtocolAddress } from './protocol_address.js';
|
|
2
|
+
export { SessionRecord, SessionEntry } from './session/record/index.js';
|
|
3
|
+
export { SessionCipher } from './session/cipher/index.js';
|
|
4
|
+
export { SessionBuilder } from './session/builder/session-builder.js';
|
|
5
|
+
export { crypto } from './crypto.js';
|
|
6
|
+
export { signalCrypto, generateKeyPair, calculateSignature } from './curve.js';
|
|
7
|
+
export { generateIdentityKeyPair, generateRegistrationId, generateSignedPreKey, generatePreKey } from './key-helper.js';
|
|
8
|
+
export { FingerprintGenerator } from './fingerprint.js';
|
|
9
|
+
export { SignalError, UntrustedIdentityKeyError, SessionError, MessageCounterError, PreKeyError } from './signal-errors.js';
|
|
10
|
+
export { ChainType } from './chain_type.js';
|
|
11
|
+
export { BaseKeyType } from './base_key_type.js';
|
|
12
|
+
export { PreKeyWhisperMessage, WhisperMessage } from './protobuf.js';
|
|
13
|
+
export { enqueue } from './job_queue.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const queueBuckets = new Map();
|
|
2
|
+
const GC_LIMIT = 10_000;
|
|
3
|
+
async function asyncQueueExecutor(bucket, state) {
|
|
4
|
+
const queue = state.queue;
|
|
5
|
+
while (state.offset < queue.length) {
|
|
6
|
+
const limit = Math.min(queue.length, state.offset + GC_LIMIT);
|
|
7
|
+
for (let i = state.offset; i < limit; i++) {
|
|
8
|
+
const job = queue[i];
|
|
9
|
+
if (!job)
|
|
10
|
+
continue;
|
|
11
|
+
try {
|
|
12
|
+
const result = await job.awaitable();
|
|
13
|
+
job.resolve(result);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
job.reject(err);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
state.offset = limit;
|
|
20
|
+
if (limit < queue.length) {
|
|
21
|
+
queue.splice(0, limit);
|
|
22
|
+
state.offset = 0;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
state.running = false;
|
|
26
|
+
queueBuckets.delete(bucket);
|
|
27
|
+
}
|
|
28
|
+
export function enqueue(bucket, awaitable) {
|
|
29
|
+
let state = queueBuckets.get(bucket);
|
|
30
|
+
const isInactive = !state;
|
|
31
|
+
if (!state) {
|
|
32
|
+
state = {
|
|
33
|
+
queue: [],
|
|
34
|
+
offset: 0,
|
|
35
|
+
running: false
|
|
36
|
+
};
|
|
37
|
+
queueBuckets.set(bucket, state);
|
|
38
|
+
}
|
|
39
|
+
const queue = state.queue;
|
|
40
|
+
const jobPromise = new Promise((resolve, reject) => {
|
|
41
|
+
queue.push({ awaitable, resolve, reject });
|
|
42
|
+
});
|
|
43
|
+
if (isInactive) {
|
|
44
|
+
state.running = true;
|
|
45
|
+
void asyncQueueExecutor(bucket, state);
|
|
46
|
+
}
|
|
47
|
+
return jobPromise;
|
|
48
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IdentityKeyPair, DHKeyPair } from '../types/asymmetric.js';
|
|
2
|
+
export interface SignedPreKey {
|
|
3
|
+
keyId: number;
|
|
4
|
+
keyPair: DHKeyPair;
|
|
5
|
+
signature: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
export interface PreKey {
|
|
8
|
+
keyId: number;
|
|
9
|
+
keyPair: DHKeyPair;
|
|
10
|
+
}
|
|
11
|
+
export declare const generateIdentityKeyPair: () => Promise<IdentityKeyPair>;
|
|
12
|
+
export declare function generateRegistrationId(): number;
|
|
13
|
+
export declare function generateSignedPreKey(identityKeyPair: IdentityKeyPair, signedKeyId: number): Promise<SignedPreKey>;
|
|
14
|
+
export declare function generatePreKey(keyId: number): Promise<PreKey>;
|