@freesignal/protocol 0.1.0 → 0.1.5
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/README.md +34 -0
- package/crypto.d.ts +15 -6
- package/crypto.js +24 -4
- package/data.d.ts +14 -54
- package/data.js +76 -132
- package/double-ratchet.d.ts +26 -42
- package/double-ratchet.js +90 -142
- package/index.d.ts +46 -0
- package/index.js +66 -0
- package/package.json +2 -1
- package/test.js +20 -6
- package/types.d.ts +61 -0
- package/types.js +29 -0
- package/utils.js +1 -0
- package/x3dh.d.ts +17 -47
- package/x3dh.js +86 -90
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# freesignal-protocol
|
|
2
|
+
|
|
3
|
+
This library implements a secure messaging protocol inspired by Signal, with support for encryption, data management, and key exchange.
|
|
4
|
+
|
|
5
|
+
## Main File Structure
|
|
6
|
+
|
|
7
|
+
- **[src/crypto.ts](src/crypto.ts)**
|
|
8
|
+
Contains cryptographic primitives, including box, ECDH, EdDSA, and UUID.
|
|
9
|
+
See [`crypto.box`](src/crypto.ts), [`crypto.ECDH`](src/crypto.ts), [`crypto.EdDSA`](src/crypto.ts), [`crypto.UUID`](src/crypto.ts).
|
|
10
|
+
|
|
11
|
+
- **[src/data.ts](src/data.ts)**
|
|
12
|
+
Defines data structures for messages and datagrams, including attachments and serialization.
|
|
13
|
+
See [`Datagram`](src/data.ts), [`Message`](src/data.ts).
|
|
14
|
+
|
|
15
|
+
- **[src/double-ratchet.ts](src/double-ratchet.ts)**
|
|
16
|
+
Implements the Double Ratchet algorithm for forward secrecy in conversations.
|
|
17
|
+
|
|
18
|
+
- **[src/types.ts](src/types.ts)**
|
|
19
|
+
Defines types and interfaces used throughout the project.
|
|
20
|
+
|
|
21
|
+
- **[src/utils.ts](src/utils.ts)**
|
|
22
|
+
Utility functions for manipulating arrays, strings, and binary data.
|
|
23
|
+
|
|
24
|
+
- **[src/x3dh.ts](src/x3dh.ts)**
|
|
25
|
+
Implements the X3DH protocol for secure key exchange between users.
|
|
26
|
+
|
|
27
|
+
## How to Use
|
|
28
|
+
|
|
29
|
+
Import the required modules from [src/index.ts](src/index.ts) to access the main protocol features.
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
Distributed under the GPL v3 license.
|
|
34
|
+
See [LICENSE](LICENSE) for details.
|
package/crypto.d.ts
CHANGED
|
@@ -18,22 +18,31 @@
|
|
|
18
18
|
*/
|
|
19
19
|
export type HashAlgorithms = 'sha224' | 'sha256' | 'sha384' | 'sha512';
|
|
20
20
|
export type HmacAlgorithms = 'kmac128' | 'kmac256';
|
|
21
|
+
interface UUIDv4 {
|
|
22
|
+
toString(): string;
|
|
23
|
+
toJSON(): string;
|
|
24
|
+
toBuffer(): Uint8Array;
|
|
25
|
+
}
|
|
21
26
|
export interface Crypto {
|
|
22
27
|
hash(message: Uint8Array, algorithm?: HashAlgorithms): Uint8Array;
|
|
23
28
|
hmac(key: Uint8Array, message: Uint8Array, length?: number, algorithm?: HmacAlgorithms): Uint8Array;
|
|
24
29
|
hkdf(key: Uint8Array, salt: Uint8Array, info?: Uint8Array | string, length?: number): Uint8Array;
|
|
30
|
+
readonly KeyPair: typeof Crypto.KeyPair;
|
|
25
31
|
readonly box: Crypto.box;
|
|
26
32
|
readonly ECDH: Crypto.ECDH;
|
|
27
33
|
readonly EdDSA: Crypto.EdDSA;
|
|
34
|
+
readonly UUID: Crypto.UUID;
|
|
28
35
|
randomBytes(n: number): Uint8Array;
|
|
29
36
|
scalarMult(n: Uint8Array, p: Uint8Array): Uint8Array;
|
|
30
|
-
generateId(): Crypto.UUID;
|
|
31
37
|
}
|
|
32
38
|
export declare namespace Crypto {
|
|
33
39
|
type KeyPair = {
|
|
34
|
-
publicKey: Uint8Array;
|
|
35
|
-
secretKey: Uint8Array;
|
|
40
|
+
readonly publicKey: Uint8Array;
|
|
41
|
+
readonly secretKey: Uint8Array;
|
|
36
42
|
};
|
|
43
|
+
namespace KeyPair {
|
|
44
|
+
function isKeyPair(obj: any): boolean;
|
|
45
|
+
}
|
|
37
46
|
interface box {
|
|
38
47
|
readonly keyLength: number;
|
|
39
48
|
readonly nonceLength: number;
|
|
@@ -57,9 +66,9 @@ export declare namespace Crypto {
|
|
|
57
66
|
verify(msg: Uint8Array, sig: Uint8Array, publicKey: Uint8Array): boolean;
|
|
58
67
|
}
|
|
59
68
|
interface UUID {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
generate(): UUIDv4;
|
|
70
|
+
stringify(arr: Uint8Array, offset?: number): string;
|
|
71
|
+
parse(uuid: string): Uint8Array;
|
|
63
72
|
}
|
|
64
73
|
}
|
|
65
74
|
declare const crypto: Crypto;
|
package/crypto.js
CHANGED
|
@@ -21,15 +21,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.Crypto = void 0;
|
|
24
25
|
const js_sha3_1 = require("js-sha3");
|
|
25
26
|
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
26
27
|
const uuid_1 = require("uuid");
|
|
27
28
|
const utils_1 = require("./utils");
|
|
29
|
+
var Crypto;
|
|
30
|
+
(function (Crypto) {
|
|
31
|
+
})(Crypto || (exports.Crypto = Crypto = {}));
|
|
28
32
|
class CryptoConstructor {
|
|
29
33
|
constructor() {
|
|
34
|
+
this.KeyPair = {
|
|
35
|
+
isKeyPair(obj) {
|
|
36
|
+
if (typeof obj === 'object' && obj.publicKey && obj.secretKey)
|
|
37
|
+
return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
30
41
|
this.box = new CryptoConstructor.box();
|
|
31
42
|
this.ECDH = new CryptoConstructor.ECDH();
|
|
32
43
|
this.EdDSA = new CryptoConstructor.EdDSA();
|
|
44
|
+
this.UUID = new CryptoConstructor.UUID();
|
|
33
45
|
this.randomBytes = tweetnacl_1.default.randomBytes;
|
|
34
46
|
}
|
|
35
47
|
hash(message, algorithm = 'sha256') {
|
|
@@ -63,9 +75,6 @@ class CryptoConstructor {
|
|
|
63
75
|
scalarMult(n, p) {
|
|
64
76
|
return tweetnacl_1.default.scalarMult(n, p);
|
|
65
77
|
}
|
|
66
|
-
generateId() {
|
|
67
|
-
return new CryptoConstructor.UUID();
|
|
68
|
-
}
|
|
69
78
|
}
|
|
70
79
|
(function (CryptoConstructor) {
|
|
71
80
|
class box {
|
|
@@ -121,6 +130,18 @@ class CryptoConstructor {
|
|
|
121
130
|
}
|
|
122
131
|
CryptoConstructor.EdDSA = EdDSA;
|
|
123
132
|
class UUID {
|
|
133
|
+
generate() {
|
|
134
|
+
return new UUIDv4();
|
|
135
|
+
}
|
|
136
|
+
stringify(arr, offset) {
|
|
137
|
+
return (0, uuid_1.stringify)(arr, offset);
|
|
138
|
+
}
|
|
139
|
+
parse(uuid) {
|
|
140
|
+
return (0, uuid_1.parse)(uuid);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
CryptoConstructor.UUID = UUID;
|
|
144
|
+
class UUIDv4 {
|
|
124
145
|
constructor() {
|
|
125
146
|
this.value = (0, uuid_1.v4)();
|
|
126
147
|
}
|
|
@@ -134,7 +155,6 @@ class CryptoConstructor {
|
|
|
134
155
|
return (0, utils_1.decodeUTF8)(this.value);
|
|
135
156
|
}
|
|
136
157
|
}
|
|
137
|
-
CryptoConstructor.UUID = UUID;
|
|
138
158
|
})(CryptoConstructor || (CryptoConstructor = {}));
|
|
139
159
|
const crypto = new CryptoConstructor();
|
|
140
160
|
exports.default = crypto;
|
package/data.d.ts
CHANGED
|
@@ -16,15 +16,7 @@
|
|
|
16
16
|
* You should have received a copy of the GNU General Public License
|
|
17
17
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
readonly length: number;
|
|
21
|
-
encode(): Uint8Array;
|
|
22
|
-
toString(): string;
|
|
23
|
-
toJSON(): string;
|
|
24
|
-
}
|
|
25
|
-
export declare namespace Encodable {
|
|
26
|
-
function isEncodable(obj: any): boolean;
|
|
27
|
-
}
|
|
19
|
+
import { Encodable } from "./types";
|
|
28
20
|
export declare enum Protocols {
|
|
29
21
|
NULL = "",
|
|
30
22
|
MESSAGE = "/freesignal/message/1.0.0",
|
|
@@ -40,11 +32,13 @@ export declare namespace Protocols {
|
|
|
40
32
|
export interface Datagram {
|
|
41
33
|
readonly id: string;
|
|
42
34
|
readonly version: number;
|
|
43
|
-
readonly
|
|
44
|
-
readonly
|
|
35
|
+
readonly senderKey: string;
|
|
36
|
+
readonly senderRelay?: string;
|
|
37
|
+
readonly receiverKey: string;
|
|
38
|
+
readonly receiverRelay?: string;
|
|
45
39
|
readonly protocol: Protocols;
|
|
46
|
-
payload?: Uint8Array;
|
|
47
40
|
readonly createdAt: number;
|
|
41
|
+
payload?: Uint8Array;
|
|
48
42
|
}
|
|
49
43
|
export declare namespace Datagram {
|
|
50
44
|
const version = 1;
|
|
@@ -53,54 +47,20 @@ export declare namespace Datagram {
|
|
|
53
47
|
function from(data: Uint8Array): DatagramConstructor;
|
|
54
48
|
}
|
|
55
49
|
declare class DatagramConstructor implements Encodable, Datagram {
|
|
56
|
-
readonly createdAt: number;
|
|
57
50
|
readonly id: string;
|
|
58
51
|
readonly version: number;
|
|
59
|
-
readonly
|
|
60
|
-
readonly
|
|
52
|
+
readonly senderKey: string;
|
|
53
|
+
readonly senderRelay?: string;
|
|
54
|
+
readonly receiverKey: string;
|
|
55
|
+
readonly receiverRelay?: string;
|
|
61
56
|
readonly protocol: Protocols;
|
|
57
|
+
readonly createdAt: number;
|
|
62
58
|
payload?: Uint8Array;
|
|
59
|
+
private static headerOffset;
|
|
63
60
|
constructor(sender: Uint8Array | string, receiver: Uint8Array | string, protocol: Protocols, payload?: Uint8Array | Encodable);
|
|
64
61
|
constructor(data: Uint8Array | Datagram);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
toString(): string;
|
|
68
|
-
toJSON(): string;
|
|
69
|
-
}
|
|
70
|
-
type Attachment = any;
|
|
71
|
-
export interface Message {
|
|
72
|
-
readonly version: number;
|
|
73
|
-
text: string;
|
|
74
|
-
group?: string;
|
|
75
|
-
attachments?: Attachment[];
|
|
76
|
-
}
|
|
77
|
-
export declare namespace Message {
|
|
78
|
-
function isMessage(obj: any): boolean;
|
|
79
|
-
function create(opts?: {
|
|
80
|
-
text?: string;
|
|
81
|
-
group?: string;
|
|
82
|
-
attachments?: Attachment[];
|
|
83
|
-
}): MessageConstructor;
|
|
84
|
-
function from(data: Uint8Array | Message): MessageConstructor;
|
|
85
|
-
}
|
|
86
|
-
declare class MessageConstructor implements Encodable, Message {
|
|
87
|
-
static readonly version = 1;
|
|
88
|
-
readonly version: number;
|
|
89
|
-
text: string;
|
|
90
|
-
group?: string;
|
|
91
|
-
attachments?: Attachment[];
|
|
92
|
-
constructor(opts?: {
|
|
93
|
-
text?: string;
|
|
94
|
-
group?: string;
|
|
95
|
-
attachments?: Attachment[];
|
|
96
|
-
});
|
|
97
|
-
constructor(data: Uint8Array | Message);
|
|
98
|
-
get length(): number;
|
|
99
|
-
setText(str: string): this;
|
|
100
|
-
setGroup(str: string): this;
|
|
101
|
-
addAttachment(obj: Attachment): this;
|
|
102
|
-
delAttachment(obj: Attachment): this | undefined;
|
|
103
|
-
encode(): Uint8Array;
|
|
62
|
+
encode(compression?: boolean): Uint8Array;
|
|
63
|
+
encodeSigned(secretKey: Uint8Array, compression?: boolean): Uint8Array;
|
|
104
64
|
toString(): string;
|
|
105
65
|
toJSON(): string;
|
|
106
66
|
}
|
package/data.js
CHANGED
|
@@ -21,17 +21,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
24
|
+
exports.Datagram = exports.Protocols = void 0;
|
|
25
25
|
const utils_1 = require("./utils");
|
|
26
26
|
const crypto_1 = __importDefault(require("./crypto"));
|
|
27
|
-
|
|
28
|
-
(function (Encodable) {
|
|
29
|
-
const properties = ['length', 'encode', 'toString', 'toJSON'];
|
|
30
|
-
function isEncodable(obj) {
|
|
31
|
-
return !properties.some(prop => !obj[prop]);
|
|
32
|
-
}
|
|
33
|
-
Encodable.isEncodable = isEncodable;
|
|
34
|
-
})(Encodable || (exports.Encodable = Encodable = {}));
|
|
27
|
+
const fflate_1 = __importDefault(require("fflate"));
|
|
35
28
|
var Protocols;
|
|
36
29
|
(function (Protocols) {
|
|
37
30
|
Protocols["NULL"] = "";
|
|
@@ -52,9 +45,10 @@ var Protocols;
|
|
|
52
45
|
}
|
|
53
46
|
Protocols.toCode = toCode;
|
|
54
47
|
function encode(protocol, length) {
|
|
55
|
-
const raw =
|
|
48
|
+
/*const raw = numberToUint8Array(Protocols.toCode(protocol), length).reverse();
|
|
56
49
|
raw[0] |= (raw.length - 1) << 6;
|
|
57
|
-
return raw
|
|
50
|
+
return raw;*/
|
|
51
|
+
return (0, utils_1.numberToUint8Array)(Protocols.toCode(protocol), length !== null && length !== void 0 ? length : 4, 'big');
|
|
58
52
|
}
|
|
59
53
|
Protocols.encode = encode;
|
|
60
54
|
function decode(array) {
|
|
@@ -84,149 +78,99 @@ class DatagramConstructor {
|
|
|
84
78
|
constructor(data, receiver, protocol, payload) {
|
|
85
79
|
if (!receiver && !protocol && !payload) {
|
|
86
80
|
if (data instanceof Uint8Array) {
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
90
|
-
this.
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
81
|
+
this.version = data[0] & 63;
|
|
82
|
+
this.protocol = Protocols.decode(data.subarray(1, 4));
|
|
83
|
+
this.id = crypto_1.default.UUID.stringify(data.subarray(4, 20));
|
|
84
|
+
this.createdAt = (0, utils_1.numberFromUint8Array)(data.subarray(20, 28));
|
|
85
|
+
this.senderKey = (0, utils_1.encodeBase64)(data.subarray(28, 28 + crypto_1.default.EdDSA.publicKeyLength));
|
|
86
|
+
this.receiverKey = (0, utils_1.encodeBase64)(data.subarray(28 + crypto_1.default.EdDSA.publicKeyLength, DatagramConstructor.headerOffset));
|
|
87
|
+
const senderRelayOffset = data.indexOf(255, DatagramConstructor.headerOffset);
|
|
88
|
+
const receiverRelayOffset = data.indexOf(255, senderRelayOffset + 1);
|
|
89
|
+
this.senderRelay = (0, utils_1.encodeUTF8)(data.subarray(DatagramConstructor.headerOffset, senderRelayOffset)) ? "" : undefined;
|
|
90
|
+
this.receiverRelay = (0, utils_1.encodeUTF8)(data.subarray(senderRelayOffset + 1, receiverRelayOffset)) ? "" : undefined;
|
|
91
|
+
if (data[0] & 128) {
|
|
92
|
+
const signature = data.subarray(data.length - crypto_1.default.EdDSA.signatureLength);
|
|
93
|
+
if (!crypto_1.default.EdDSA.verify(data.subarray(0, data.length - crypto_1.default.EdDSA.signatureLength), signature, data.subarray(28, 28 + crypto_1.default.EdDSA.publicKeyLength)))
|
|
94
|
+
throw new Error('Invalid signature for Datagram');
|
|
95
|
+
}
|
|
96
|
+
if (data[0] & 64)
|
|
97
|
+
this.payload = fflate_1.default.inflateSync(data.subarray(receiverRelayOffset + 1, data.length));
|
|
98
|
+
else
|
|
99
|
+
this.payload = data.subarray(receiverRelayOffset + 1, data.length);
|
|
95
100
|
}
|
|
96
|
-
else {
|
|
101
|
+
else if (Datagram.isDatagram(data)) {
|
|
97
102
|
const datagram = data;
|
|
98
103
|
this.id = datagram.id;
|
|
99
104
|
this.version = datagram.version;
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
105
|
+
this.senderKey = datagram.senderKey;
|
|
106
|
+
this.receiverKey = datagram.receiverKey;
|
|
102
107
|
this.protocol = datagram.protocol;
|
|
103
|
-
this.payload = datagram.payload;
|
|
104
108
|
this.createdAt = datagram.createdAt;
|
|
109
|
+
this.senderRelay = datagram.senderRelay;
|
|
110
|
+
this.receiverRelay = datagram.receiverRelay;
|
|
111
|
+
this.payload = datagram.payload;
|
|
105
112
|
}
|
|
113
|
+
else
|
|
114
|
+
throw new Error('Invalid constructor arguments for Datagram');
|
|
106
115
|
}
|
|
107
116
|
else if (typeof data === 'string' || data instanceof Uint8Array) {
|
|
108
|
-
this.id = crypto_1.default.
|
|
117
|
+
this.id = crypto_1.default.UUID.generate().toString();
|
|
109
118
|
this.version = Datagram.version;
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
if (typeof data === 'string') {
|
|
120
|
+
const address = data.split('@');
|
|
121
|
+
this.senderKey = address[0];
|
|
122
|
+
this.senderRelay = address[1];
|
|
123
|
+
}
|
|
124
|
+
else
|
|
125
|
+
this.senderKey = (0, utils_1.encodeBase64)(data);
|
|
126
|
+
if (typeof receiver === 'string') {
|
|
127
|
+
const address = receiver.split('@');
|
|
128
|
+
this.receiverKey = address[0];
|
|
129
|
+
this.receiverRelay = address[1];
|
|
130
|
+
}
|
|
131
|
+
else
|
|
132
|
+
this.receiverKey = (0, utils_1.encodeBase64)(receiver);
|
|
112
133
|
this.protocol = protocol;
|
|
113
|
-
this.payload = payload instanceof Uint8Array ? payload : payload === null || payload === void 0 ? void 0 : payload.encode();
|
|
114
134
|
this.createdAt = Date.now();
|
|
135
|
+
this.payload = payload instanceof Uint8Array ? payload : payload === null || payload === void 0 ? void 0 : payload.encode();
|
|
115
136
|
}
|
|
116
137
|
else
|
|
117
138
|
throw new Error('Invalid constructor arguments for Datagram');
|
|
118
139
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
].
|
|
140
|
+
encode(compression = true) {
|
|
141
|
+
var _a;
|
|
142
|
+
compression = compression && this.payload != undefined && this.payload.length > 1024;
|
|
143
|
+
return (0, utils_1.concatUint8Array)(new Uint8Array(1).fill(this.version | (compression ? 64 : 0)), //1
|
|
144
|
+
Protocols.encode(this.protocol, 3), //3
|
|
145
|
+
(_a = crypto_1.default.UUID.parse(this.id)) !== null && _a !== void 0 ? _a : [], //16
|
|
146
|
+
(0, utils_1.numberToUint8Array)(this.createdAt, 8), //8
|
|
147
|
+
(0, utils_1.decodeBase64)(this.senderKey), //32
|
|
148
|
+
(0, utils_1.decodeBase64)(this.receiverKey), //32
|
|
149
|
+
...(this.senderRelay ? [(0, utils_1.decodeUTF8)(this.senderRelay)] : []), new Uint8Array(1).fill(255), ...(this.receiverRelay ? [(0, utils_1.decodeUTF8)(this.receiverRelay)] : []), new Uint8Array(1).fill(255), ...(this.payload ? [compression ? fflate_1.default.deflateSync(this.payload) : this.payload] : []));
|
|
150
|
+
}
|
|
151
|
+
encodeSigned(secretKey, compression) {
|
|
152
|
+
//if (!this.payload) throw new Error('Cannot sign a datagram without payload');
|
|
153
|
+
const header = this.encode(compression);
|
|
154
|
+
header[0] |= 128; // Set the sign bit
|
|
155
|
+
const signature = crypto_1.default.EdDSA.sign(header, secretKey);
|
|
156
|
+
return (0, utils_1.concatUint8Array)(header, signature);
|
|
129
157
|
}
|
|
130
158
|
toString() {
|
|
131
|
-
return this.
|
|
159
|
+
return (0, utils_1.encodeBase64)(this.encode());
|
|
132
160
|
}
|
|
133
161
|
toJSON() {
|
|
134
|
-
return JSON.stringify({
|
|
162
|
+
/*return JSON.stringify({
|
|
135
163
|
id: this.id,
|
|
136
164
|
version: this.version,
|
|
137
|
-
|
|
138
|
-
|
|
165
|
+
senderKey: this.senderKey,
|
|
166
|
+
senderRelay: this.senderRelay,
|
|
167
|
+
receiverKey: this.receiverKey,
|
|
168
|
+
receiverRelay: this.receiverRelay,
|
|
139
169
|
protocol: this.protocol,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
var Message;
|
|
146
|
-
(function (Message) {
|
|
147
|
-
function isMessage(obj) {
|
|
148
|
-
return obj instanceof MessageConstructor || (obj && typeof obj === 'object' && 'version' in obj && 'text' in obj && 'group' in obj && 'attachments' in obj);
|
|
149
|
-
}
|
|
150
|
-
Message.isMessage = isMessage;
|
|
151
|
-
function create(opts) {
|
|
152
|
-
return new MessageConstructor(opts);
|
|
153
|
-
}
|
|
154
|
-
Message.create = create;
|
|
155
|
-
;
|
|
156
|
-
function from(data) {
|
|
157
|
-
return new MessageConstructor(data);
|
|
158
|
-
}
|
|
159
|
-
Message.from = from;
|
|
160
|
-
})(Message || (exports.Message = Message = {}));
|
|
161
|
-
class MessageConstructor {
|
|
162
|
-
constructor(opts) {
|
|
163
|
-
var _a;
|
|
164
|
-
this.version = MessageConstructor.version;
|
|
165
|
-
this.text = "";
|
|
166
|
-
if (Message.isMessage(opts)) {
|
|
167
|
-
const json = opts;
|
|
168
|
-
this.version = json.version;
|
|
169
|
-
this.text = json.text;
|
|
170
|
-
this.group = json.group;
|
|
171
|
-
this.attachments = json.attachments;
|
|
172
|
-
}
|
|
173
|
-
else if (!opts) {
|
|
174
|
-
this.text = "";
|
|
175
|
-
}
|
|
176
|
-
else if (opts instanceof Uint8Array) {
|
|
177
|
-
const arr = (0, utils_1.encodeUTF8)(opts).split(',');
|
|
178
|
-
this.version = arr[0];
|
|
179
|
-
this.text = (_a = arr[1]) !== null && _a !== void 0 ? _a : "";
|
|
180
|
-
this.group = arr[2];
|
|
181
|
-
this.attachments = arr[3] ? JSON.parse(arr[3]) : undefined;
|
|
182
|
-
}
|
|
183
|
-
else if (typeof opts === 'object') {
|
|
184
|
-
const { text, group, attachments } = opts;
|
|
185
|
-
this.text = text || "";
|
|
186
|
-
this.group = group;
|
|
187
|
-
this.attachments = attachments || [];
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
throw new Error('Invalid constructor arguments for Message');
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
get length() { return this.encode().length; }
|
|
194
|
-
setText(str) {
|
|
195
|
-
this.text = str;
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
setGroup(str) {
|
|
199
|
-
this.group = str;
|
|
200
|
-
return this;
|
|
201
|
-
}
|
|
202
|
-
addAttachment(obj) {
|
|
203
|
-
if (this.attachments)
|
|
204
|
-
this.attachments.push(obj);
|
|
205
|
-
else
|
|
206
|
-
this.attachments = [obj];
|
|
207
|
-
return this;
|
|
208
|
-
}
|
|
209
|
-
delAttachment(obj) {
|
|
210
|
-
var _a;
|
|
211
|
-
const index = (_a = this.attachments) === null || _a === void 0 ? void 0 : _a.indexOf(obj);
|
|
212
|
-
if (!index || !this.attachments)
|
|
213
|
-
return undefined;
|
|
214
|
-
this.attachments = this.attachments.filter((v, i) => index !== i);
|
|
215
|
-
return this;
|
|
216
|
-
}
|
|
217
|
-
encode() {
|
|
218
|
-
return (0, utils_1.decodeUTF8)([this.version, this.text, this.group, JSON.stringify(this.attachments || [])].join(','));
|
|
219
|
-
}
|
|
220
|
-
toString() {
|
|
221
|
-
return this.toJSON();
|
|
222
|
-
}
|
|
223
|
-
toJSON() {
|
|
224
|
-
return JSON.stringify({
|
|
225
|
-
version: MessageConstructor.version,
|
|
226
|
-
text: this.text,
|
|
227
|
-
group: this.group,
|
|
228
|
-
attachments: JSON.stringify(this.attachments)
|
|
229
|
-
});
|
|
170
|
+
createdAt: this.createdAt,
|
|
171
|
+
payload: this.payload ? encodeBase64(this.payload) : undefined
|
|
172
|
+
});*/
|
|
173
|
+
return this.toString();
|
|
230
174
|
}
|
|
231
175
|
}
|
|
232
|
-
|
|
176
|
+
DatagramConstructor.headerOffset = 28 + crypto_1.default.EdDSA.publicKeyLength * 2;
|
package/double-ratchet.d.ts
CHANGED
|
@@ -16,24 +16,23 @@
|
|
|
16
16
|
* You should have received a copy of the GNU General Public License
|
|
17
17
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
18
18
|
*/
|
|
19
|
-
import { Encodable } from "./
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}): Session;
|
|
19
|
+
import { Encodable } from "./types";
|
|
20
|
+
type ExportedKeySession = {
|
|
21
|
+
secretKey: string;
|
|
22
|
+
remoteKey: string;
|
|
23
|
+
rootKey: string;
|
|
24
|
+
sendingChain: string;
|
|
25
|
+
receivingChain: string;
|
|
26
|
+
sendingCount: number;
|
|
27
|
+
receivingCount: number;
|
|
28
|
+
previousCount: number;
|
|
29
|
+
previousKeys: [number, Uint8Array][];
|
|
30
|
+
};
|
|
32
31
|
/**
|
|
33
32
|
* Represents a secure Double Ratchet session.
|
|
34
33
|
* Used for forward-secure encryption and decryption of messages.
|
|
35
34
|
*/
|
|
36
|
-
export declare class
|
|
35
|
+
export declare class KeySession {
|
|
37
36
|
private static readonly skipLimit;
|
|
38
37
|
static readonly version = 1;
|
|
39
38
|
static readonly rootKeyLength: number;
|
|
@@ -47,8 +46,9 @@ export declare class Session {
|
|
|
47
46
|
private receivingCount;
|
|
48
47
|
private previousKeys;
|
|
49
48
|
constructor(opts?: {
|
|
49
|
+
secretKey?: Uint8Array;
|
|
50
50
|
remoteKey?: Uint8Array;
|
|
51
|
-
|
|
51
|
+
rootKey?: Uint8Array;
|
|
52
52
|
});
|
|
53
53
|
/**
|
|
54
54
|
* Whether both the sending and receiving chains are initialized.
|
|
@@ -62,11 +62,8 @@ export declare class Session {
|
|
|
62
62
|
* The last known remote public key.
|
|
63
63
|
*/
|
|
64
64
|
get remoteKey(): Uint8Array | undefined;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
*/
|
|
68
|
-
setRemoteKey(key: Uint8Array): this;
|
|
69
|
-
private dhRatchet;
|
|
65
|
+
private setRemoteKey;
|
|
66
|
+
private ratchetKeys;
|
|
70
67
|
private getSendingKey;
|
|
71
68
|
private getReceivingKey;
|
|
72
69
|
/**
|
|
@@ -75,25 +72,25 @@ export declare class Session {
|
|
|
75
72
|
* @param message - The message as a Uint8Array.
|
|
76
73
|
* @returns An EncryptedPayload or undefined if encryption fails.
|
|
77
74
|
*/
|
|
78
|
-
encrypt(message: Uint8Array):
|
|
75
|
+
encrypt(message: Uint8Array): EncryptedData;
|
|
79
76
|
/**
|
|
80
77
|
* Decrypts an encrypted message.
|
|
81
78
|
*
|
|
82
79
|
* @param payload - The received encrypted message.
|
|
83
80
|
* @returns The decrypted message as a Uint8Array, or undefined if decryption fails.
|
|
84
81
|
*/
|
|
85
|
-
decrypt(payload: Uint8Array |
|
|
82
|
+
decrypt(payload: Uint8Array | EncryptedData): Uint8Array | undefined;
|
|
86
83
|
/**
|
|
87
84
|
* Export the state of the session;
|
|
88
85
|
*/
|
|
89
|
-
export():
|
|
86
|
+
export(): ExportedKeySession;
|
|
90
87
|
/**
|
|
91
88
|
* Import a state.
|
|
92
89
|
*
|
|
93
90
|
* @param json string returned by `export()` method.
|
|
94
91
|
* @returns session with the state parsed.
|
|
95
92
|
*/
|
|
96
|
-
static import(json: string):
|
|
93
|
+
static import(json: string): KeySession;
|
|
97
94
|
/**
|
|
98
95
|
* The fixed key length (in bytes) used throughout the Double Ratchet session.
|
|
99
96
|
* Typically 32 bytes (256 bits) for symmetric keys.
|
|
@@ -105,7 +102,7 @@ export declare class Session {
|
|
|
105
102
|
* Interface representing an encrypted payload.
|
|
106
103
|
* Provides metadata and de/serialization methods.
|
|
107
104
|
*/
|
|
108
|
-
export interface
|
|
105
|
+
export interface EncryptedData extends Encodable {
|
|
109
106
|
/**
|
|
110
107
|
* The length of the payload.
|
|
111
108
|
*/
|
|
@@ -134,26 +131,12 @@ export interface EncryptedPayload extends Encodable {
|
|
|
134
131
|
* The encrypted message content.
|
|
135
132
|
*/
|
|
136
133
|
readonly ciphertext: Uint8Array;
|
|
137
|
-
/**
|
|
138
|
-
* The payload signature.
|
|
139
|
-
*/
|
|
140
|
-
/**
|
|
141
|
-
* Set the signature of the payload.
|
|
142
|
-
*
|
|
143
|
-
* @param signature signature
|
|
144
|
-
*/
|
|
145
|
-
/**
|
|
146
|
-
* Return the payload without the signature.
|
|
147
|
-
*/
|
|
148
134
|
/**
|
|
149
135
|
* Serializes the payload into a Uint8Array for transport.
|
|
150
136
|
*/
|
|
151
137
|
encode(): Uint8Array;
|
|
152
138
|
/**
|
|
153
|
-
*
|
|
154
|
-
*/
|
|
155
|
-
/**
|
|
156
|
-
* Returns the payload as a UTF-8 string.
|
|
139
|
+
* Returns the payload as a Base64 string.
|
|
157
140
|
*/
|
|
158
141
|
toString(): string;
|
|
159
142
|
/**
|
|
@@ -161,12 +144,13 @@ export interface EncryptedPayload extends Encodable {
|
|
|
161
144
|
*/
|
|
162
145
|
toJSON(): string;
|
|
163
146
|
}
|
|
164
|
-
export declare class
|
|
147
|
+
export declare class EncryptedData {
|
|
165
148
|
/**
|
|
166
149
|
* Static factory method that constructs an `EncryptedPayload` from a raw Uint8Array.
|
|
167
150
|
*
|
|
168
151
|
* @param array - A previously serialized encrypted payload.
|
|
169
152
|
* @returns An instance of `EncryptedPayload`.
|
|
170
153
|
*/
|
|
171
|
-
static from(array: Uint8Array |
|
|
154
|
+
static from(array: Uint8Array | EncryptedData): EncryptedData;
|
|
172
155
|
}
|
|
156
|
+
export {};
|