@vex-chat/crypto 1.1.0-rc.1 → 2.0.0
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 +75 -12
- package/dist/index.d.ts +112 -79
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +214 -165
- package/dist/index.js.map +1 -0
- package/package.json +108 -77
- package/src/__tests__/XKeyConvert.ts +68 -0
- package/src/__tests__/XUtils/bytesEqual.ts +16 -0
- package/src/__tests__/XUtils/emptyHeader.ts +12 -0
- package/src/__tests__/XUtils/numberToUint8Arr.ts +22 -0
- package/src/__tests__/XUtils/packMessage.ts +23 -0
- package/src/__tests__/XUtils/stringEncoding.ts +68 -0
- package/src/__tests__/XUtils/uint8ArrToNumber.ts +19 -0
- package/src/__tests__/XUtils/unpackMessage.ts +25 -0
- package/src/__tests__/xConcat.ts +18 -0
- package/src/__tests__/xDH.ts +16 -0
- package/src/__tests__/xEncode.ts +11 -0
- package/src/__tests__/xHMAC.ts +26 -0
- package/src/__tests__/xMnemonic.ts +12 -0
- package/src/index.ts +540 -0
package/package.json
CHANGED
|
@@ -1,80 +1,111 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
"name": "@vex-chat/crypto",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Crypto primitives for the Vex encrypted chat platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"author": "Extra <extrahash@protonmail.com>",
|
|
21
|
+
"license": "AGPL-3.0-or-later",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=24.0.0",
|
|
24
|
+
"npm": ">=10.0.0"
|
|
25
|
+
},
|
|
26
|
+
"packageManager": "npm@10.9.2",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prepare": "husky",
|
|
29
|
+
"preinstall": "npx only-allow npm",
|
|
30
|
+
"build": "tsc -p tsconfig.build.json",
|
|
31
|
+
"build:clean": "rimraf dist && tsc -p tsconfig.build.json",
|
|
32
|
+
"prepack": "npm run build",
|
|
33
|
+
"format": "prettier --write .",
|
|
34
|
+
"format:check": "prettier --check .",
|
|
35
|
+
"lint": "eslint src/",
|
|
36
|
+
"lint:fix": "eslint src/ --fix",
|
|
37
|
+
"license:check": "npx @onebeyond/license-checker scan --allowOnly MIT ISC BSD-2-Clause BSD-3-Clause Apache-2.0 0BSD MPL-2.0 CC0-1.0 CC-BY-4.0 Unlicense BlueOak-1.0.0 Python-2.0 Zlib PSF-2.0 Artistic-2.0 AGPL-3.0-or-later --ignoreRootPackageLicense --disableReport",
|
|
38
|
+
"lint:pkg": "publint --strict",
|
|
39
|
+
"lint:types": "attw --pack . --ignore-rules cjs-resolves-to-esm",
|
|
40
|
+
"lint:api": "api-extractor run --local --verbose",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:types": "tsc --noEmit",
|
|
43
|
+
"prepublish": "npm run build"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@vex-chat/types": "^2.0.0",
|
|
47
|
+
"typescript": ">=5.9.0 || >=6.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"typescript": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@noble/hashes": "2.0.1",
|
|
56
|
+
"@stablelib/base64": "2.0.1",
|
|
57
|
+
"@stablelib/utf8": "2.1.0",
|
|
58
|
+
"bip39": "3.1.0",
|
|
59
|
+
"ed2curve": "0.3.0",
|
|
60
|
+
"msgpackr": "1.11.9",
|
|
61
|
+
"tweetnacl": "1.0.3"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@arethetypeswrong/cli": "0.18.2",
|
|
65
|
+
"@changesets/cli": "2.30.0",
|
|
66
|
+
"@microsoft/api-extractor": "7.58.2",
|
|
67
|
+
"@types/create-hmac": "1.1.3",
|
|
68
|
+
"@types/ed2curve": "0.2.4",
|
|
69
|
+
"@types/node": "25.6.0",
|
|
70
|
+
"@vex-chat/types": "2.0.0",
|
|
71
|
+
"@vitest/eslint-plugin": "1.6.15",
|
|
72
|
+
"eslint": "10.2.0",
|
|
73
|
+
"eslint-config-prettier": "10.1.8",
|
|
74
|
+
"eslint-plugin-perfectionist": "5.8.0",
|
|
75
|
+
"husky": "9.1.7",
|
|
76
|
+
"lint-staged": "16.4.0",
|
|
77
|
+
"prettier": "3.8.2",
|
|
78
|
+
"publint": "0.3.18",
|
|
79
|
+
"rimraf": "6.1.3",
|
|
80
|
+
"type-coverage": "2.29.7",
|
|
81
|
+
"typescript": "6.0.2",
|
|
82
|
+
"typescript-eslint": "8.58.1",
|
|
83
|
+
"vitest": "4.1.4"
|
|
84
|
+
},
|
|
85
|
+
"typeCoverage": {
|
|
86
|
+
"atLeast": 100,
|
|
87
|
+
"strict": true,
|
|
88
|
+
"ignoreCatch": true
|
|
89
|
+
},
|
|
90
|
+
"lint-staged": {
|
|
91
|
+
"src/**/*.ts": [
|
|
92
|
+
"eslint --fix",
|
|
93
|
+
"prettier --write"
|
|
94
|
+
],
|
|
95
|
+
"*.{json,md,yaml,yml}": [
|
|
96
|
+
"prettier --write"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"repository": {
|
|
100
|
+
"type": "git",
|
|
101
|
+
"url": "git+https://github.com/vex-protocol/crypto-js.git"
|
|
102
|
+
},
|
|
103
|
+
"bugs": {
|
|
104
|
+
"url": "https://github.com/vex-protocol/crypto-js/issues"
|
|
105
|
+
},
|
|
106
|
+
"homepage": "https://github.com/vex-protocol/crypto-js#readme",
|
|
107
|
+
"publishConfig": {
|
|
108
|
+
"access": "public",
|
|
109
|
+
"registry": "https://registry.npmjs.org/"
|
|
13
110
|
}
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist"
|
|
17
|
-
],
|
|
18
|
-
"author": "Extra <extrahash@protonmail.com>",
|
|
19
|
-
"license": "AGPL-3.0-or-later",
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "rimraf dist && tsc",
|
|
22
|
-
"prepack": "npm run build",
|
|
23
|
-
"prettier": "prettier '**/*.{ts,tsx,json,md}' --ignore-path .gitignore --write",
|
|
24
|
-
"lint": "eslint src/**/*.ts",
|
|
25
|
-
"lint-fix": "eslint src/**/*.ts --fix",
|
|
26
|
-
"prepublish": "npm run build",
|
|
27
|
-
"test": "vitest run"
|
|
28
|
-
},
|
|
29
|
-
"peerDependencies": {
|
|
30
|
-
"@vex-chat/types": "^1.0.0-rc.1",
|
|
31
|
-
"typescript": ">=5.9.0 || >=6.0.0"
|
|
32
|
-
},
|
|
33
|
-
"peerDependenciesMeta": {
|
|
34
|
-
"typescript": {
|
|
35
|
-
"optional": true
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"msgpackr": "1.11.8",
|
|
40
|
-
"@stablelib/base64": "^2.0.1",
|
|
41
|
-
"@stablelib/utf8": "^2.1.0",
|
|
42
|
-
"bip39": "^3.1.0",
|
|
43
|
-
"ed2curve": "^0.3.0",
|
|
44
|
-
"tweetnacl": "^1.0.3"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@changesets/cli": "^2.29.8",
|
|
48
|
-
"@types/create-hmac": "^1.1.3",
|
|
49
|
-
"@types/ed2curve": "^0.2.4",
|
|
50
|
-
"@types/node": "^24.12.2",
|
|
51
|
-
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
52
|
-
"@typescript-eslint/parser": "^8.57.1",
|
|
53
|
-
"@vex-chat/types": "^1.0.0-rc.1",
|
|
54
|
-
"eslint": "^10.1.0",
|
|
55
|
-
"eslint-config-prettier": "^9.0.0",
|
|
56
|
-
"husky": "^9.0.0",
|
|
57
|
-
"lint-staged": "^15.2.0",
|
|
58
|
-
"prettier": "^3.2.0",
|
|
59
|
-
"rimraf": "^6.1.3",
|
|
60
|
-
"typescript": "^6.0.2",
|
|
61
|
-
"vitest": "^3.0.0"
|
|
62
|
-
},
|
|
63
|
-
"lint-staged": {
|
|
64
|
-
"src/**/*.{ts}": [
|
|
65
|
-
"eslint --fix"
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"repository": {
|
|
69
|
-
"type": "git",
|
|
70
|
-
"url": "git+https://github.com/vex-chat/libvex-js.git"
|
|
71
|
-
},
|
|
72
|
-
"bugs": {
|
|
73
|
-
"url": "https://github.com/vex-chat/libvex-js/issues"
|
|
74
|
-
},
|
|
75
|
-
"homepage": "https://github.com/vex-chat/libvex-js#readme",
|
|
76
|
-
"publishConfig": {
|
|
77
|
-
"access": "public",
|
|
78
|
-
"registry": "https://registry.npmjs.org/"
|
|
79
|
-
}
|
|
80
111
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type nacl from "tweetnacl";
|
|
2
|
+
|
|
3
|
+
import { XKeyConvert, XUtils } from "../index.js";
|
|
4
|
+
|
|
5
|
+
const ed25519Keys = {
|
|
6
|
+
private:
|
|
7
|
+
"f69c92fbb224e1d75c5dffb5e40946e6106baa89ad73dbb6ef0bec2d8562d8a28d0538a45bce3d6fd43cd80a247da063c67cd01da2e263758567a51db5b1f7c6",
|
|
8
|
+
public: "8d0538a45bce3d6fd43cd80a247da063c67cd01da2e263758567a51db5b1f7c6",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const convertedX25519Keys = {
|
|
12
|
+
private: "10ed501acc2125730c294aa4b78eac989588d031015d1c77a75ea98aa7744b7a",
|
|
13
|
+
public: "55c4ca5a1d8e2859e186f36564cc41c9c9882ed9dbc01be8ec9a36b106eeee5b",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
test("convertKeyPair", () => {
|
|
17
|
+
const keys = keyPairFromString(ed25519Keys);
|
|
18
|
+
const converted = XKeyConvert.convertKeyPair(keys);
|
|
19
|
+
// ed2curve returns null if conversion fails, though for valid keys it shouldn't.
|
|
20
|
+
// We cast to any to allow lodash comparison or check for existence
|
|
21
|
+
expect(converted).toBeDefined();
|
|
22
|
+
if (converted) {
|
|
23
|
+
expect(keyPairToString(converted)).toEqual(convertedX25519Keys);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("convertPublicKey", () => {
|
|
28
|
+
const keys = keyPairFromString(ed25519Keys);
|
|
29
|
+
const convertedPublicKey = XKeyConvert.convertPublicKey(keys.publicKey);
|
|
30
|
+
if (!convertedPublicKey) {
|
|
31
|
+
throw new Error("Conversion failed.");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const correctConvertedKey = XUtils.decodeHex(convertedX25519Keys.public);
|
|
35
|
+
expect(XUtils.bytesEqual(convertedPublicKey, correctConvertedKey)).toBe(
|
|
36
|
+
true,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("convertPrivateKey", () => {
|
|
41
|
+
const keys = keyPairFromString(ed25519Keys);
|
|
42
|
+
const convertedPrivateKey = XKeyConvert.convertSecretKey(keys.secretKey);
|
|
43
|
+
if (!convertedPrivateKey) {
|
|
44
|
+
throw new Error("Conversion failed.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const correctConvertedKey = XUtils.decodeHex(convertedX25519Keys.private);
|
|
48
|
+
expect(XUtils.bytesEqual(convertedPrivateKey, correctConvertedKey)).toBe(
|
|
49
|
+
true,
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
function keyPairFromString(strKeyPair: { private: string; public: string }) {
|
|
54
|
+
return {
|
|
55
|
+
publicKey: XUtils.decodeHex(strKeyPair.public),
|
|
56
|
+
secretKey: XUtils.decodeHex(strKeyPair.private),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function keyPairToString(keyPair: nacl.BoxKeyPair | nacl.SignKeyPair): {
|
|
61
|
+
private: string;
|
|
62
|
+
public: string;
|
|
63
|
+
} {
|
|
64
|
+
return {
|
|
65
|
+
private: XUtils.encodeHex(keyPair.secretKey),
|
|
66
|
+
public: XUtils.encodeHex(keyPair.publicKey),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { XUtils } from "../../index.js";
|
|
2
|
+
const { bytesEqual } = XUtils;
|
|
3
|
+
|
|
4
|
+
test("bytesEqual", () => {
|
|
5
|
+
const bytes = [25, 23, 122, 142, 73, 92, 58];
|
|
6
|
+
|
|
7
|
+
const buf1 = Buffer.from(bytes);
|
|
8
|
+
const buf2 = Buffer.from(bytes);
|
|
9
|
+
|
|
10
|
+
expect(bytesEqual(buf1, buf2)).toBe(true);
|
|
11
|
+
|
|
12
|
+
bytes[0] = 0;
|
|
13
|
+
const buf3 = Buffer.from(bytes);
|
|
14
|
+
|
|
15
|
+
expect(bytesEqual(buf1, buf3)).toBe(false);
|
|
16
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { XUtils } from "../../index.js";
|
|
2
|
+
const { emptyHeader } = XUtils;
|
|
3
|
+
|
|
4
|
+
test("emptyHeader", () => {
|
|
5
|
+
const headerData =
|
|
6
|
+
"0000000000000000000000000000000000000000000000000000000000000000";
|
|
7
|
+
|
|
8
|
+
const eHeader = emptyHeader();
|
|
9
|
+
const testEmptyHeader = XUtils.decodeHex(headerData);
|
|
10
|
+
|
|
11
|
+
expect(XUtils.bytesEqual(eHeader, testEmptyHeader)).toBe(true);
|
|
12
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { XUtils } from "../../index.js";
|
|
2
|
+
|
|
3
|
+
const { bytesEqual, numberToUint8Arr } = XUtils;
|
|
4
|
+
|
|
5
|
+
test("numberToUint8Arr", () => {
|
|
6
|
+
const cases: [number, number[]][] = [
|
|
7
|
+
[255, [0, 0, 0, 0, 0, 255]],
|
|
8
|
+
[65535, [0, 0, 0, 0, 255, 255]],
|
|
9
|
+
[16777215, [0, 0, 0, 255, 255, 255]],
|
|
10
|
+
[4294967295, [0, 0, 255, 255, 255, 255]],
|
|
11
|
+
[1099511627775, [0, 255, 255, 255, 255, 255]],
|
|
12
|
+
[281474976710655, [255, 255, 255, 255, 255, 255]],
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
for (const [number, buffer] of cases) {
|
|
16
|
+
const arr = numberToUint8Arr(number);
|
|
17
|
+
expect(bytesEqual(arr, Buffer.from(buffer))).toBe(true);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
expect(() => numberToUint8Arr(281474976710656)).toThrow();
|
|
21
|
+
expect(() => numberToUint8Arr(-1)).toThrow();
|
|
22
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ResourceMsg } from "@vex-chat/types";
|
|
2
|
+
|
|
3
|
+
import { XUtils } from "../../index.js";
|
|
4
|
+
const { emptyHeader, packMessage, unpackMessage } = XUtils;
|
|
5
|
+
|
|
6
|
+
test("packMessage Round Trip", () => {
|
|
7
|
+
const testMessage: ResourceMsg = {
|
|
8
|
+
action: "create",
|
|
9
|
+
data: "A Server Name",
|
|
10
|
+
resourceType: "server",
|
|
11
|
+
transmissionID: "8154ac29-54fb-407c-8353-0f67742bb7c4",
|
|
12
|
+
type: "resource",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Pack the message using the new implementation
|
|
16
|
+
const packedBytes = packMessage(testMessage, emptyHeader());
|
|
17
|
+
|
|
18
|
+
// Unpack it immediately to verify consistency (Round Trip)
|
|
19
|
+
const [header, body] = unpackMessage(packedBytes);
|
|
20
|
+
|
|
21
|
+
expect(XUtils.bytesEqual(header, emptyHeader())).toBe(true);
|
|
22
|
+
expect(body).toEqual(testMessage);
|
|
23
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { XUtils } from "../../index.js";
|
|
2
|
+
const {
|
|
3
|
+
decodeBase64,
|
|
4
|
+
decodeHex,
|
|
5
|
+
decodeUTF8,
|
|
6
|
+
encodeBase64,
|
|
7
|
+
encodeHex,
|
|
8
|
+
encodeUTF8,
|
|
9
|
+
} = XUtils;
|
|
10
|
+
|
|
11
|
+
test("Encodes and decodes hex", () => {
|
|
12
|
+
const data = [
|
|
13
|
+
"a2dc693b93b3e2a31eb2b54f26f43b8ce971c6b9b4197544",
|
|
14
|
+
"9d9158ea82750c0b164834789f216d5a17a223d87e082199",
|
|
15
|
+
"e32079ba7c8ed5e62123ab55386689c2ec9f480ebb82f05c",
|
|
16
|
+
"e037b3f87bea23b8afea27c7ad173f5a43d0050559fbe091",
|
|
17
|
+
"df3cefb0f980f96eb5d6cc996702d6d166413fb2785772b1",
|
|
18
|
+
"6a328c1b103d1b331c9759ddde6c5df5753010a3c9881514",
|
|
19
|
+
"c5ad6470766845c420205700aaaed806456cae49b905aeed",
|
|
20
|
+
"5dc12b62156b1f68698b36b42e3e2f4716dffee09b768030",
|
|
21
|
+
"2985705f1f590b11e027ea6a05cbe4e0d351ab81748cbea0",
|
|
22
|
+
"6455945ea7110197a17a809cb973c2007eff629d5549273a",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
for (const value of data) {
|
|
26
|
+
expect(encodeHex(decodeHex(value)) === value).toBe(true);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("Encodes and decodes utf8", () => {
|
|
31
|
+
const data = [
|
|
32
|
+
"L-dr`?%z5%?R8rT:Lwvk",
|
|
33
|
+
"H]gy!'X\")(:V/3.'LpE/",
|
|
34
|
+
"5G%h:@%PvCOk R,[]=z>",
|
|
35
|
+
'#d868evg)LM"{04$gFt',
|
|
36
|
+
'?\\/sz?&mh"$!K1_`qc15',
|
|
37
|
+
"V{Yw[ R{5L}1T3OHSj.",
|
|
38
|
+
"%-Kek[HIfW=_z`r'R|Av",
|
|
39
|
+
"E.E'\"\\ jzyxpfc'.N*z`",
|
|
40
|
+
"p:&^?<[n<ScUXB#O=|z",
|
|
41
|
+
'D;`5`"@H7X8Iw0%KbJr8',
|
|
42
|
+
'#,y][nQ9]",.62Bwxj#d',
|
|
43
|
+
'[eN"USyz$Dg@%a=a)r2h',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const value of data) {
|
|
47
|
+
expect(encodeUTF8(decodeUTF8(value))).toBe(value);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("Encodes and decodes base64", () => {
|
|
52
|
+
const data = [
|
|
53
|
+
"+UMP/v5VnVF/qSrSDfcLAXZ9jEauYFrbAcgtE3z46bI=",
|
|
54
|
+
"Cb+zq/R1zMRSEMGA1p47XWzwD48NZ/JqLO1p1hUnpEY=",
|
|
55
|
+
"mODgEB/U3MnvMHuG5fQ0xv8NRqo24diRlzyzJ4/Et7g=",
|
|
56
|
+
"vvYVuOpi3/pMdP49C7TgTqEdk02/LlcIY9a0CPyOJsc=",
|
|
57
|
+
"S6vBIf8WXmPi/BPV3ei9CMgdanxBNiTl8oHQ/HSnvsU=",
|
|
58
|
+
"0i2WNMF8I5ewIAefTbBBjhS3sZwZ9tILLpksPE00bt8=",
|
|
59
|
+
"W3SHYUb/F3sWFytIYNG4TCBgrDT80L0A9bB335nU8/8=",
|
|
60
|
+
"vbov+TNLyWc+VdpH7egFOifdKup26ertUlutTv8kFyY=",
|
|
61
|
+
"re9JVfQRSsXaaUG9uLoMd/bW05xDcCnk0qaPh6CUn90=",
|
|
62
|
+
"X9AyjBOM9tAsXrINjeDr5wgMiZNlkK5HlOOtDBwMeFw=",
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
for (const value of data) {
|
|
66
|
+
expect(encodeBase64(decodeBase64(value)) === value).toBe(true);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { XUtils } from "../../index.js";
|
|
2
|
+
|
|
3
|
+
const { uint8ArrToNumber } = XUtils;
|
|
4
|
+
|
|
5
|
+
test("uint8ArrToNumber", () => {
|
|
6
|
+
const cases: [number, number[]][] = [
|
|
7
|
+
[255, [0, 0, 0, 0, 0, 255]],
|
|
8
|
+
[65535, [0, 0, 0, 0, 255, 255]],
|
|
9
|
+
[16777215, [0, 0, 0, 255, 255, 255]],
|
|
10
|
+
[4294967295, [0, 0, 255, 255, 255, 255]],
|
|
11
|
+
[1099511627775, [0, 255, 255, 255, 255, 255]],
|
|
12
|
+
[281474976710655, [255, 255, 255, 255, 255, 255]],
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
for (const [expected, buffer] of cases) {
|
|
16
|
+
const actual = uint8ArrToNumber(Buffer.from(buffer));
|
|
17
|
+
expect(actual === expected).toBe(true);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ResourceMsg } from "@vex-chat/types";
|
|
2
|
+
|
|
3
|
+
import { XUtils } from "../../index.js";
|
|
4
|
+
const { bytesEqual, emptyHeader, unpackMessage } = XUtils;
|
|
5
|
+
|
|
6
|
+
test("unpackMessage (Legacy Compatibility)", () => {
|
|
7
|
+
const testHeader = emptyHeader();
|
|
8
|
+
const testMessage: ResourceMsg = {
|
|
9
|
+
action: "create",
|
|
10
|
+
data: "A Server Name",
|
|
11
|
+
resourceType: "server",
|
|
12
|
+
transmissionID: "8154ac29-54fb-407c-8353-0f67742bb7c4",
|
|
13
|
+
type: "resource",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// This hex string was generated by the old version (msgpack-lite).
|
|
17
|
+
// We keep this test to ensure the new version (msgpackr) can read old data.
|
|
18
|
+
const packedTestMessage =
|
|
19
|
+
"000000000000000000000000000000000000000000000000000000000000000085a474797065a87265736f75726365ac7265736f7572636554797065a6736572766572a6616374696f6ea6637265617465ae7472616e736d697373696f6e4944d92438313534616332392d353466622d343037632d383335332d306636373734326262376334a464617461ad4120536572766572204e616d65";
|
|
20
|
+
const messageData = XUtils.decodeHex(packedTestMessage);
|
|
21
|
+
|
|
22
|
+
const [unpackedHeader, unpackedMessage] = unpackMessage(messageData);
|
|
23
|
+
expect(bytesEqual(unpackedHeader, testHeader)).toBe(true);
|
|
24
|
+
expect(unpackedMessage).toEqual(testMessage);
|
|
25
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { xConcat, XUtils } from "../index.js";
|
|
2
|
+
|
|
3
|
+
test("xConcat", () => {
|
|
4
|
+
const data1 = "dead";
|
|
5
|
+
const data2 = "beef";
|
|
6
|
+
const data3 = "bead";
|
|
7
|
+
const correctConcatData = data1 + data2 + data3;
|
|
8
|
+
|
|
9
|
+
const concatData = XUtils.encodeHex(
|
|
10
|
+
xConcat(
|
|
11
|
+
XUtils.decodeHex(data1),
|
|
12
|
+
XUtils.decodeHex(data2),
|
|
13
|
+
XUtils.decodeHex(data3),
|
|
14
|
+
),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(concatData === correctConcatData).toBe(true);
|
|
18
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { xDH, XUtils } from "../index.js";
|
|
2
|
+
|
|
3
|
+
test("xDH", () => {
|
|
4
|
+
const myPrivateKey =
|
|
5
|
+
"918ed243e2c6c507168b20e8b167cff33a10c30e99e8defe28dc2147f5cce703";
|
|
6
|
+
const theirPublicKey =
|
|
7
|
+
"6f4cc1ffc4009bd4f94628ba5922e40afa3491f0daa43ec9da0f7dc39bb1c026";
|
|
8
|
+
|
|
9
|
+
const correctDerivedKey =
|
|
10
|
+
"19a8594bdcf875ec9d4b8b9615ea8b73a0b327bb64b8f727dd2dee3a603a2230";
|
|
11
|
+
const derivedKey = XUtils.encodeHex(
|
|
12
|
+
xDH(XUtils.decodeHex(myPrivateKey), XUtils.decodeHex(theirPublicKey)),
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
expect(correctDerivedKey === derivedKey).toBe(true);
|
|
16
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { xEncode, XUtils } from "../index.js";
|
|
2
|
+
|
|
3
|
+
test("xEncode", () => {
|
|
4
|
+
const PK =
|
|
5
|
+
"3a488fc006156e77e58793846c204f17e0df88e914fc7638a084524a9124bf87";
|
|
6
|
+
const correctEncoded =
|
|
7
|
+
"00013a488fc006156e77e58793846c204f17e0df88e914fc7638a084524a9124bf87";
|
|
8
|
+
|
|
9
|
+
const encoded = XUtils.encodeHex(xEncode("X25519", XUtils.decodeHex(PK)));
|
|
10
|
+
expect(encoded === correctEncoded).toBe(true);
|
|
11
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createHmac } from "crypto";
|
|
2
|
+
|
|
3
|
+
import { Packr } from "msgpackr";
|
|
4
|
+
|
|
5
|
+
import { xHMAC, XUtils } from "../index.js";
|
|
6
|
+
|
|
7
|
+
test("xHMAC", () => {
|
|
8
|
+
const message = {
|
|
9
|
+
hello: "world",
|
|
10
|
+
};
|
|
11
|
+
const SK =
|
|
12
|
+
"b45203ef77c0a7fe7f771297f3e5c8248fe5b9f18ecf77faf8a8cef1058e630a";
|
|
13
|
+
|
|
14
|
+
// Must match the Packr config in src/index.ts
|
|
15
|
+
const packer = new Packr({ moreTypes: false, useRecords: false });
|
|
16
|
+
const packedMsg = packer.pack(message);
|
|
17
|
+
const hmacGen = createHmac("sha256", Buffer.from(XUtils.decodeHex(SK)));
|
|
18
|
+
hmacGen.update(packedMsg);
|
|
19
|
+
const expectedHMAC = XUtils.encodeHex(Uint8Array.from(hmacGen.digest()));
|
|
20
|
+
|
|
21
|
+
// Run the actual function
|
|
22
|
+
const hmac = XUtils.encodeHex(xHMAC(message, XUtils.decodeHex(SK)));
|
|
23
|
+
|
|
24
|
+
// Compare
|
|
25
|
+
expect(hmac).toBe(expectedHMAC);
|
|
26
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { xMnemonic, XUtils } from "../index.js";
|
|
2
|
+
|
|
3
|
+
test("xMnemonic", () => {
|
|
4
|
+
const IKM =
|
|
5
|
+
"dfb3c08de7335cc352e2c063c8e6891a06e17bf0dfcb4eec8139fc5eaf482b0e";
|
|
6
|
+
const correctMnemonic =
|
|
7
|
+
"text own casino solar cupboard giant entire fix glow elbow pelican cross host sadness sell west exclude goat example weather turtle piano promote scene";
|
|
8
|
+
|
|
9
|
+
const mnemonic = xMnemonic(XUtils.decodeHex(IKM));
|
|
10
|
+
|
|
11
|
+
expect(mnemonic === correctMnemonic).toBe(true);
|
|
12
|
+
});
|