@trust-proto/auth-node 0.2.0 → 0.2.1
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/index.cjs +1346 -0
- package/dist/index.d.cts +423 -0
- package/dist/index.js +3 -1
- package/package.json +9 -8
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1346 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
COMMAND_ACTIVATED: () => COMMAND_ACTIVATED,
|
|
34
|
+
COMMAND_AUTH: () => COMMAND_AUTH,
|
|
35
|
+
COMMAND_AUTH_DECLINED: () => COMMAND_AUTH_DECLINED,
|
|
36
|
+
COMMAND_AUTH_RESULT: () => COMMAND_AUTH_RESULT,
|
|
37
|
+
COMMAND_AUTH_TIMEOUT: () => COMMAND_AUTH_TIMEOUT,
|
|
38
|
+
COMMAND_ERROR: () => COMMAND_ERROR,
|
|
39
|
+
COMMAND_READY: () => COMMAND_READY,
|
|
40
|
+
ConsoleLogger: () => ConsoleLogger,
|
|
41
|
+
DECLINE_REASON: () => DECLINE_REASON,
|
|
42
|
+
DEFAULT_PORT: () => DEFAULT_PORT,
|
|
43
|
+
LiberionAuth: () => LiberionAuth,
|
|
44
|
+
NoOpLogger: () => NoOpLogger,
|
|
45
|
+
PQCrypto: () => PQCrypto,
|
|
46
|
+
STATUS: () => STATUS,
|
|
47
|
+
USER_CONTRACT_ABI: () => USER_CONTRACT_ABI,
|
|
48
|
+
checkSignature: () => checkSignature,
|
|
49
|
+
clearTokenCache: () => clearTokenCache,
|
|
50
|
+
createWinstonAdapter: () => createWinstonAdapter,
|
|
51
|
+
decryptBuffer: () => decryptBuffer,
|
|
52
|
+
encryptBuffer: () => encryptBuffer,
|
|
53
|
+
extractIpfsHash: () => extractIpfsHash,
|
|
54
|
+
getNetworkConfig: () => getNetworkConfig,
|
|
55
|
+
getTokenFromIPFS: () => getTokenFromIPFS,
|
|
56
|
+
initUserCrypto: () => initUserCrypto,
|
|
57
|
+
shortenAddress: () => shortenAddress
|
|
58
|
+
});
|
|
59
|
+
module.exports = __toCommonJS(index_exports);
|
|
60
|
+
|
|
61
|
+
// src/liberion-auth.ts
|
|
62
|
+
var import_uuid = require("uuid");
|
|
63
|
+
var import_ws2 = __toESM(require("ws"), 1);
|
|
64
|
+
var import_https = __toESM(require("https"), 1);
|
|
65
|
+
var import_http = __toESM(require("http"), 1);
|
|
66
|
+
var import_msgpack2 = require("@msgpack/msgpack");
|
|
67
|
+
|
|
68
|
+
// src/adapters/logger.ts
|
|
69
|
+
var NoOpLogger = class {
|
|
70
|
+
info() {
|
|
71
|
+
}
|
|
72
|
+
warn() {
|
|
73
|
+
}
|
|
74
|
+
error() {
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var ConsoleLogger = class {
|
|
78
|
+
prefix;
|
|
79
|
+
constructor(prefix = "[LiberionAuth]") {
|
|
80
|
+
this.prefix = prefix;
|
|
81
|
+
}
|
|
82
|
+
info(message, meta) {
|
|
83
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
84
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
85
|
+
console.log(`${timestamp} ${this.prefix} INFO: ${message}`, meta);
|
|
86
|
+
} else {
|
|
87
|
+
console.log(`${timestamp} ${this.prefix} INFO: ${message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
warn(message, meta) {
|
|
91
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
92
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
93
|
+
console.warn(`${timestamp} ${this.prefix} WARN: ${message}`, meta);
|
|
94
|
+
} else {
|
|
95
|
+
console.warn(`${timestamp} ${this.prefix} WARN: ${message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
error(message, meta) {
|
|
99
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
100
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
101
|
+
console.error(`${timestamp} ${this.prefix} ERROR: ${message}`, meta);
|
|
102
|
+
} else {
|
|
103
|
+
console.error(`${timestamp} ${this.prefix} ERROR: ${message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function createWinstonAdapter(winston) {
|
|
108
|
+
return {
|
|
109
|
+
info: (msg, meta) => winston.info(msg, meta),
|
|
110
|
+
warn: (msg, meta) => winston.warn(msg, meta),
|
|
111
|
+
error: (msg, meta) => winston.error(msg, meta)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function shortenAddress(address) {
|
|
115
|
+
if (!address || address.length < 10) return address ?? "";
|
|
116
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/crypto/aes.ts
|
|
120
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
121
|
+
var AES_CIPHER = "aes-256-cbc";
|
|
122
|
+
function encryptBuffer(buffer, key) {
|
|
123
|
+
const hashedKey = import_crypto.default.createHash("sha256").update(key).digest("hex").substring(0, 32);
|
|
124
|
+
const iv = import_crypto.default.randomBytes(16);
|
|
125
|
+
const cipher = import_crypto.default.createCipheriv(
|
|
126
|
+
AES_CIPHER,
|
|
127
|
+
Buffer.from(hashedKey),
|
|
128
|
+
iv
|
|
129
|
+
);
|
|
130
|
+
const encrypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
|
|
131
|
+
return Buffer.concat([iv, encrypted]);
|
|
132
|
+
}
|
|
133
|
+
function decryptBuffer(data, key) {
|
|
134
|
+
const hashedKey = import_crypto.default.createHash("sha256").update(key).digest("hex").substring(0, 32);
|
|
135
|
+
const iv = data.subarray(0, 16);
|
|
136
|
+
const encryptedData = data.subarray(16);
|
|
137
|
+
const decipher = import_crypto.default.createDecipheriv(AES_CIPHER, hashedKey, iv);
|
|
138
|
+
return Buffer.concat([decipher.update(encryptedData), decipher.final()]);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/crypto/signature.ts
|
|
142
|
+
var import_ml_dsa = require("@noble/post-quantum/ml-dsa.js");
|
|
143
|
+
function normalizeToBytes(data) {
|
|
144
|
+
if (data instanceof Uint8Array) {
|
|
145
|
+
return data;
|
|
146
|
+
}
|
|
147
|
+
if (Buffer.isBuffer(data)) {
|
|
148
|
+
return new Uint8Array(data);
|
|
149
|
+
}
|
|
150
|
+
if (data instanceof ArrayBuffer) {
|
|
151
|
+
return new Uint8Array(data);
|
|
152
|
+
}
|
|
153
|
+
if (typeof data === "string") {
|
|
154
|
+
if (data.length % 2 === 0 && /^[0-9a-fA-F]*$/.test(data)) {
|
|
155
|
+
return new Uint8Array(Buffer.from(data, "hex"));
|
|
156
|
+
}
|
|
157
|
+
return new Uint8Array(Buffer.from(data, "utf8"));
|
|
158
|
+
}
|
|
159
|
+
throw new Error(`Invalid data type: ${typeof data}`);
|
|
160
|
+
}
|
|
161
|
+
function normalizeSignature(signature) {
|
|
162
|
+
if (signature instanceof Uint8Array) {
|
|
163
|
+
return signature;
|
|
164
|
+
}
|
|
165
|
+
if (Buffer.isBuffer(signature)) {
|
|
166
|
+
return new Uint8Array(signature);
|
|
167
|
+
}
|
|
168
|
+
if (signature instanceof ArrayBuffer) {
|
|
169
|
+
return new Uint8Array(signature);
|
|
170
|
+
}
|
|
171
|
+
if (typeof signature === "string") {
|
|
172
|
+
return new Uint8Array(Buffer.from(signature, "hex"));
|
|
173
|
+
}
|
|
174
|
+
throw new Error(`Invalid signature format: ${typeof signature}`);
|
|
175
|
+
}
|
|
176
|
+
function initUserCrypto(userToken, logger = new NoOpLogger()) {
|
|
177
|
+
logger.info("[initUserCrypto] Initializing user crypto with ML-DSA-87");
|
|
178
|
+
if (!userToken || !userToken.publicKeySign) {
|
|
179
|
+
throw new Error("Invalid user token: publicKeySign not found");
|
|
180
|
+
}
|
|
181
|
+
const dsaPublicKey = new Uint8Array(
|
|
182
|
+
Buffer.from(userToken.publicKeySign, "base64")
|
|
183
|
+
);
|
|
184
|
+
if (dsaPublicKey.length !== 2592) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`Invalid ML-DSA-87 public key size: expected 2592 bytes, got ${dsaPublicKey.length}`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
let kemPublicKey = null;
|
|
190
|
+
if (userToken.publicKeyEncrypt) {
|
|
191
|
+
try {
|
|
192
|
+
const kemBuffer = Buffer.from(userToken.publicKeyEncrypt, "base64");
|
|
193
|
+
if (kemBuffer.length !== 1568) {
|
|
194
|
+
logger.warn(
|
|
195
|
+
`[initUserCrypto] Invalid ML-KEM-1024 public key size: expected 1568, got ${kemBuffer.length}`
|
|
196
|
+
);
|
|
197
|
+
} else {
|
|
198
|
+
kemPublicKey = new Uint8Array(kemBuffer);
|
|
199
|
+
}
|
|
200
|
+
} catch (ex) {
|
|
201
|
+
const error = ex;
|
|
202
|
+
logger.warn(
|
|
203
|
+
`[initUserCrypto] Failed to parse publicKeyEncrypt: ${error.message}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const verifySignature = (msg, sig) => {
|
|
208
|
+
try {
|
|
209
|
+
const msgBytes = normalizeToBytes(msg);
|
|
210
|
+
const sigBytes = normalizeSignature(sig);
|
|
211
|
+
const isValid = import_ml_dsa.ml_dsa87.verify(sigBytes, msgBytes, dsaPublicKey);
|
|
212
|
+
logger.info("[initUserCrypto.verifySignature] Verification result", {
|
|
213
|
+
isValid,
|
|
214
|
+
msgLength: msgBytes.length,
|
|
215
|
+
sigLength: sigBytes.length
|
|
216
|
+
});
|
|
217
|
+
return isValid;
|
|
218
|
+
} catch (ex) {
|
|
219
|
+
const error = ex;
|
|
220
|
+
logger.error(
|
|
221
|
+
`[initUserCrypto.verifySignature] Error: ${error.message}`
|
|
222
|
+
);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
logger.info("[initUserCrypto] Crypto initialized successfully", {
|
|
227
|
+
algorithm: "ML-DSA-87 + ML-KEM-1024",
|
|
228
|
+
dsaPublicKeySize: dsaPublicKey.length,
|
|
229
|
+
kemPublicKeySize: kemPublicKey?.length ?? 0,
|
|
230
|
+
hasEncryption: !!kemPublicKey
|
|
231
|
+
});
|
|
232
|
+
return {
|
|
233
|
+
dsaPublicKey,
|
|
234
|
+
kemPublicKey,
|
|
235
|
+
algorithm: "ML-DSA-87",
|
|
236
|
+
userToken,
|
|
237
|
+
verifySignature
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function checkSignature(crypto2, data, signature, logger = new NoOpLogger()) {
|
|
241
|
+
logger.info("[checkSignature] Checking ML-DSA-87 signature");
|
|
242
|
+
if (!crypto2 || !crypto2.verifySignature) {
|
|
243
|
+
throw new Error("Invalid crypto instance: missing verifySignature method");
|
|
244
|
+
}
|
|
245
|
+
if (!data || !signature) {
|
|
246
|
+
throw new Error("Missing data or signature");
|
|
247
|
+
}
|
|
248
|
+
const msgBytes = normalizeToBytes(data);
|
|
249
|
+
const sigBytes = normalizeSignature(signature);
|
|
250
|
+
logger.info("[checkSignature] Data and signature normalized", {
|
|
251
|
+
dataLength: msgBytes.length,
|
|
252
|
+
signatureLength: sigBytes.length,
|
|
253
|
+
algorithm: crypto2.algorithm
|
|
254
|
+
});
|
|
255
|
+
if (sigBytes.length < 4500 || sigBytes.length > 4700) {
|
|
256
|
+
logger.warn("[checkSignature] Unexpected signature size", {
|
|
257
|
+
expected: "~4595 bytes (ML-DSA-87)",
|
|
258
|
+
actual: sigBytes.length
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
const isValid = crypto2.verifySignature(msgBytes, sigBytes);
|
|
262
|
+
if (!isValid) {
|
|
263
|
+
throw new Error("Invalid signature");
|
|
264
|
+
}
|
|
265
|
+
logger.info("[checkSignature] ML-DSA-87 signature verified successfully");
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/blockchain/token-provider.ts
|
|
270
|
+
var import_ethers = require("ethers");
|
|
271
|
+
|
|
272
|
+
// src/blockchain/constants.ts
|
|
273
|
+
var PRODUCTION_CONFIG = {
|
|
274
|
+
RPC_ENDPOINT: "https://bc.liberion.com/rpc",
|
|
275
|
+
USER_CONTRACT_ADDRESS: "0xB0b23F79Bf023C97f0235BC0ffC5a8258C03fef9",
|
|
276
|
+
IPFS_GATEWAY: "https://secure.liberion.com",
|
|
277
|
+
TRUST_GATE_URL: "wss://gate.liberion.com"
|
|
278
|
+
};
|
|
279
|
+
var DEVELOPMENT_CONFIG = {
|
|
280
|
+
RPC_ENDPOINT: "https://bc.liberion.dev/rpc",
|
|
281
|
+
USER_CONTRACT_ADDRESS: "0xb584861f5760E9B04B7439c777246c5B82FE6Fff",
|
|
282
|
+
IPFS_GATEWAY: "https://secure.liberion.dev",
|
|
283
|
+
TRUST_GATE_URL: "wss://gate.liberion.dev"
|
|
284
|
+
};
|
|
285
|
+
function getNetworkConfig(env = "production") {
|
|
286
|
+
return env === "development" ? DEVELOPMENT_CONFIG : PRODUCTION_CONFIG;
|
|
287
|
+
}
|
|
288
|
+
var USER_CONTRACT_ABI = [
|
|
289
|
+
{
|
|
290
|
+
inputs: [
|
|
291
|
+
{
|
|
292
|
+
internalType: "address",
|
|
293
|
+
name: "tokenId",
|
|
294
|
+
type: "address"
|
|
295
|
+
}
|
|
296
|
+
],
|
|
297
|
+
name: "tokenURI",
|
|
298
|
+
outputs: [
|
|
299
|
+
{
|
|
300
|
+
internalType: "string",
|
|
301
|
+
name: "",
|
|
302
|
+
type: "string"
|
|
303
|
+
}
|
|
304
|
+
],
|
|
305
|
+
stateMutability: "view",
|
|
306
|
+
type: "function"
|
|
307
|
+
}
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
// src/blockchain/token-provider.ts
|
|
311
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
312
|
+
var CACHE_TTL = 15 * 60 * 1e3;
|
|
313
|
+
function extractIpfsHash(tokenURI) {
|
|
314
|
+
if (!tokenURI) {
|
|
315
|
+
throw new Error("tokenURI is empty");
|
|
316
|
+
}
|
|
317
|
+
if (tokenURI.startsWith("ipfs://")) {
|
|
318
|
+
return tokenURI.replace("ipfs://", "");
|
|
319
|
+
}
|
|
320
|
+
if (tokenURI.includes("/ipfs/")) {
|
|
321
|
+
const parts = tokenURI.split("/ipfs/");
|
|
322
|
+
return parts[1];
|
|
323
|
+
}
|
|
324
|
+
if (tokenURI.includes("liberion.com/")) {
|
|
325
|
+
const parts = tokenURI.split("/");
|
|
326
|
+
return parts[parts.length - 1];
|
|
327
|
+
}
|
|
328
|
+
return tokenURI;
|
|
329
|
+
}
|
|
330
|
+
async function fetchFromIPFS(ipfsHash, ipfsGateway, logger) {
|
|
331
|
+
const cached = tokenCache.get(ipfsHash);
|
|
332
|
+
if (cached && cached.expiry > Date.now()) {
|
|
333
|
+
logger.info("[fetchFromIPFS] Cache hit", { ipfsHash });
|
|
334
|
+
return cached.data;
|
|
335
|
+
}
|
|
336
|
+
const url = `${ipfsGateway}/${ipfsHash}`;
|
|
337
|
+
logger.info("[fetchFromIPFS] Fetching from IPFS", { url });
|
|
338
|
+
const response = await fetch(url, {
|
|
339
|
+
headers: {
|
|
340
|
+
Accept: "application/json"
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
if (!response.ok) {
|
|
344
|
+
throw new Error(`IPFS fetch failed: ${response.status} ${response.statusText}`);
|
|
345
|
+
}
|
|
346
|
+
const data = await response.json();
|
|
347
|
+
tokenCache.set(ipfsHash, {
|
|
348
|
+
data,
|
|
349
|
+
expiry: Date.now() + CACHE_TTL
|
|
350
|
+
});
|
|
351
|
+
logger.info("[fetchFromIPFS] Token fetched and cached", { ipfsHash });
|
|
352
|
+
return data;
|
|
353
|
+
}
|
|
354
|
+
async function getTokenFromIPFS(address, logger = new NoOpLogger(), networkConfig) {
|
|
355
|
+
const config = networkConfig ?? getNetworkConfig();
|
|
356
|
+
logger.info("[getTokenFromIPFS] Getting SNFT token from IPFS", { address: shortenAddress(address) });
|
|
357
|
+
const provider = new import_ethers.JsonRpcProvider(config.RPC_ENDPOINT);
|
|
358
|
+
const contract = new import_ethers.Contract(
|
|
359
|
+
config.USER_CONTRACT_ADDRESS,
|
|
360
|
+
USER_CONTRACT_ABI,
|
|
361
|
+
provider
|
|
362
|
+
);
|
|
363
|
+
const tokenURI = await contract.tokenURI(address);
|
|
364
|
+
logger.info("[getTokenFromIPFS] Token URI retrieved", {
|
|
365
|
+
address: shortenAddress(address),
|
|
366
|
+
tokenURI
|
|
367
|
+
});
|
|
368
|
+
const ipfsHash = extractIpfsHash(tokenURI);
|
|
369
|
+
logger.info("[getTokenFromIPFS] IPFS hash extracted", {
|
|
370
|
+
address: shortenAddress(address),
|
|
371
|
+
ipfsHash
|
|
372
|
+
});
|
|
373
|
+
const userToken = await fetchFromIPFS(ipfsHash, config.IPFS_GATEWAY, logger);
|
|
374
|
+
if (!userToken.publicKeySign || !userToken.publicKeyEncrypt) {
|
|
375
|
+
throw new Error("Invalid SNFT token structure: missing public keys");
|
|
376
|
+
}
|
|
377
|
+
logger.info("[getTokenFromIPFS] SNFT token fetched successfully", {
|
|
378
|
+
address: shortenAddress(address),
|
|
379
|
+
hasPublicKeySign: !!userToken.publicKeySign,
|
|
380
|
+
hasPublicKeyEncrypt: !!userToken.publicKeyEncrypt,
|
|
381
|
+
hasAssets: !!userToken.assets
|
|
382
|
+
});
|
|
383
|
+
return userToken;
|
|
384
|
+
}
|
|
385
|
+
function clearTokenCache() {
|
|
386
|
+
tokenCache.clear();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/protocol/trust-gate-client.ts
|
|
390
|
+
var import_ws = __toESM(require("ws"), 1);
|
|
391
|
+
var import_msgpack = require("@msgpack/msgpack");
|
|
392
|
+
var TrustGateClient = class {
|
|
393
|
+
address;
|
|
394
|
+
timeout;
|
|
395
|
+
ws = null;
|
|
396
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
397
|
+
requestId = 0;
|
|
398
|
+
connectionTimeout = null;
|
|
399
|
+
logger;
|
|
400
|
+
constructor(options) {
|
|
401
|
+
this.address = options.address;
|
|
402
|
+
this.timeout = options.timeout ?? 1e4;
|
|
403
|
+
this.logger = options.logger ?? new NoOpLogger();
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Opens WebSocket connection
|
|
407
|
+
*/
|
|
408
|
+
async open() {
|
|
409
|
+
this.logger.info(`[TrustGateClient] Attempting to connect to ${this.address}`);
|
|
410
|
+
return new Promise((resolve, reject) => {
|
|
411
|
+
try {
|
|
412
|
+
this.ws = new import_ws.default(this.address);
|
|
413
|
+
this.ws.on("open", () => {
|
|
414
|
+
if (this.connectionTimeout) {
|
|
415
|
+
clearTimeout(this.connectionTimeout);
|
|
416
|
+
}
|
|
417
|
+
this.logger.info(`[TrustGateClient] Connected to ${this.address}`);
|
|
418
|
+
resolve();
|
|
419
|
+
});
|
|
420
|
+
this.ws.on("message", (data) => {
|
|
421
|
+
try {
|
|
422
|
+
const message = (0, import_msgpack.decode)(data);
|
|
423
|
+
this.handleMessage(message);
|
|
424
|
+
} catch (ex) {
|
|
425
|
+
const error = ex;
|
|
426
|
+
this.logger.error(
|
|
427
|
+
`[TrustGateClient] Failed to decode message: ${error.message}`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
this.ws.on("close", (code) => {
|
|
432
|
+
this.logger.info(
|
|
433
|
+
`[TrustGateClient] Connection closed with code ${code}`
|
|
434
|
+
);
|
|
435
|
+
this.pendingRequests.forEach((request, id) => {
|
|
436
|
+
request.reject(new Error(`Connection closed with code ${code}`));
|
|
437
|
+
this.pendingRequests.delete(id);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
this.ws.on("error", (error) => {
|
|
441
|
+
if (this.connectionTimeout) {
|
|
442
|
+
clearTimeout(this.connectionTimeout);
|
|
443
|
+
}
|
|
444
|
+
this.logger.error("[TrustGateClient] Connection error", {
|
|
445
|
+
message: error.message,
|
|
446
|
+
code: error.code,
|
|
447
|
+
address: this.address
|
|
448
|
+
});
|
|
449
|
+
const enhancedError = new Error(
|
|
450
|
+
`Failed to connect to Trust Gate Server at ${this.address}: ${error.message}`
|
|
451
|
+
);
|
|
452
|
+
enhancedError.code = error.code;
|
|
453
|
+
reject(enhancedError);
|
|
454
|
+
});
|
|
455
|
+
this.connectionTimeout = setTimeout(() => {
|
|
456
|
+
if (this.ws && this.ws.readyState !== import_ws.default.OPEN) {
|
|
457
|
+
this.ws.terminate();
|
|
458
|
+
this.logger.error("[TrustGateClient] Connection timeout", {
|
|
459
|
+
address: this.address,
|
|
460
|
+
timeout: this.timeout
|
|
461
|
+
});
|
|
462
|
+
reject(
|
|
463
|
+
new Error(
|
|
464
|
+
`Connection timeout: Trust Gate Server at ${this.address} did not respond within ${this.timeout}ms`
|
|
465
|
+
)
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}, this.timeout);
|
|
469
|
+
} catch (ex) {
|
|
470
|
+
reject(ex);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Sends message and waits for response
|
|
476
|
+
*/
|
|
477
|
+
send(data) {
|
|
478
|
+
if (!this.ws || this.ws.readyState !== import_ws.default.OPEN) {
|
|
479
|
+
return Promise.reject(new Error("WebSocket is not open"));
|
|
480
|
+
}
|
|
481
|
+
return new Promise((resolve, reject) => {
|
|
482
|
+
const requestId = ++this.requestId;
|
|
483
|
+
const timeout = setTimeout(() => {
|
|
484
|
+
this.pendingRequests.delete(requestId);
|
|
485
|
+
reject(new Error("Request timeout"));
|
|
486
|
+
}, 3e4);
|
|
487
|
+
this.pendingRequests.set(requestId, {
|
|
488
|
+
resolve,
|
|
489
|
+
reject,
|
|
490
|
+
timeout
|
|
491
|
+
});
|
|
492
|
+
const message = (0, import_msgpack.encode)({ ...data, _requestId: requestId });
|
|
493
|
+
this.ws.send(message);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Handles incoming message
|
|
498
|
+
*/
|
|
499
|
+
handleMessage(message) {
|
|
500
|
+
const requestId = message._requestId;
|
|
501
|
+
if (!requestId) {
|
|
502
|
+
this.logger.warn(
|
|
503
|
+
"[TrustGateClient] Received message without requestId",
|
|
504
|
+
message
|
|
505
|
+
);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const pending = this.pendingRequests.get(requestId);
|
|
509
|
+
if (!pending) {
|
|
510
|
+
this.logger.warn(
|
|
511
|
+
`[TrustGateClient] No pending request for id ${requestId}`
|
|
512
|
+
);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
clearTimeout(pending.timeout);
|
|
516
|
+
this.pendingRequests.delete(requestId);
|
|
517
|
+
if (message._ === "error") {
|
|
518
|
+
pending.reject(
|
|
519
|
+
new Error(message.message || "Unknown error")
|
|
520
|
+
);
|
|
521
|
+
} else {
|
|
522
|
+
pending.resolve(message);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Closes WebSocket connection
|
|
527
|
+
*/
|
|
528
|
+
close() {
|
|
529
|
+
if (this.connectionTimeout) {
|
|
530
|
+
clearTimeout(this.connectionTimeout);
|
|
531
|
+
}
|
|
532
|
+
if (this.ws) {
|
|
533
|
+
this.ws.close();
|
|
534
|
+
this.ws = null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Creates authorization task via Trust Gate Server
|
|
539
|
+
*/
|
|
540
|
+
async createTask(params) {
|
|
541
|
+
const response = await this.send({
|
|
542
|
+
_: "task_init",
|
|
543
|
+
projectId: params.projectId,
|
|
544
|
+
scenarioId: params.scenarioId,
|
|
545
|
+
clientKey: params.clientKey
|
|
546
|
+
});
|
|
547
|
+
if (response.status !== "ok") {
|
|
548
|
+
throw new Error(response.message || "Task creation failed");
|
|
549
|
+
}
|
|
550
|
+
return {
|
|
551
|
+
linkWeb: response.linkWeb,
|
|
552
|
+
taskId: response.taskId
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// src/protocol/constants.ts
|
|
558
|
+
var COMMAND_ACTIVATE = "activate";
|
|
559
|
+
var COMMAND_READY = "ready";
|
|
560
|
+
var COMMAND_AUTH = "auth";
|
|
561
|
+
var COMMAND_AUTH_RESULT = "auth_result";
|
|
562
|
+
var COMMAND_AUTH_INIT = "auth_init";
|
|
563
|
+
var COMMAND_ACTIVATED = "activated";
|
|
564
|
+
var COMMAND_AUTH_DECLINED = "declined";
|
|
565
|
+
var COMMAND_AUTH_TIMEOUT = "timeout";
|
|
566
|
+
var COMMAND_RECONNECT = "reconnect";
|
|
567
|
+
var COMMAND_CONNECTION_FAILED = "connection_failed";
|
|
568
|
+
var COMMAND_ERROR = "error";
|
|
569
|
+
var COMMAND_HEALTH = "health";
|
|
570
|
+
var SOCKET_PING_TIMEOUT = 3e4;
|
|
571
|
+
var AUTHORIZATION_TIME_FRAME = 10 * 60 * 1e3;
|
|
572
|
+
var DEFAULT_PORT = 31313;
|
|
573
|
+
var STATUS = {
|
|
574
|
+
OK: "ok",
|
|
575
|
+
FAILED: "error"
|
|
576
|
+
};
|
|
577
|
+
var DECLINE_REASON = {
|
|
578
|
+
USER: "user_declined",
|
|
579
|
+
TIMEOUT: "timeout",
|
|
580
|
+
ERROR: "error",
|
|
581
|
+
UNKNOWN: "unknown"
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/liberion-auth.ts
|
|
585
|
+
var LiberionAuth = class {
|
|
586
|
+
logger;
|
|
587
|
+
projectId;
|
|
588
|
+
secretCode;
|
|
589
|
+
networkConfig;
|
|
590
|
+
sessions = {};
|
|
591
|
+
interval = null;
|
|
592
|
+
// Callbacks
|
|
593
|
+
onHello;
|
|
594
|
+
onSuccess;
|
|
595
|
+
onDecline;
|
|
596
|
+
// Static command exports for compatibility
|
|
597
|
+
static COMMAND_AUTH = COMMAND_AUTH;
|
|
598
|
+
static COMMAND_READY = COMMAND_READY;
|
|
599
|
+
constructor(config) {
|
|
600
|
+
this.logger = config.logger ?? (config.debug ? new ConsoleLogger() : new NoOpLogger());
|
|
601
|
+
if (!(0, import_uuid.validate)(config.projectId)) {
|
|
602
|
+
this.logger.error(
|
|
603
|
+
"[LiberionAuth] Invalid projectId (should be UUID string)"
|
|
604
|
+
);
|
|
605
|
+
throw new Error("Invalid projectId: must be a valid UUID");
|
|
606
|
+
}
|
|
607
|
+
this.projectId = config.projectId;
|
|
608
|
+
this.secretCode = config.secretCode;
|
|
609
|
+
this.networkConfig = getNetworkConfig(config.environment);
|
|
610
|
+
this.onHello = config.onHello;
|
|
611
|
+
this.onSuccess = config.onSuccess;
|
|
612
|
+
this.onDecline = config.onDecline;
|
|
613
|
+
const port = config.port ?? DEFAULT_PORT;
|
|
614
|
+
const server = config.ssl ? import_https.default.createServer(config.ssl) : import_http.default.createServer();
|
|
615
|
+
this.logger.info(
|
|
616
|
+
`[LiberionAuth] Starting ws${config.ssl ? "s" : ""} server on port ${port}`
|
|
617
|
+
);
|
|
618
|
+
const wsServer = new import_ws2.WebSocketServer({ server });
|
|
619
|
+
server.listen(port);
|
|
620
|
+
wsServer.on("connection", (socket) => {
|
|
621
|
+
const ws = socket;
|
|
622
|
+
this.newClient(ws);
|
|
623
|
+
ws.on("message", (data) => {
|
|
624
|
+
this.request(ws, data);
|
|
625
|
+
});
|
|
626
|
+
ws.on("close", (code) => {
|
|
627
|
+
this.handleClose(ws, code);
|
|
628
|
+
});
|
|
629
|
+
ws.isAlive = true;
|
|
630
|
+
ws.on("pong", () => {
|
|
631
|
+
ws.isAlive = true;
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
this.interval = setInterval(() => {
|
|
635
|
+
wsServer.clients.forEach((socket) => {
|
|
636
|
+
const ws = socket;
|
|
637
|
+
if (ws.isAlive === false) {
|
|
638
|
+
return ws.terminate();
|
|
639
|
+
}
|
|
640
|
+
ws.isAlive = false;
|
|
641
|
+
ws.ping();
|
|
642
|
+
});
|
|
643
|
+
}, SOCKET_PING_TIMEOUT);
|
|
644
|
+
wsServer.on("close", () => {
|
|
645
|
+
if (this.interval) {
|
|
646
|
+
clearInterval(this.interval);
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
encode(data) {
|
|
651
|
+
return Buffer.from((0, import_msgpack2.encode)(data));
|
|
652
|
+
}
|
|
653
|
+
decode(data) {
|
|
654
|
+
return (0, import_msgpack2.decode)(data);
|
|
655
|
+
}
|
|
656
|
+
async request(client, data) {
|
|
657
|
+
try {
|
|
658
|
+
const response = await this.readMessage(client, data);
|
|
659
|
+
if (response) {
|
|
660
|
+
this.send(client, response);
|
|
661
|
+
}
|
|
662
|
+
} catch (error) {
|
|
663
|
+
const err = error;
|
|
664
|
+
this.logger.error(`[LiberionAuth] Request error: ${err.message}`);
|
|
665
|
+
this.errorResponse(client, err.message);
|
|
666
|
+
this.finalizeSession(client.clientId);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
send(client, data) {
|
|
670
|
+
if (client.readyState === import_ws2.default.OPEN) {
|
|
671
|
+
client.send(this.encode(data));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
async readMessage(client, rawData) {
|
|
675
|
+
let data;
|
|
676
|
+
try {
|
|
677
|
+
data = this.decode(rawData);
|
|
678
|
+
} catch (error) {
|
|
679
|
+
return this.errorResponse(client, "Invalid message format");
|
|
680
|
+
}
|
|
681
|
+
const command = data._;
|
|
682
|
+
switch (command) {
|
|
683
|
+
case COMMAND_AUTH_INIT:
|
|
684
|
+
return this.responseInit(client, data);
|
|
685
|
+
case COMMAND_ACTIVATE:
|
|
686
|
+
return this.responseActivate(
|
|
687
|
+
client,
|
|
688
|
+
data.data,
|
|
689
|
+
data._requestId
|
|
690
|
+
);
|
|
691
|
+
case COMMAND_AUTH:
|
|
692
|
+
return this.responseAuth(client, data);
|
|
693
|
+
case COMMAND_AUTH_DECLINED:
|
|
694
|
+
return this.responseDeclined(client, data);
|
|
695
|
+
case COMMAND_HEALTH:
|
|
696
|
+
return { status: STATUS.OK };
|
|
697
|
+
case COMMAND_RECONNECT:
|
|
698
|
+
return this.responseReconnect(client, data);
|
|
699
|
+
default:
|
|
700
|
+
return this.errorResponse(client, `Unknown command: ${command}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
newClient(client) {
|
|
704
|
+
const clientId = (0, import_uuid.v1)();
|
|
705
|
+
const sessionId = (0, import_uuid.v1)();
|
|
706
|
+
this.sessions[clientId] = {
|
|
707
|
+
client,
|
|
708
|
+
sessionId,
|
|
709
|
+
address: null,
|
|
710
|
+
clientSessionId: null,
|
|
711
|
+
isBrowserSession: false
|
|
712
|
+
};
|
|
713
|
+
client.clientId = clientId;
|
|
714
|
+
this.logger.info("[LiberionAuth] New client connected", {
|
|
715
|
+
clientId,
|
|
716
|
+
activeSessions: Object.keys(this.sessions).length
|
|
717
|
+
});
|
|
718
|
+
setTimeout(() => {
|
|
719
|
+
if (this.sessions[clientId]) {
|
|
720
|
+
this.finalizeSession(clientId, true);
|
|
721
|
+
}
|
|
722
|
+
}, AUTHORIZATION_TIME_FRAME);
|
|
723
|
+
}
|
|
724
|
+
handleClose(client, code) {
|
|
725
|
+
const isNormal = code === 1e3 || code === 1001;
|
|
726
|
+
client.isAlive = false;
|
|
727
|
+
const session = this.sessions[client.clientId];
|
|
728
|
+
if (!session) {
|
|
729
|
+
this.logger.info("[LiberionAuth] Socket closed, session already cleaned", {
|
|
730
|
+
clientId: client.clientId,
|
|
731
|
+
code
|
|
732
|
+
});
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const shouldPreserve = session.isBrowserSession && !session.authResult;
|
|
736
|
+
this.logger.info("[LiberionAuth] WebSocket closed", {
|
|
737
|
+
clientId: client.clientId,
|
|
738
|
+
code,
|
|
739
|
+
isNormal,
|
|
740
|
+
shouldPreserve
|
|
741
|
+
});
|
|
742
|
+
if (shouldPreserve) {
|
|
743
|
+
if (!isNormal) {
|
|
744
|
+
this.logger.warn("[LiberionAuth] Browser abnormal close, session preserved", {
|
|
745
|
+
clientId: client.clientId,
|
|
746
|
+
code
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
this.logger.info("[LiberionAuth] Browser session preserved for reconnect", {
|
|
750
|
+
clientId: client.clientId,
|
|
751
|
+
sessionId: session.sessionId
|
|
752
|
+
});
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (!isNormal) {
|
|
756
|
+
this.responseFailed(client, { _: COMMAND_CONNECTION_FAILED });
|
|
757
|
+
}
|
|
758
|
+
delete this.sessions[client.clientId];
|
|
759
|
+
}
|
|
760
|
+
async responseInit(client, data) {
|
|
761
|
+
const session = this.sessions[client.clientId];
|
|
762
|
+
this.logger.info("[LiberionAuth] Browser requesting QR code", {
|
|
763
|
+
clientId: client.clientId,
|
|
764
|
+
sessionId: session.sessionId
|
|
765
|
+
});
|
|
766
|
+
const token = encryptBuffer(
|
|
767
|
+
Buffer.from(session.sessionId),
|
|
768
|
+
this.secretCode
|
|
769
|
+
);
|
|
770
|
+
let trustGateClient = null;
|
|
771
|
+
try {
|
|
772
|
+
this.logger.info("[LiberionAuth] Connecting to Trust Gate Server", {
|
|
773
|
+
url: this.networkConfig.TRUST_GATE_URL
|
|
774
|
+
});
|
|
775
|
+
trustGateClient = new TrustGateClient({
|
|
776
|
+
address: this.networkConfig.TRUST_GATE_URL,
|
|
777
|
+
logger: this.logger
|
|
778
|
+
});
|
|
779
|
+
await trustGateClient.open();
|
|
780
|
+
const result = await trustGateClient.createTask({
|
|
781
|
+
projectId: this.projectId,
|
|
782
|
+
clientKey: token.toString("base64")
|
|
783
|
+
});
|
|
784
|
+
this.logger.info("[LiberionAuth] Task created successfully", {
|
|
785
|
+
linkWeb: result.linkWeb,
|
|
786
|
+
taskId: result.taskId
|
|
787
|
+
});
|
|
788
|
+
session.isBrowserSession = true;
|
|
789
|
+
return {
|
|
790
|
+
_: data._,
|
|
791
|
+
linkWeb: result.linkWeb,
|
|
792
|
+
sessionId: session.sessionId
|
|
793
|
+
};
|
|
794
|
+
} catch (ex) {
|
|
795
|
+
const error = ex;
|
|
796
|
+
this.logger.error("[LiberionAuth] responseInit failed", {
|
|
797
|
+
message: error.message
|
|
798
|
+
});
|
|
799
|
+
let userMessage;
|
|
800
|
+
if (error.message.includes("timeout")) {
|
|
801
|
+
userMessage = "Authorization service timeout. Please try again.";
|
|
802
|
+
} else if (error.message.includes("Failed to connect")) {
|
|
803
|
+
userMessage = "Authorization service unavailable. Please try again later.";
|
|
804
|
+
} else {
|
|
805
|
+
userMessage = "Authorization service error. Please contact support.";
|
|
806
|
+
}
|
|
807
|
+
throw new Error(userMessage);
|
|
808
|
+
} finally {
|
|
809
|
+
trustGateClient?.close();
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
async responseActivate(client, encryptedData, requestId) {
|
|
813
|
+
const decrypted = decryptBuffer(Buffer.from(encryptedData), this.secretCode);
|
|
814
|
+
const { address, sessionId } = this.decode(decrypted);
|
|
815
|
+
const session = this.findSession("sessionId", sessionId);
|
|
816
|
+
if (!session) {
|
|
817
|
+
this.logger.error("[LiberionAuth] Session not found for activation", {
|
|
818
|
+
address: shortenAddress(address),
|
|
819
|
+
sessionId
|
|
820
|
+
});
|
|
821
|
+
return this.errorResponse(client, "Session not found", requestId);
|
|
822
|
+
}
|
|
823
|
+
if (session.address) {
|
|
824
|
+
this.logger.warn("[LiberionAuth] Session already activated", {
|
|
825
|
+
existingAddress: shortenAddress(session.address),
|
|
826
|
+
newAddress: shortenAddress(address)
|
|
827
|
+
});
|
|
828
|
+
return this.errorResponse(client, "Session already activated", requestId);
|
|
829
|
+
}
|
|
830
|
+
this.logger.info("[LiberionAuth] Activating session", {
|
|
831
|
+
address: shortenAddress(address),
|
|
832
|
+
sessionId
|
|
833
|
+
});
|
|
834
|
+
session.address = address;
|
|
835
|
+
session.clientSessionId = (0, import_uuid.v1)();
|
|
836
|
+
const isRegistered = this.onHello ? await this.onHello(address) : false;
|
|
837
|
+
const responseData = encryptBuffer(
|
|
838
|
+
this.encode({ clientSessionId: session.clientSessionId, isRegistered }),
|
|
839
|
+
this.secretCode
|
|
840
|
+
);
|
|
841
|
+
this.finalResponse(client, {
|
|
842
|
+
_: COMMAND_READY,
|
|
843
|
+
data: responseData,
|
|
844
|
+
_requestId: requestId
|
|
845
|
+
});
|
|
846
|
+
const browserClient = session.client;
|
|
847
|
+
if (browserClient?.readyState === import_ws2.default.OPEN) {
|
|
848
|
+
this.send(browserClient, { _: COMMAND_ACTIVATED });
|
|
849
|
+
this.logger.info("[LiberionAuth] ACTIVATED sent to browser", { address: shortenAddress(address) });
|
|
850
|
+
}
|
|
851
|
+
return void 0;
|
|
852
|
+
}
|
|
853
|
+
async responseAuth(client, data) {
|
|
854
|
+
const { address, payload, signature, fields } = data;
|
|
855
|
+
if (!address || !payload || !signature || !fields) {
|
|
856
|
+
return this.errorResponse(client, "Missing required parameters");
|
|
857
|
+
}
|
|
858
|
+
let session = null;
|
|
859
|
+
try {
|
|
860
|
+
const decryptedPayload = decryptBuffer(
|
|
861
|
+
Buffer.from(payload),
|
|
862
|
+
this.secretCode
|
|
863
|
+
);
|
|
864
|
+
const { clientSessionId } = this.decode(decryptedPayload);
|
|
865
|
+
if (!clientSessionId || !(0, import_uuid.validate)(clientSessionId)) {
|
|
866
|
+
throw new Error("Invalid clientSessionId");
|
|
867
|
+
}
|
|
868
|
+
session = this.findSession("clientSessionId", clientSessionId);
|
|
869
|
+
if (!session) {
|
|
870
|
+
return this.errorResponse(client, "Session not found");
|
|
871
|
+
}
|
|
872
|
+
const userToken = await getTokenFromIPFS(address, this.logger, this.networkConfig);
|
|
873
|
+
const crypto2 = initUserCrypto(userToken, this.logger);
|
|
874
|
+
checkSignature(crypto2, payload, signature, this.logger);
|
|
875
|
+
const result = this.onSuccess ? await this.onSuccess({ address, fields }) : { token: void 0 };
|
|
876
|
+
this.logger.info("[LiberionAuth] Auth successful", {
|
|
877
|
+
address: shortenAddress(address),
|
|
878
|
+
hasToken: !!result.token
|
|
879
|
+
});
|
|
880
|
+
this.finalResponse(client, {
|
|
881
|
+
_: result.error ? STATUS.FAILED : COMMAND_AUTH,
|
|
882
|
+
message: result.error || "welcome"
|
|
883
|
+
});
|
|
884
|
+
if (result.token) {
|
|
885
|
+
session.authResult = { token: result.token };
|
|
886
|
+
}
|
|
887
|
+
const browserClient = session.client;
|
|
888
|
+
if (browserClient?.readyState === import_ws2.default.OPEN) {
|
|
889
|
+
this.finalResponse(browserClient, {
|
|
890
|
+
_: result.error ? STATUS.FAILED : COMMAND_AUTH_RESULT,
|
|
891
|
+
message: result.error || "welcome",
|
|
892
|
+
payload: { token: result.token }
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
return void 0;
|
|
896
|
+
} catch (ex) {
|
|
897
|
+
const error = ex;
|
|
898
|
+
this.logger.error(`[LiberionAuth] Auth failed: ${error.message}`);
|
|
899
|
+
if (session) {
|
|
900
|
+
const browserClient = session.client;
|
|
901
|
+
if (browserClient?.readyState === import_ws2.default.OPEN) {
|
|
902
|
+
this.errorResponse(browserClient, error.message);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return this.errorResponse(client, error.message);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
responseDeclined(client, data) {
|
|
909
|
+
const { payload } = data;
|
|
910
|
+
let clientSessionId;
|
|
911
|
+
let browserSession = null;
|
|
912
|
+
if (payload) {
|
|
913
|
+
try {
|
|
914
|
+
const decryptedPayload = decryptBuffer(
|
|
915
|
+
Buffer.from(payload),
|
|
916
|
+
this.secretCode
|
|
917
|
+
);
|
|
918
|
+
const decoded = this.decode(decryptedPayload);
|
|
919
|
+
clientSessionId = decoded.clientSessionId;
|
|
920
|
+
if (clientSessionId && (0, import_uuid.validate)(clientSessionId)) {
|
|
921
|
+
browserSession = this.findSession("clientSessionId", clientSessionId);
|
|
922
|
+
}
|
|
923
|
+
} catch (ex) {
|
|
924
|
+
this.logger.error("[LiberionAuth] Failed to decrypt decline payload", {
|
|
925
|
+
error: ex.message
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (browserSession) {
|
|
930
|
+
this.logger.info("[LiberionAuth] Wallet declined, notifying browser", {
|
|
931
|
+
clientSessionId,
|
|
932
|
+
address: shortenAddress(browserSession.address)
|
|
933
|
+
});
|
|
934
|
+
const browserClient = browserSession.client;
|
|
935
|
+
if (browserClient?.readyState === import_ws2.default.OPEN) {
|
|
936
|
+
this.send(browserClient, {
|
|
937
|
+
_: COMMAND_AUTH_DECLINED,
|
|
938
|
+
message: "Authorization declined"
|
|
939
|
+
});
|
|
940
|
+
} else {
|
|
941
|
+
browserSession.declineResult = { message: "Authorization declined" };
|
|
942
|
+
this.logger.info("[LiberionAuth] Browser offline, decline stored", {
|
|
943
|
+
clientSessionId
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
if (this.onDecline) {
|
|
947
|
+
this.onDecline({
|
|
948
|
+
address: browserSession.address,
|
|
949
|
+
reason: DECLINE_REASON.USER,
|
|
950
|
+
message: "Authorization declined",
|
|
951
|
+
declinedBy: "wallet",
|
|
952
|
+
sessionId: browserSession.sessionId
|
|
953
|
+
}).catch((ex) => {
|
|
954
|
+
this.logger.error(`[LiberionAuth] onDecline error: ${ex.message}`);
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
this.finalResponse(client, {
|
|
958
|
+
_: COMMAND_AUTH_DECLINED,
|
|
959
|
+
message: "Authorization declined"
|
|
960
|
+
});
|
|
961
|
+
return void 0;
|
|
962
|
+
}
|
|
963
|
+
this.logger.error("[LiberionAuth] Browser session not found for decline", {
|
|
964
|
+
clientSessionId,
|
|
965
|
+
hasPayload: !!payload
|
|
966
|
+
});
|
|
967
|
+
return this.responseFailed(client, data);
|
|
968
|
+
}
|
|
969
|
+
responseReconnect(client, data) {
|
|
970
|
+
const sessionId = data.sessionId;
|
|
971
|
+
if (!sessionId) {
|
|
972
|
+
return this.errorResponse(client, "sessionId required");
|
|
973
|
+
}
|
|
974
|
+
const existingSession = this.findSession("sessionId", sessionId);
|
|
975
|
+
if (!existingSession) {
|
|
976
|
+
return this.errorResponse(client, "session_not_found");
|
|
977
|
+
}
|
|
978
|
+
const oldClientId = Object.keys(this.sessions).find(
|
|
979
|
+
(k) => this.sessions[k] === existingSession
|
|
980
|
+
);
|
|
981
|
+
this.logger.info("[LiberionAuth] Reconnecting session", {
|
|
982
|
+
sessionId,
|
|
983
|
+
oldClientId,
|
|
984
|
+
newClientId: client.clientId,
|
|
985
|
+
hasAuthResult: !!existingSession.authResult
|
|
986
|
+
});
|
|
987
|
+
existingSession.client = client;
|
|
988
|
+
if (oldClientId) {
|
|
989
|
+
delete this.sessions[oldClientId];
|
|
990
|
+
}
|
|
991
|
+
this.sessions[client.clientId] = existingSession;
|
|
992
|
+
if (existingSession.authResult) {
|
|
993
|
+
this.send(client, {
|
|
994
|
+
_: COMMAND_AUTH_RESULT,
|
|
995
|
+
message: "welcome",
|
|
996
|
+
payload: existingSession.authResult
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
if (existingSession.declineResult) {
|
|
1000
|
+
this.send(client, {
|
|
1001
|
+
_: COMMAND_AUTH_DECLINED,
|
|
1002
|
+
message: existingSession.declineResult.message
|
|
1003
|
+
});
|
|
1004
|
+
this.logger.info("[LiberionAuth] Sent stored decline", { sessionId });
|
|
1005
|
+
}
|
|
1006
|
+
let status;
|
|
1007
|
+
if (existingSession.authResult) {
|
|
1008
|
+
status = "completed";
|
|
1009
|
+
} else if (existingSession.declineResult) {
|
|
1010
|
+
status = "declined";
|
|
1011
|
+
} else if (existingSession.address) {
|
|
1012
|
+
status = "activated";
|
|
1013
|
+
} else {
|
|
1014
|
+
status = "waiting";
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
_: COMMAND_RECONNECT,
|
|
1018
|
+
status
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
responseFailed(client, data) {
|
|
1022
|
+
const session = this.sessions[client.clientId];
|
|
1023
|
+
if (!session) {
|
|
1024
|
+
return this.errorResponse(client, "Session not found");
|
|
1025
|
+
}
|
|
1026
|
+
const command = data._;
|
|
1027
|
+
const message = data.message || "Authorization declined";
|
|
1028
|
+
let reason;
|
|
1029
|
+
switch (command) {
|
|
1030
|
+
case COMMAND_AUTH_DECLINED:
|
|
1031
|
+
reason = DECLINE_REASON.USER;
|
|
1032
|
+
break;
|
|
1033
|
+
case COMMAND_AUTH_TIMEOUT:
|
|
1034
|
+
reason = DECLINE_REASON.TIMEOUT;
|
|
1035
|
+
break;
|
|
1036
|
+
case COMMAND_CONNECTION_FAILED:
|
|
1037
|
+
case COMMAND_ERROR:
|
|
1038
|
+
reason = DECLINE_REASON.ERROR;
|
|
1039
|
+
break;
|
|
1040
|
+
default:
|
|
1041
|
+
reason = DECLINE_REASON.UNKNOWN;
|
|
1042
|
+
}
|
|
1043
|
+
const isBrowser = session.client === client && session.isBrowserSession;
|
|
1044
|
+
this.logger.info("[LiberionAuth] Authorization declined", {
|
|
1045
|
+
sessionId: session.sessionId,
|
|
1046
|
+
address: shortenAddress(session.address),
|
|
1047
|
+
reason,
|
|
1048
|
+
declinedBy: isBrowser ? "browser" : "wallet"
|
|
1049
|
+
});
|
|
1050
|
+
if (this.onDecline) {
|
|
1051
|
+
this.onDecline({
|
|
1052
|
+
address: session.address,
|
|
1053
|
+
reason,
|
|
1054
|
+
message,
|
|
1055
|
+
declinedBy: isBrowser ? "browser" : "wallet",
|
|
1056
|
+
sessionId: session.sessionId
|
|
1057
|
+
}).catch((ex) => {
|
|
1058
|
+
this.logger.error(`[LiberionAuth] onDecline error: ${ex.message}`);
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
this.finalResponse(client, { _: command, message });
|
|
1062
|
+
return void 0;
|
|
1063
|
+
}
|
|
1064
|
+
errorResponse(client, error, requestId) {
|
|
1065
|
+
this.logger.error("[LiberionAuth] Sending error", {
|
|
1066
|
+
clientId: client.clientId,
|
|
1067
|
+
error
|
|
1068
|
+
});
|
|
1069
|
+
this.finalResponse(client, {
|
|
1070
|
+
_: COMMAND_ERROR,
|
|
1071
|
+
message: error,
|
|
1072
|
+
...requestId && { _requestId: requestId }
|
|
1073
|
+
});
|
|
1074
|
+
return false;
|
|
1075
|
+
}
|
|
1076
|
+
finalResponse(client, data) {
|
|
1077
|
+
if (client.readyState === import_ws2.default.OPEN) {
|
|
1078
|
+
this.send(client, data);
|
|
1079
|
+
}
|
|
1080
|
+
this.closeClient(client);
|
|
1081
|
+
}
|
|
1082
|
+
finalizeSession(clientId, isTimeout = false) {
|
|
1083
|
+
const session = this.sessions[clientId];
|
|
1084
|
+
if (!session) return;
|
|
1085
|
+
if (isTimeout) {
|
|
1086
|
+
this.responseFailed(session.client, {
|
|
1087
|
+
_: COMMAND_AUTH_TIMEOUT,
|
|
1088
|
+
message: "Authorization timeout"
|
|
1089
|
+
});
|
|
1090
|
+
} else {
|
|
1091
|
+
this.closeClient(session.client);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
closeClient(client) {
|
|
1095
|
+
delete this.sessions[client.clientId];
|
|
1096
|
+
client?.terminate();
|
|
1097
|
+
}
|
|
1098
|
+
findSession(paramName, searchValue) {
|
|
1099
|
+
for (const key of Object.keys(this.sessions)) {
|
|
1100
|
+
if (this.sessions[key][paramName] === searchValue) {
|
|
1101
|
+
return this.sessions[key];
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
// src/crypto/pq-crypto.ts
|
|
1109
|
+
var import_ml_kem = require("@noble/post-quantum/ml-kem.js");
|
|
1110
|
+
var import_ml_dsa2 = require("@noble/post-quantum/ml-dsa.js");
|
|
1111
|
+
var import_crypto2 = require("crypto");
|
|
1112
|
+
var import_libsodium_wrappers = __toESM(require("libsodium-wrappers"), 1);
|
|
1113
|
+
var { subtle } = import_crypto2.webcrypto;
|
|
1114
|
+
var PROTOCOL_AAD = new TextEncoder().encode("PQv1");
|
|
1115
|
+
var PQCrypto = class {
|
|
1116
|
+
logger;
|
|
1117
|
+
// Trust Gate keys (generated from seed)
|
|
1118
|
+
// Note: kemPrivateKey kept for potential future decryption support
|
|
1119
|
+
_kemPrivateKey = null;
|
|
1120
|
+
kemPublicKey = null;
|
|
1121
|
+
dsaPrivateKey = null;
|
|
1122
|
+
dsaPublicKey = null;
|
|
1123
|
+
// Peer (User/Wallet) public keys
|
|
1124
|
+
peerKEMPublicKey = null;
|
|
1125
|
+
peerDSAPublicKey = null;
|
|
1126
|
+
constructor(logger) {
|
|
1127
|
+
this.logger = logger ?? new NoOpLogger();
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Generate Trust Gate session keys from cryptographic seed
|
|
1131
|
+
* @param seed - Random seed (at least 96 bytes: 64 for ML-KEM + 32 for ML-DSA)
|
|
1132
|
+
*/
|
|
1133
|
+
async generateKeysFromSeed(seed) {
|
|
1134
|
+
try {
|
|
1135
|
+
if (seed.length < 96) {
|
|
1136
|
+
throw new Error(
|
|
1137
|
+
`Seed too short: expected at least 96 bytes (64 for KEM + 32 for DSA), got ${seed.length}`
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
const kemSeed = seed.slice(0, 64);
|
|
1141
|
+
const kemKeys = import_ml_kem.ml_kem1024.keygen(kemSeed);
|
|
1142
|
+
this.kemPublicKey = kemKeys.publicKey;
|
|
1143
|
+
this._kemPrivateKey = kemKeys.secretKey;
|
|
1144
|
+
const dsaSeed = seed.slice(64, 96);
|
|
1145
|
+
const dsaKeys = import_ml_dsa2.ml_dsa87.keygen(dsaSeed);
|
|
1146
|
+
this.dsaPublicKey = dsaKeys.publicKey;
|
|
1147
|
+
this.dsaPrivateKey = dsaKeys.secretKey;
|
|
1148
|
+
this.logger.info("[PQCrypto] Keys generated successfully", {
|
|
1149
|
+
kemPublicKeySize: this.kemPublicKey.length,
|
|
1150
|
+
dsaPublicKeySize: this.dsaPublicKey.length
|
|
1151
|
+
});
|
|
1152
|
+
} catch (ex) {
|
|
1153
|
+
const error = ex;
|
|
1154
|
+
this.logger.error(`[PQCrypto] Failed to generate keys: ${error.message}`);
|
|
1155
|
+
throw new Error(`Failed to generate PQ keys: ${error.message}`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Import peer's (user) public keys for encryption and verification
|
|
1160
|
+
* @param kemPublicKey - ML-KEM-1024 public key (1568 bytes)
|
|
1161
|
+
* @param dsaPublicKey - ML-DSA-87 public key (2592 bytes)
|
|
1162
|
+
*/
|
|
1163
|
+
importPeerPublicKeys(kemPublicKey, dsaPublicKey) {
|
|
1164
|
+
try {
|
|
1165
|
+
this.peerKEMPublicKey = new Uint8Array(kemPublicKey);
|
|
1166
|
+
this.peerDSAPublicKey = new Uint8Array(dsaPublicKey);
|
|
1167
|
+
if (this.peerKEMPublicKey.length !== 1568) {
|
|
1168
|
+
throw new Error(
|
|
1169
|
+
`Invalid ML-KEM-1024 public key size: expected 1568, got ${this.peerKEMPublicKey.length}`
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
if (this.peerDSAPublicKey.length !== 2592) {
|
|
1173
|
+
throw new Error(
|
|
1174
|
+
`Invalid ML-DSA-87 public key size: expected 2592, got ${this.peerDSAPublicKey.length}`
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
this.logger.info("[PQCrypto] Peer public keys imported", {
|
|
1178
|
+
kemKeySize: this.peerKEMPublicKey.length,
|
|
1179
|
+
dsaKeySize: this.peerDSAPublicKey.length
|
|
1180
|
+
});
|
|
1181
|
+
} catch (ex) {
|
|
1182
|
+
const error = ex;
|
|
1183
|
+
this.logger.error(`[PQCrypto] Failed to import peer keys: ${error.message}`);
|
|
1184
|
+
throw new Error(`Failed to import peer public keys: ${error.message}`);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Hybrid encryption: ML-KEM + XChaCha20-Poly1305 + ML-DSA signature
|
|
1189
|
+
* Matches client format: version + header + sigLen + signature + cipherText + nonce + ct
|
|
1190
|
+
* @param message - Data to encrypt
|
|
1191
|
+
* @returns Encrypted package in client-compatible format
|
|
1192
|
+
*/
|
|
1193
|
+
async encrypt(message) {
|
|
1194
|
+
try {
|
|
1195
|
+
await import_libsodium_wrappers.default.ready;
|
|
1196
|
+
if (!this.peerKEMPublicKey) {
|
|
1197
|
+
throw new Error("Peer KEM public key not imported");
|
|
1198
|
+
}
|
|
1199
|
+
if (!this.dsaPrivateKey) {
|
|
1200
|
+
throw new Error("DSA private key not generated");
|
|
1201
|
+
}
|
|
1202
|
+
const messageBytes = message instanceof Uint8Array ? message : new Uint8Array(message);
|
|
1203
|
+
this.logger.info("[PQCrypto] Starting hybrid encryption", {
|
|
1204
|
+
messageSize: messageBytes.length
|
|
1205
|
+
});
|
|
1206
|
+
const { cipherText: kemCiphertext, sharedSecret } = import_ml_kem.ml_kem1024.encapsulate(
|
|
1207
|
+
this.peerKEMPublicKey
|
|
1208
|
+
);
|
|
1209
|
+
this.logger.info("[PQCrypto] ML-KEM encapsulation complete", {
|
|
1210
|
+
ciphertextSize: kemCiphertext.length,
|
|
1211
|
+
// 1568 bytes
|
|
1212
|
+
sharedSecretSize: sharedSecret.length
|
|
1213
|
+
// 32 bytes
|
|
1214
|
+
});
|
|
1215
|
+
const sharedSecretBuffer = Uint8Array.from(sharedSecret);
|
|
1216
|
+
const secretKeyRaw = await subtle.deriveBits(
|
|
1217
|
+
{
|
|
1218
|
+
name: "HKDF",
|
|
1219
|
+
hash: "SHA-256",
|
|
1220
|
+
salt: PROTOCOL_AAD,
|
|
1221
|
+
info: PROTOCOL_AAD
|
|
1222
|
+
},
|
|
1223
|
+
await subtle.importKey("raw", sharedSecretBuffer, { name: "HKDF" }, false, [
|
|
1224
|
+
"deriveBits"
|
|
1225
|
+
]),
|
|
1226
|
+
256
|
|
1227
|
+
);
|
|
1228
|
+
sharedSecret.fill(0);
|
|
1229
|
+
sharedSecretBuffer.fill(0);
|
|
1230
|
+
const versionBuf = new Uint8Array([1]);
|
|
1231
|
+
const header = new Uint8Array(4);
|
|
1232
|
+
new DataView(header.buffer).setUint32(0, kemCiphertext.length, false);
|
|
1233
|
+
const aad = new Uint8Array(PROTOCOL_AAD.length + 1 + 4);
|
|
1234
|
+
aad.set(PROTOCOL_AAD, 0);
|
|
1235
|
+
aad.set(versionBuf, PROTOCOL_AAD.length);
|
|
1236
|
+
aad.set(header, PROTOCOL_AAD.length + 1);
|
|
1237
|
+
const keyBytes = new Uint8Array(secretKeyRaw);
|
|
1238
|
+
const nonce = import_crypto2.webcrypto.getRandomValues(
|
|
1239
|
+
new Uint8Array(import_libsodium_wrappers.default.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)
|
|
1240
|
+
);
|
|
1241
|
+
const ct = import_libsodium_wrappers.default.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
|
1242
|
+
messageBytes,
|
|
1243
|
+
aad,
|
|
1244
|
+
null,
|
|
1245
|
+
nonce,
|
|
1246
|
+
keyBytes
|
|
1247
|
+
);
|
|
1248
|
+
this.logger.info("[PQCrypto] XChaCha20-Poly1305 encryption complete", {
|
|
1249
|
+
nonceSize: nonce.length,
|
|
1250
|
+
// 24 bytes
|
|
1251
|
+
encryptedSize: ct.length
|
|
1252
|
+
// message + 16 bytes tag
|
|
1253
|
+
});
|
|
1254
|
+
const signature = import_ml_dsa2.ml_dsa87.sign(kemCiphertext, this.dsaPrivateKey);
|
|
1255
|
+
this.logger.info("[PQCrypto] ML-DSA signature created", {
|
|
1256
|
+
signatureSize: signature.length
|
|
1257
|
+
// ~4627 bytes
|
|
1258
|
+
});
|
|
1259
|
+
const sigLenBuf = new Uint8Array(4);
|
|
1260
|
+
new DataView(sigLenBuf.buffer).setUint32(0, signature.length, false);
|
|
1261
|
+
const result = new Uint8Array(
|
|
1262
|
+
1 + 4 + 4 + signature.length + kemCiphertext.length + nonce.length + ct.length
|
|
1263
|
+
);
|
|
1264
|
+
let offset = 0;
|
|
1265
|
+
result.set(versionBuf, offset);
|
|
1266
|
+
offset += 1;
|
|
1267
|
+
result.set(header, offset);
|
|
1268
|
+
offset += 4;
|
|
1269
|
+
result.set(sigLenBuf, offset);
|
|
1270
|
+
offset += 4;
|
|
1271
|
+
result.set(signature, offset);
|
|
1272
|
+
offset += signature.length;
|
|
1273
|
+
result.set(kemCiphertext, offset);
|
|
1274
|
+
offset += kemCiphertext.length;
|
|
1275
|
+
result.set(nonce, offset);
|
|
1276
|
+
offset += nonce.length;
|
|
1277
|
+
result.set(ct, offset);
|
|
1278
|
+
keyBytes.fill(0);
|
|
1279
|
+
new Uint8Array(secretKeyRaw).fill(0);
|
|
1280
|
+
this.logger.info("[PQCrypto] Hybrid encryption complete", {
|
|
1281
|
+
totalSize: result.length,
|
|
1282
|
+
breakdown: {
|
|
1283
|
+
version: 1,
|
|
1284
|
+
header: 4,
|
|
1285
|
+
sigLen: 4,
|
|
1286
|
+
signature: signature.length,
|
|
1287
|
+
kemCiphertext: kemCiphertext.length,
|
|
1288
|
+
nonce: nonce.length,
|
|
1289
|
+
ct: ct.length
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
return Buffer.from(result);
|
|
1293
|
+
} catch (ex) {
|
|
1294
|
+
const error = ex;
|
|
1295
|
+
this.logger.error(`[PQCrypto] Encryption failed: ${error.message}`);
|
|
1296
|
+
throw new Error(`PQ encryption failed: ${error.message}`);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Check if keys have been generated
|
|
1301
|
+
*/
|
|
1302
|
+
hasKeys() {
|
|
1303
|
+
return !!(this.kemPublicKey && this.dsaPublicKey && this._kemPrivateKey);
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Export Trust Gate public keys (for sending to client)
|
|
1307
|
+
* @returns Object with publicKeyEncrypt and publicKeySign as Buffers
|
|
1308
|
+
*/
|
|
1309
|
+
exportKeys() {
|
|
1310
|
+
if (!this.kemPublicKey || !this.dsaPublicKey) {
|
|
1311
|
+
throw new Error("Keys not generated yet");
|
|
1312
|
+
}
|
|
1313
|
+
return {
|
|
1314
|
+
publicKeyEncrypt: Buffer.from(this.kemPublicKey),
|
|
1315
|
+
publicKeySign: Buffer.from(this.dsaPublicKey)
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1320
|
+
0 && (module.exports = {
|
|
1321
|
+
COMMAND_ACTIVATED,
|
|
1322
|
+
COMMAND_AUTH,
|
|
1323
|
+
COMMAND_AUTH_DECLINED,
|
|
1324
|
+
COMMAND_AUTH_RESULT,
|
|
1325
|
+
COMMAND_AUTH_TIMEOUT,
|
|
1326
|
+
COMMAND_ERROR,
|
|
1327
|
+
COMMAND_READY,
|
|
1328
|
+
ConsoleLogger,
|
|
1329
|
+
DECLINE_REASON,
|
|
1330
|
+
DEFAULT_PORT,
|
|
1331
|
+
LiberionAuth,
|
|
1332
|
+
NoOpLogger,
|
|
1333
|
+
PQCrypto,
|
|
1334
|
+
STATUS,
|
|
1335
|
+
USER_CONTRACT_ABI,
|
|
1336
|
+
checkSignature,
|
|
1337
|
+
clearTokenCache,
|
|
1338
|
+
createWinstonAdapter,
|
|
1339
|
+
decryptBuffer,
|
|
1340
|
+
encryptBuffer,
|
|
1341
|
+
extractIpfsHash,
|
|
1342
|
+
getNetworkConfig,
|
|
1343
|
+
getTokenFromIPFS,
|
|
1344
|
+
initUserCrypto,
|
|
1345
|
+
shortenAddress
|
|
1346
|
+
});
|