@freesignal/protocol 0.2.0 → 0.2.2
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/api.d.ts +12 -12
- package/api.js +67 -18
- package/index.d.ts +4 -9
- package/index.js +19 -4
- package/package.json +1 -1
package/api.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Crypto, LocalStorage } from "@freesignal/interfaces";
|
|
|
2
2
|
import { KeySession } from "./double-ratchet";
|
|
3
3
|
import { KeyExchange } from "./x3dh";
|
|
4
4
|
import { Datagram, IdentityKeys, EncryptedData, UserId } from "./types";
|
|
5
|
+
export declare const FREESIGNAL_MIME = "application/x-freesignal";
|
|
6
|
+
type DatagramId = string;
|
|
5
7
|
export declare class FreeSignalAPI {
|
|
6
8
|
protected readonly signKey: Crypto.KeyPair;
|
|
7
9
|
protected readonly boxKey: Crypto.KeyPair;
|
|
@@ -15,24 +17,22 @@ export declare class FreeSignalAPI {
|
|
|
15
17
|
keyExchange: LocalStorage<string, Crypto.KeyPair>;
|
|
16
18
|
users: LocalStorage<UserId, IdentityKeys>;
|
|
17
19
|
});
|
|
20
|
+
get userId(): Uint8Array;
|
|
21
|
+
get identityKeys(): IdentityKeys;
|
|
18
22
|
encryptData(data: Uint8Array, userId: string): Promise<EncryptedData>;
|
|
19
23
|
decryptData(data: Uint8Array, userId: string): Promise<Uint8Array>;
|
|
24
|
+
getDatagrams(publicKey: string | Uint8Array, url: string): Promise<Datagram[]>;
|
|
25
|
+
postDatagrams(datagrams: Datagram[], publicKey: string | Uint8Array, url: string): Promise<number>;
|
|
26
|
+
deleteDatagrams(datagramIds: DatagramId[], publicKey: string | Uint8Array, url: string): Promise<number>;
|
|
27
|
+
createToken(publicKey: Uint8Array): string;
|
|
20
28
|
protected digestToken(auth?: string): Promise<{
|
|
21
29
|
identityKeys: IdentityKeys;
|
|
22
30
|
userId: UserId;
|
|
23
31
|
}>;
|
|
24
|
-
|
|
32
|
+
protected packIdList(datagramIds: DatagramId[]): Uint8Array;
|
|
33
|
+
protected unpackIdList(data: Uint8Array): DatagramId[];
|
|
25
34
|
protected packDatagrams(messages: Datagram[]): Uint8Array;
|
|
26
35
|
protected unpackDatagrams(data: Uint8Array): Datagram[];
|
|
27
|
-
|
|
28
|
-
readonly publicKey: string;
|
|
29
|
-
readonly identityKey: string;
|
|
30
|
-
encode(): Uint8Array;
|
|
31
|
-
toString(): string;
|
|
32
|
-
toJSON(): string;
|
|
33
|
-
};
|
|
34
|
-
static createSecretIdentityKeys(): {
|
|
35
|
-
secretSignKey: Uint8Array;
|
|
36
|
-
secretBoxKey: Uint8Array;
|
|
37
|
-
};
|
|
36
|
+
static getUserId(publicKey: string | Uint8Array): string;
|
|
38
37
|
}
|
|
38
|
+
export {};
|
package/api.js
CHANGED
|
@@ -12,12 +12,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.FreeSignalAPI = void 0;
|
|
15
|
+
exports.FreeSignalAPI = exports.FREESIGNAL_MIME = void 0;
|
|
16
16
|
const crypto_1 = __importDefault(require("@freesignal/crypto"));
|
|
17
17
|
const x3dh_1 = require("./x3dh");
|
|
18
18
|
const utils_1 = require("@freesignal/utils");
|
|
19
19
|
const types_1 = require("./types");
|
|
20
20
|
const fflate_1 = __importDefault(require("fflate"));
|
|
21
|
+
exports.FREESIGNAL_MIME = "application/x-freesignal";
|
|
21
22
|
class FreeSignalAPI {
|
|
22
23
|
constructor(opts) {
|
|
23
24
|
const { secretSignKey, secretBoxKey, sessions, keyExchange, users } = opts;
|
|
@@ -27,6 +28,15 @@ class FreeSignalAPI {
|
|
|
27
28
|
this.keyExchange = new x3dh_1.KeyExchange(secretSignKey, secretBoxKey, keyExchange);
|
|
28
29
|
this.users = users;
|
|
29
30
|
}
|
|
31
|
+
get userId() {
|
|
32
|
+
return crypto_1.default.hash(this.signKey.publicKey);
|
|
33
|
+
}
|
|
34
|
+
get identityKeys() {
|
|
35
|
+
return {
|
|
36
|
+
publicKey: (0, utils_1.encodeBase64)(this.signKey.publicKey),
|
|
37
|
+
identityKey: (0, utils_1.encodeBase64)(this.boxKey.publicKey)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
30
40
|
encryptData(data, userId) {
|
|
31
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
42
|
const session = yield this.sessions.get(userId);
|
|
@@ -49,6 +59,50 @@ class FreeSignalAPI {
|
|
|
49
59
|
return decrypted;
|
|
50
60
|
});
|
|
51
61
|
}
|
|
62
|
+
getDatagrams(publicKey, url) {
|
|
63
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
const res = yield fetch(url, {
|
|
65
|
+
method: 'GET',
|
|
66
|
+
headers: {
|
|
67
|
+
authorization: this.createToken(publicKey instanceof Uint8Array ? publicKey : (0, utils_1.decodeBase64)(publicKey))
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return this.unpackDatagrams(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), FreeSignalAPI.getUserId(publicKey)));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
postDatagrams(datagrams, publicKey, url) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
const data = yield this.encryptData(this.packDatagrams(datagrams), FreeSignalAPI.getUserId(publicKey));
|
|
76
|
+
const res = yield fetch(url, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'Content-Type': exports.FREESIGNAL_MIME,
|
|
80
|
+
authorization: this.createToken(publicKey instanceof Uint8Array ? publicKey : (0, utils_1.decodeBase64)(publicKey))
|
|
81
|
+
},
|
|
82
|
+
body: data.encode()
|
|
83
|
+
});
|
|
84
|
+
return (0, utils_1.numberFromUint8Array)(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), FreeSignalAPI.getUserId(publicKey)));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
deleteDatagrams(datagramIds, publicKey, url) {
|
|
88
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
const data = yield this.encryptData(this.packIdList(datagramIds), FreeSignalAPI.getUserId(publicKey));
|
|
90
|
+
const res = yield fetch(url, {
|
|
91
|
+
method: 'DELETE',
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': exports.FREESIGNAL_MIME,
|
|
94
|
+
authorization: this.createToken(publicKey instanceof Uint8Array ? publicKey : (0, utils_1.decodeBase64)(publicKey))
|
|
95
|
+
},
|
|
96
|
+
body: data.encode()
|
|
97
|
+
});
|
|
98
|
+
return (0, utils_1.numberFromUint8Array)(yield this.decryptData(new Uint8Array(yield res.arrayBuffer()), FreeSignalAPI.getUserId(publicKey)));
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
createToken(publicKey) {
|
|
102
|
+
const sharedId = crypto_1.default.hash(crypto_1.default.ECDH.scalarMult(publicKey, this.boxKey.secretKey));
|
|
103
|
+
return `Bearer ${(0, utils_1.encodeBase64)(this.userId)}:${(0, utils_1.encodeBase64)(sharedId)}`;
|
|
104
|
+
}
|
|
105
|
+
;
|
|
52
106
|
digestToken(auth) {
|
|
53
107
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
108
|
if (auth && auth.startsWith("Bearer ")) {
|
|
@@ -56,7 +110,7 @@ class FreeSignalAPI {
|
|
|
56
110
|
const identityKeys = yield this.users.get(userId);
|
|
57
111
|
if (!identityKeys)
|
|
58
112
|
throw new Error('User not found or invalid auth token');
|
|
59
|
-
if ((0, utils_1.verifyUint8Array)(crypto_1.default.hash(crypto_1.default.ECDH.
|
|
113
|
+
if ((0, utils_1.verifyUint8Array)(crypto_1.default.hash(crypto_1.default.ECDH.scalarMult((0, utils_1.decodeBase64)(identityKeys.publicKey), this.boxKey.secretKey)), (0, utils_1.decodeBase64)(sharedId)))
|
|
60
114
|
return { identityKeys, userId: auth };
|
|
61
115
|
else
|
|
62
116
|
throw new Error('Authorization token not valid');
|
|
@@ -64,12 +118,16 @@ class FreeSignalAPI {
|
|
|
64
118
|
throw new Error('Authorization header is required');
|
|
65
119
|
});
|
|
66
120
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
121
|
+
packIdList(datagramIds) {
|
|
122
|
+
return datagramIds.map(datagramId => crypto_1.default.UUID.parse(datagramId)).reduce((prev, curr) => new Uint8Array([...prev, ...curr]), new Uint8Array());
|
|
123
|
+
}
|
|
124
|
+
unpackIdList(data) {
|
|
125
|
+
const ids = [];
|
|
126
|
+
for (let i = 0; i < data.length; i += 16) {
|
|
127
|
+
ids.push(crypto_1.default.UUID.stringify(data.subarray(i, i + 16)));
|
|
128
|
+
}
|
|
129
|
+
return ids;
|
|
71
130
|
}
|
|
72
|
-
;
|
|
73
131
|
packDatagrams(messages) {
|
|
74
132
|
return fflate_1.default.deflateSync((0, utils_1.concatUint8Array)(...messages.flatMap(datagram => {
|
|
75
133
|
const encoded = types_1.Datagram.from(datagram).encode();
|
|
@@ -102,17 +160,8 @@ class FreeSignalAPI {
|
|
|
102
160
|
}
|
|
103
161
|
return messages;
|
|
104
162
|
}
|
|
105
|
-
|
|
106
|
-
return
|
|
107
|
-
publicKey: (0, utils_1.encodeBase64)(this.signKey.publicKey),
|
|
108
|
-
identityKey: (0, utils_1.encodeBase64)(this.boxKey.publicKey)
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
static createSecretIdentityKeys() {
|
|
112
|
-
return {
|
|
113
|
-
secretSignKey: crypto_1.default.EdDSA.keyPair().secretKey,
|
|
114
|
-
secretBoxKey: crypto_1.default.ECDH.keyPair().secretKey
|
|
115
|
-
};
|
|
163
|
+
static getUserId(publicKey) {
|
|
164
|
+
return (0, utils_1.encodeBase64)(crypto_1.default.hash(publicKey instanceof Uint8Array ? publicKey : (0, utils_1.decodeBase64)(publicKey)));
|
|
116
165
|
}
|
|
117
166
|
}
|
|
118
167
|
exports.FreeSignalAPI = FreeSignalAPI;
|
package/index.d.ts
CHANGED
|
@@ -20,8 +20,6 @@ import crypto from "@freesignal/crypto";
|
|
|
20
20
|
import { LocalStorage, Crypto } from "@freesignal/interfaces";
|
|
21
21
|
import { KeySession } from "./double-ratchet";
|
|
22
22
|
import { KeyExchange } from "./x3dh";
|
|
23
|
-
import { IdentityKeys, UserId } from "./types";
|
|
24
|
-
import { FreeSignalAPI } from "./api";
|
|
25
23
|
/**
|
|
26
24
|
* Creates a new Double Ratchet session.
|
|
27
25
|
*
|
|
@@ -43,11 +41,8 @@ export declare function createKeySession(opts?: {
|
|
|
43
41
|
* @returns A new X3DH session.
|
|
44
42
|
*/
|
|
45
43
|
export declare function createKeyExchange(signSecretKey: Uint8Array, boxSecretKey: Uint8Array, bundleStore?: LocalStorage<string, crypto.KeyPair>): KeyExchange;
|
|
46
|
-
export declare function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
keyExchange: LocalStorage<string, Crypto.KeyPair>;
|
|
51
|
-
users: LocalStorage<UserId, IdentityKeys>;
|
|
52
|
-
}): FreeSignalAPI;
|
|
44
|
+
export declare function createIdentityKeys(signSecretKey?: Uint8Array, boxSecretKey?: Uint8Array): {
|
|
45
|
+
sign: Crypto.KeyPair;
|
|
46
|
+
box: Crypto.KeyPair;
|
|
47
|
+
};
|
|
53
48
|
export { IdentityKeys, Protocols, EncryptedData, Datagram } from "./types";
|
package/index.js
CHANGED
|
@@ -17,14 +17,17 @@
|
|
|
17
17
|
* You should have received a copy of the GNU General Public License
|
|
18
18
|
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
19
19
|
*/
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
exports.Datagram = exports.EncryptedData = exports.Protocols = exports.IdentityKeys = void 0;
|
|
22
25
|
exports.createKeySession = createKeySession;
|
|
23
26
|
exports.createKeyExchange = createKeyExchange;
|
|
24
|
-
exports.
|
|
27
|
+
exports.createIdentityKeys = createIdentityKeys;
|
|
28
|
+
const crypto_1 = __importDefault(require("@freesignal/crypto"));
|
|
25
29
|
const double_ratchet_1 = require("./double-ratchet");
|
|
26
30
|
const x3dh_1 = require("./x3dh");
|
|
27
|
-
const api_1 = require("./api");
|
|
28
31
|
/**
|
|
29
32
|
* Creates a new Double Ratchet session.
|
|
30
33
|
*
|
|
@@ -46,9 +49,21 @@ function createKeySession(opts) {
|
|
|
46
49
|
function createKeyExchange(signSecretKey, boxSecretKey, bundleStore) {
|
|
47
50
|
return new x3dh_1.KeyExchange(signSecretKey, boxSecretKey, bundleStore);
|
|
48
51
|
}
|
|
49
|
-
function
|
|
50
|
-
return
|
|
52
|
+
function createIdentityKeys(signSecretKey, boxSecretKey) {
|
|
53
|
+
return {
|
|
54
|
+
sign: crypto_1.default.EdDSA.keyPair(signSecretKey),
|
|
55
|
+
box: crypto_1.default.ECDH.keyPair(boxSecretKey)
|
|
56
|
+
};
|
|
51
57
|
}
|
|
58
|
+
/*export function createAPI(opts: {
|
|
59
|
+
secretSignKey: Uint8Array;
|
|
60
|
+
secretBoxKey: Uint8Array;
|
|
61
|
+
sessions: LocalStorage<UserId, KeySession>;
|
|
62
|
+
keyExchange: LocalStorage<string, Crypto.KeyPair>;
|
|
63
|
+
users: LocalStorage<UserId, IdentityKeys>;
|
|
64
|
+
}): FreeSignalAPI {
|
|
65
|
+
return new FreeSignalAPI(opts);
|
|
66
|
+
}*/
|
|
52
67
|
var types_1 = require("./types");
|
|
53
68
|
Object.defineProperty(exports, "IdentityKeys", { enumerable: true, get: function () { return types_1.IdentityKeys; } });
|
|
54
69
|
Object.defineProperty(exports, "Protocols", { enumerable: true, get: function () { return types_1.Protocols; } });
|