@cryptforge/key-exchange 0.1.0 → 0.2.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 +55 -0
- package/dist/electron-main.d.mts +1 -1
- package/dist/electron-main.d.ts +1 -1
- package/dist/electron-main.js +21 -38
- package/dist/electron-main.mjs +21 -38
- package/dist/electron-preload.js +1 -1
- package/dist/electron-preload.mjs +1 -1
- package/dist/electron-renderer.d.mts +2 -2
- package/dist/electron-renderer.d.ts +2 -2
- package/dist/electron-renderer.js +2 -2
- package/dist/electron-renderer.mjs +2 -2
- package/dist/index.d.mts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +95 -2
- package/dist/index.mjs +94 -2
- package/dist/server.d.mts +45 -1
- package/dist/server.d.ts +45 -1
- package/dist/server.js +111 -35
- package/dist/server.mjs +110 -35
- package/dist/vite.d.mts +23 -0
- package/dist/vite.d.ts +23 -0
- package/dist/vite.js +76 -0
- package/dist/vite.mjs +51 -0
- package/package.json +9 -3
package/dist/index.mjs
CHANGED
|
@@ -495,11 +495,11 @@ var KeyTransportClient = class {
|
|
|
495
495
|
throw error;
|
|
496
496
|
}
|
|
497
497
|
};
|
|
498
|
-
broadcastClientState = async (id, state) => {
|
|
498
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
499
499
|
console.log("KeyTransportClient.broadcastClientState");
|
|
500
500
|
this.peers.set(id, state);
|
|
501
501
|
try {
|
|
502
|
-
await this.sendRequest(MESSAGES.broadcastClientState, { id, state });
|
|
502
|
+
await this.sendRequest(MESSAGES.broadcastClientState, { id, state, name, isHeartbeat });
|
|
503
503
|
} catch (error) {
|
|
504
504
|
console.error("Failed to broadcast client state:", error);
|
|
505
505
|
throw error;
|
|
@@ -567,6 +567,98 @@ var KeyTransportClient = class {
|
|
|
567
567
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
568
568
|
};
|
|
569
569
|
};
|
|
570
|
+
|
|
571
|
+
// src/devicePairing.ts
|
|
572
|
+
var DevicePairingManager = class {
|
|
573
|
+
storageKey;
|
|
574
|
+
constructor(identityId) {
|
|
575
|
+
this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Get all linked devices for this app
|
|
579
|
+
*/
|
|
580
|
+
getLinkedDevices = () => {
|
|
581
|
+
try {
|
|
582
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
583
|
+
return stored ? JSON.parse(stored) : [];
|
|
584
|
+
} catch (error) {
|
|
585
|
+
console.error("Failed to load linked devices:", error);
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
/**
|
|
590
|
+
* Add a device to the linked devices list
|
|
591
|
+
* Called after successful key exchange
|
|
592
|
+
*/
|
|
593
|
+
addLinkedDevice = (device) => {
|
|
594
|
+
try {
|
|
595
|
+
const devices = this.getLinkedDevices();
|
|
596
|
+
const existing = devices.find((d) => d.id === device.id);
|
|
597
|
+
if (existing) {
|
|
598
|
+
existing.name = device.name;
|
|
599
|
+
} else {
|
|
600
|
+
devices.push({
|
|
601
|
+
id: device.id,
|
|
602
|
+
name: device.name,
|
|
603
|
+
linkedAt: Date.now()
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
607
|
+
} catch (error) {
|
|
608
|
+
console.error("Failed to add linked device:", error);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* Remove a device from the linked devices list
|
|
613
|
+
* For future use when user wants to unlink a device
|
|
614
|
+
*/
|
|
615
|
+
removeLinkedDevice = (id) => {
|
|
616
|
+
try {
|
|
617
|
+
const devices = this.getLinkedDevices().filter((d) => d.id !== id);
|
|
618
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
619
|
+
console.log(`Removed linked device: ${id}`);
|
|
620
|
+
} catch (error) {
|
|
621
|
+
console.error("Failed to remove linked device:", error);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
/**
|
|
625
|
+
* Update the hostname of a device (system-level name)
|
|
626
|
+
*/
|
|
627
|
+
updateDeviceName = (id, name) => {
|
|
628
|
+
try {
|
|
629
|
+
const devices = this.getLinkedDevices();
|
|
630
|
+
const device = devices.find((d) => d.id === id);
|
|
631
|
+
if (device) {
|
|
632
|
+
device.name = name;
|
|
633
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
634
|
+
}
|
|
635
|
+
} catch (error) {
|
|
636
|
+
console.error("Failed to update device name:", error);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
/**
|
|
640
|
+
* Set a custom user-defined name for a device
|
|
641
|
+
*/
|
|
642
|
+
setCustomName = (id, customName) => {
|
|
643
|
+
try {
|
|
644
|
+
const devices = this.getLinkedDevices();
|
|
645
|
+
const device = devices.find((d) => d.id === id);
|
|
646
|
+
if (device) {
|
|
647
|
+
device.customName = customName.trim() || void 0;
|
|
648
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
649
|
+
}
|
|
650
|
+
} catch (error) {
|
|
651
|
+
console.error("Failed to set custom device name:", error);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
/**
|
|
655
|
+
* Check if a device is linked
|
|
656
|
+
*/
|
|
657
|
+
isLinked = (id) => {
|
|
658
|
+
return this.getLinkedDevices().some((d) => d.id === id);
|
|
659
|
+
};
|
|
660
|
+
};
|
|
570
661
|
export {
|
|
662
|
+
DevicePairingManager,
|
|
571
663
|
KeyTransportClient
|
|
572
664
|
};
|
package/dist/server.d.mts
CHANGED
|
@@ -43,4 +43,48 @@ declare class KeyTransportServer {
|
|
|
43
43
|
getPort: () => number;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Manages linked devices (devices that have completed key exchange)
|
|
48
|
+
* Stores device info in localStorage scoped per app
|
|
49
|
+
*/
|
|
50
|
+
interface LinkedDevice {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
customName?: string;
|
|
54
|
+
linkedAt: number;
|
|
55
|
+
}
|
|
56
|
+
declare class DevicePairingManager {
|
|
57
|
+
private storageKey;
|
|
58
|
+
constructor(identityId: string);
|
|
59
|
+
/**
|
|
60
|
+
* Get all linked devices for this app
|
|
61
|
+
*/
|
|
62
|
+
getLinkedDevices: () => LinkedDevice[];
|
|
63
|
+
/**
|
|
64
|
+
* Add a device to the linked devices list
|
|
65
|
+
* Called after successful key exchange
|
|
66
|
+
*/
|
|
67
|
+
addLinkedDevice: (device: {
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
}) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Remove a device from the linked devices list
|
|
73
|
+
* For future use when user wants to unlink a device
|
|
74
|
+
*/
|
|
75
|
+
removeLinkedDevice: (id: string) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Update the hostname of a device (system-level name)
|
|
78
|
+
*/
|
|
79
|
+
updateDeviceName: (id: string, name: string) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Set a custom user-defined name for a device
|
|
82
|
+
*/
|
|
83
|
+
setCustomName: (id: string, customName: string) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Check if a device is linked
|
|
86
|
+
*/
|
|
87
|
+
isLinked: (id: string) => boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { DevicePairingManager, KeyTransportServer, type LinkedDevice, useKeyExchangeServer };
|
package/dist/server.d.ts
CHANGED
|
@@ -43,4 +43,48 @@ declare class KeyTransportServer {
|
|
|
43
43
|
getPort: () => number;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Manages linked devices (devices that have completed key exchange)
|
|
48
|
+
* Stores device info in localStorage scoped per app
|
|
49
|
+
*/
|
|
50
|
+
interface LinkedDevice {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
customName?: string;
|
|
54
|
+
linkedAt: number;
|
|
55
|
+
}
|
|
56
|
+
declare class DevicePairingManager {
|
|
57
|
+
private storageKey;
|
|
58
|
+
constructor(identityId: string);
|
|
59
|
+
/**
|
|
60
|
+
* Get all linked devices for this app
|
|
61
|
+
*/
|
|
62
|
+
getLinkedDevices: () => LinkedDevice[];
|
|
63
|
+
/**
|
|
64
|
+
* Add a device to the linked devices list
|
|
65
|
+
* Called after successful key exchange
|
|
66
|
+
*/
|
|
67
|
+
addLinkedDevice: (device: {
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
}) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Remove a device from the linked devices list
|
|
73
|
+
* For future use when user wants to unlink a device
|
|
74
|
+
*/
|
|
75
|
+
removeLinkedDevice: (id: string) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Update the hostname of a device (system-level name)
|
|
78
|
+
*/
|
|
79
|
+
updateDeviceName: (id: string, name: string) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Set a custom user-defined name for a device
|
|
82
|
+
*/
|
|
83
|
+
setCustomName: (id: string, customName: string) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Check if a device is linked
|
|
86
|
+
*/
|
|
87
|
+
isLinked: (id: string) => boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { DevicePairingManager, KeyTransportServer, type LinkedDevice, useKeyExchangeServer };
|
package/dist/server.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/server.ts
|
|
31
31
|
var server_exports = {};
|
|
32
32
|
__export(server_exports, {
|
|
33
|
+
DevicePairingManager: () => DevicePairingManager,
|
|
33
34
|
KeyTransportServer: () => KeyTransportServer,
|
|
34
35
|
useKeyExchangeServer: () => useKeyExchangeServer
|
|
35
36
|
});
|
|
@@ -275,7 +276,7 @@ function useKeyExchangeServer(onEvent) {
|
|
|
275
276
|
});
|
|
276
277
|
};
|
|
277
278
|
const completeSetupSuccess = async () => {
|
|
278
|
-
console.log("sending
|
|
279
|
+
console.log("sending completion message to client");
|
|
279
280
|
sendResponse({
|
|
280
281
|
to: [client],
|
|
281
282
|
header: "Setup Succeeded",
|
|
@@ -329,16 +330,9 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
329
330
|
const swarm = new import_hyperswarm.default();
|
|
330
331
|
swarm.on("connection", (connection) => {
|
|
331
332
|
const name = import_b4a3.default.toString(connection.remotePublicKey, "hex");
|
|
332
|
-
console.log("Presence: * got a connection from:", name, "*");
|
|
333
333
|
connections.push(connection);
|
|
334
334
|
sendStateRequestMessage(connection);
|
|
335
335
|
connection.once("close", () => {
|
|
336
|
-
console.log(
|
|
337
|
-
`Presence: Connection closed. Removing connection ${import_b4a3.default.toString(
|
|
338
|
-
connection.remotePublicKey,
|
|
339
|
-
"hex"
|
|
340
|
-
)}`
|
|
341
|
-
);
|
|
342
336
|
connections.splice(connections.indexOf(connection), 1);
|
|
343
337
|
const id = deviceIDs.get(import_b4a3.default.toString(connection.remotePublicKey, "hex"));
|
|
344
338
|
if (id) {
|
|
@@ -351,17 +345,18 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
351
345
|
try {
|
|
352
346
|
parsedData = JSON.parse(data);
|
|
353
347
|
} catch (error) {
|
|
354
|
-
console.error("Error parsing data:", error);
|
|
348
|
+
console.error("Error parsing presence data:", error);
|
|
355
349
|
return;
|
|
356
350
|
}
|
|
357
351
|
const header = parsedData;
|
|
358
|
-
console.log(
|
|
359
|
-
"Presence: got data for ",
|
|
360
|
-
connection.publicKey.toString("hex")
|
|
361
|
-
);
|
|
362
352
|
if (header.type === "update") {
|
|
363
353
|
const payload = parsedData;
|
|
364
|
-
onUpdate({
|
|
354
|
+
onUpdate({
|
|
355
|
+
id: payload.id,
|
|
356
|
+
state: payload.state,
|
|
357
|
+
name: payload.name,
|
|
358
|
+
isHeartbeat: payload.isHeartbeat
|
|
359
|
+
});
|
|
365
360
|
deviceIDs.set(
|
|
366
361
|
import_b4a3.default.toString(connection.remotePublicKey, "hex"),
|
|
367
362
|
payload.id
|
|
@@ -381,46 +376,35 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
381
376
|
});
|
|
382
377
|
const connections = [];
|
|
383
378
|
const connect = async (topic, id) => {
|
|
384
|
-
console.log("Presence: connecting to topic: ", topic);
|
|
385
379
|
const key = import_b4a3.default.from(topic, "hex");
|
|
386
|
-
console.log("key: ", key);
|
|
387
380
|
const discovery = swarm.join(key, { client: true, server: true });
|
|
388
|
-
console.log("got discovery: ");
|
|
389
381
|
const publicKey = import_b4a3.default.toString(
|
|
390
382
|
discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
|
|
391
383
|
"hex"
|
|
392
384
|
);
|
|
393
|
-
console.log("Presence: public key is ", publicKey);
|
|
394
385
|
deviceIDs.set(publicKey, id);
|
|
395
|
-
discovery.flushed()
|
|
396
|
-
console.log("Presence: joined topic:", import_b4a3.default.toString(key, "hex"));
|
|
397
|
-
});
|
|
386
|
+
await discovery.flushed();
|
|
398
387
|
};
|
|
399
388
|
const sendStateRequestMessage = async (connection) => {
|
|
400
389
|
const message = {
|
|
401
390
|
type: "request"
|
|
402
391
|
};
|
|
403
392
|
const payload = JSON.stringify(message);
|
|
404
|
-
console.log(
|
|
405
|
-
"sending state request message to: ",
|
|
406
|
-
connection.publicKey.toString("hex")
|
|
407
|
-
);
|
|
408
393
|
connection.write(payload);
|
|
409
394
|
};
|
|
410
|
-
const receiveStatusMessage = async (id, state) => {
|
|
411
|
-
return broadcastStatusMessage(id, state);
|
|
395
|
+
const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
|
|
396
|
+
return broadcastStatusMessage(id, state, name, isHeartbeat);
|
|
412
397
|
};
|
|
413
|
-
const broadcastStatusMessage = (id, state) => {
|
|
414
|
-
console.log(`server got connection state message for ${id}: `, state);
|
|
398
|
+
const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
|
|
415
399
|
const message = {
|
|
416
400
|
type: "update",
|
|
417
401
|
id,
|
|
418
|
-
state
|
|
402
|
+
state,
|
|
403
|
+
name,
|
|
404
|
+
isHeartbeat
|
|
419
405
|
};
|
|
420
|
-
console.log("active connections: ", connections.length);
|
|
421
406
|
const payload = JSON.stringify(message);
|
|
422
407
|
for (const connection of connections) {
|
|
423
|
-
console.log("sending message to: ", connection.publicKey.toString("hex"));
|
|
424
408
|
connection.write(payload);
|
|
425
409
|
}
|
|
426
410
|
onUpdate(message);
|
|
@@ -688,8 +672,8 @@ var CoreTransportLogic = class {
|
|
|
688
672
|
await this.presence.connect(topicHash, deviceInfo.id);
|
|
689
673
|
this.presenceConnected = true;
|
|
690
674
|
}
|
|
691
|
-
broadcastClientState(id, state) {
|
|
692
|
-
this.presence.receiveStatusMessage(id, state);
|
|
675
|
+
broadcastClientState(id, state, name, isHeartbeat) {
|
|
676
|
+
this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
|
|
693
677
|
}
|
|
694
678
|
};
|
|
695
679
|
|
|
@@ -892,7 +876,7 @@ var KeyTransportServer = class {
|
|
|
892
876
|
case MESSAGES.broadcastClientState:
|
|
893
877
|
this.logger?.log("\u{1F4E1} Broadcasting client state...");
|
|
894
878
|
try {
|
|
895
|
-
this.core.broadcastClientState(requestData.id, requestData.state);
|
|
879
|
+
this.core.broadcastClientState(requestData.id, requestData.state, requestData.isHeartbeat);
|
|
896
880
|
this.sendResponse(ws, type, requestId, { success: true });
|
|
897
881
|
} catch (error) {
|
|
898
882
|
this.sendResponse(ws, type, requestId, null, {
|
|
@@ -933,8 +917,100 @@ var KeyTransportServer = class {
|
|
|
933
917
|
return this.port;
|
|
934
918
|
};
|
|
935
919
|
};
|
|
920
|
+
|
|
921
|
+
// src/devicePairing.ts
|
|
922
|
+
var DevicePairingManager = class {
|
|
923
|
+
storageKey;
|
|
924
|
+
constructor(identityId) {
|
|
925
|
+
this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Get all linked devices for this app
|
|
929
|
+
*/
|
|
930
|
+
getLinkedDevices = () => {
|
|
931
|
+
try {
|
|
932
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
933
|
+
return stored ? JSON.parse(stored) : [];
|
|
934
|
+
} catch (error) {
|
|
935
|
+
console.error("Failed to load linked devices:", error);
|
|
936
|
+
return [];
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
/**
|
|
940
|
+
* Add a device to the linked devices list
|
|
941
|
+
* Called after successful key exchange
|
|
942
|
+
*/
|
|
943
|
+
addLinkedDevice = (device) => {
|
|
944
|
+
try {
|
|
945
|
+
const devices = this.getLinkedDevices();
|
|
946
|
+
const existing = devices.find((d) => d.id === device.id);
|
|
947
|
+
if (existing) {
|
|
948
|
+
existing.name = device.name;
|
|
949
|
+
} else {
|
|
950
|
+
devices.push({
|
|
951
|
+
id: device.id,
|
|
952
|
+
name: device.name,
|
|
953
|
+
linkedAt: Date.now()
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
957
|
+
} catch (error) {
|
|
958
|
+
console.error("Failed to add linked device:", error);
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
/**
|
|
962
|
+
* Remove a device from the linked devices list
|
|
963
|
+
* For future use when user wants to unlink a device
|
|
964
|
+
*/
|
|
965
|
+
removeLinkedDevice = (id) => {
|
|
966
|
+
try {
|
|
967
|
+
const devices = this.getLinkedDevices().filter((d) => d.id !== id);
|
|
968
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
969
|
+
console.log(`Removed linked device: ${id}`);
|
|
970
|
+
} catch (error) {
|
|
971
|
+
console.error("Failed to remove linked device:", error);
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
/**
|
|
975
|
+
* Update the hostname of a device (system-level name)
|
|
976
|
+
*/
|
|
977
|
+
updateDeviceName = (id, name) => {
|
|
978
|
+
try {
|
|
979
|
+
const devices = this.getLinkedDevices();
|
|
980
|
+
const device = devices.find((d) => d.id === id);
|
|
981
|
+
if (device) {
|
|
982
|
+
device.name = name;
|
|
983
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
984
|
+
}
|
|
985
|
+
} catch (error) {
|
|
986
|
+
console.error("Failed to update device name:", error);
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
/**
|
|
990
|
+
* Set a custom user-defined name for a device
|
|
991
|
+
*/
|
|
992
|
+
setCustomName = (id, customName) => {
|
|
993
|
+
try {
|
|
994
|
+
const devices = this.getLinkedDevices();
|
|
995
|
+
const device = devices.find((d) => d.id === id);
|
|
996
|
+
if (device) {
|
|
997
|
+
device.customName = customName.trim() || void 0;
|
|
998
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
999
|
+
}
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
console.error("Failed to set custom device name:", error);
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
/**
|
|
1005
|
+
* Check if a device is linked
|
|
1006
|
+
*/
|
|
1007
|
+
isLinked = (id) => {
|
|
1008
|
+
return this.getLinkedDevices().some((d) => d.id === id);
|
|
1009
|
+
};
|
|
1010
|
+
};
|
|
936
1011
|
// Annotate the CommonJS export names for ESM import in node:
|
|
937
1012
|
0 && (module.exports = {
|
|
1013
|
+
DevicePairingManager,
|
|
938
1014
|
KeyTransportServer,
|
|
939
1015
|
useKeyExchangeServer
|
|
940
1016
|
});
|
package/dist/server.mjs
CHANGED
|
@@ -238,7 +238,7 @@ function useKeyExchangeServer(onEvent) {
|
|
|
238
238
|
});
|
|
239
239
|
};
|
|
240
240
|
const completeSetupSuccess = async () => {
|
|
241
|
-
console.log("sending
|
|
241
|
+
console.log("sending completion message to client");
|
|
242
242
|
sendResponse({
|
|
243
243
|
to: [client],
|
|
244
244
|
header: "Setup Succeeded",
|
|
@@ -292,16 +292,9 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
292
292
|
const swarm = new Hyperswarm();
|
|
293
293
|
swarm.on("connection", (connection) => {
|
|
294
294
|
const name = b4a3.toString(connection.remotePublicKey, "hex");
|
|
295
|
-
console.log("Presence: * got a connection from:", name, "*");
|
|
296
295
|
connections.push(connection);
|
|
297
296
|
sendStateRequestMessage(connection);
|
|
298
297
|
connection.once("close", () => {
|
|
299
|
-
console.log(
|
|
300
|
-
`Presence: Connection closed. Removing connection ${b4a3.toString(
|
|
301
|
-
connection.remotePublicKey,
|
|
302
|
-
"hex"
|
|
303
|
-
)}`
|
|
304
|
-
);
|
|
305
298
|
connections.splice(connections.indexOf(connection), 1);
|
|
306
299
|
const id = deviceIDs.get(b4a3.toString(connection.remotePublicKey, "hex"));
|
|
307
300
|
if (id) {
|
|
@@ -314,17 +307,18 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
314
307
|
try {
|
|
315
308
|
parsedData = JSON.parse(data);
|
|
316
309
|
} catch (error) {
|
|
317
|
-
console.error("Error parsing data:", error);
|
|
310
|
+
console.error("Error parsing presence data:", error);
|
|
318
311
|
return;
|
|
319
312
|
}
|
|
320
313
|
const header = parsedData;
|
|
321
|
-
console.log(
|
|
322
|
-
"Presence: got data for ",
|
|
323
|
-
connection.publicKey.toString("hex")
|
|
324
|
-
);
|
|
325
314
|
if (header.type === "update") {
|
|
326
315
|
const payload = parsedData;
|
|
327
|
-
onUpdate({
|
|
316
|
+
onUpdate({
|
|
317
|
+
id: payload.id,
|
|
318
|
+
state: payload.state,
|
|
319
|
+
name: payload.name,
|
|
320
|
+
isHeartbeat: payload.isHeartbeat
|
|
321
|
+
});
|
|
328
322
|
deviceIDs.set(
|
|
329
323
|
b4a3.toString(connection.remotePublicKey, "hex"),
|
|
330
324
|
payload.id
|
|
@@ -344,46 +338,35 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
344
338
|
});
|
|
345
339
|
const connections = [];
|
|
346
340
|
const connect = async (topic, id) => {
|
|
347
|
-
console.log("Presence: connecting to topic: ", topic);
|
|
348
341
|
const key = b4a3.from(topic, "hex");
|
|
349
|
-
console.log("key: ", key);
|
|
350
342
|
const discovery = swarm.join(key, { client: true, server: true });
|
|
351
|
-
console.log("got discovery: ");
|
|
352
343
|
const publicKey = b4a3.toString(
|
|
353
344
|
discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
|
|
354
345
|
"hex"
|
|
355
346
|
);
|
|
356
|
-
console.log("Presence: public key is ", publicKey);
|
|
357
347
|
deviceIDs.set(publicKey, id);
|
|
358
|
-
discovery.flushed()
|
|
359
|
-
console.log("Presence: joined topic:", b4a3.toString(key, "hex"));
|
|
360
|
-
});
|
|
348
|
+
await discovery.flushed();
|
|
361
349
|
};
|
|
362
350
|
const sendStateRequestMessage = async (connection) => {
|
|
363
351
|
const message = {
|
|
364
352
|
type: "request"
|
|
365
353
|
};
|
|
366
354
|
const payload = JSON.stringify(message);
|
|
367
|
-
console.log(
|
|
368
|
-
"sending state request message to: ",
|
|
369
|
-
connection.publicKey.toString("hex")
|
|
370
|
-
);
|
|
371
355
|
connection.write(payload);
|
|
372
356
|
};
|
|
373
|
-
const receiveStatusMessage = async (id, state) => {
|
|
374
|
-
return broadcastStatusMessage(id, state);
|
|
357
|
+
const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
|
|
358
|
+
return broadcastStatusMessage(id, state, name, isHeartbeat);
|
|
375
359
|
};
|
|
376
|
-
const broadcastStatusMessage = (id, state) => {
|
|
377
|
-
console.log(`server got connection state message for ${id}: `, state);
|
|
360
|
+
const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
|
|
378
361
|
const message = {
|
|
379
362
|
type: "update",
|
|
380
363
|
id,
|
|
381
|
-
state
|
|
364
|
+
state,
|
|
365
|
+
name,
|
|
366
|
+
isHeartbeat
|
|
382
367
|
};
|
|
383
|
-
console.log("active connections: ", connections.length);
|
|
384
368
|
const payload = JSON.stringify(message);
|
|
385
369
|
for (const connection of connections) {
|
|
386
|
-
console.log("sending message to: ", connection.publicKey.toString("hex"));
|
|
387
370
|
connection.write(payload);
|
|
388
371
|
}
|
|
389
372
|
onUpdate(message);
|
|
@@ -651,8 +634,8 @@ var CoreTransportLogic = class {
|
|
|
651
634
|
await this.presence.connect(topicHash, deviceInfo.id);
|
|
652
635
|
this.presenceConnected = true;
|
|
653
636
|
}
|
|
654
|
-
broadcastClientState(id, state) {
|
|
655
|
-
this.presence.receiveStatusMessage(id, state);
|
|
637
|
+
broadcastClientState(id, state, name, isHeartbeat) {
|
|
638
|
+
this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
|
|
656
639
|
}
|
|
657
640
|
};
|
|
658
641
|
|
|
@@ -855,7 +838,7 @@ var KeyTransportServer = class {
|
|
|
855
838
|
case MESSAGES.broadcastClientState:
|
|
856
839
|
this.logger?.log("\u{1F4E1} Broadcasting client state...");
|
|
857
840
|
try {
|
|
858
|
-
this.core.broadcastClientState(requestData.id, requestData.state);
|
|
841
|
+
this.core.broadcastClientState(requestData.id, requestData.state, requestData.isHeartbeat);
|
|
859
842
|
this.sendResponse(ws, type, requestId, { success: true });
|
|
860
843
|
} catch (error) {
|
|
861
844
|
this.sendResponse(ws, type, requestId, null, {
|
|
@@ -896,7 +879,99 @@ var KeyTransportServer = class {
|
|
|
896
879
|
return this.port;
|
|
897
880
|
};
|
|
898
881
|
};
|
|
882
|
+
|
|
883
|
+
// src/devicePairing.ts
|
|
884
|
+
var DevicePairingManager = class {
|
|
885
|
+
storageKey;
|
|
886
|
+
constructor(identityId) {
|
|
887
|
+
this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Get all linked devices for this app
|
|
891
|
+
*/
|
|
892
|
+
getLinkedDevices = () => {
|
|
893
|
+
try {
|
|
894
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
895
|
+
return stored ? JSON.parse(stored) : [];
|
|
896
|
+
} catch (error) {
|
|
897
|
+
console.error("Failed to load linked devices:", error);
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
/**
|
|
902
|
+
* Add a device to the linked devices list
|
|
903
|
+
* Called after successful key exchange
|
|
904
|
+
*/
|
|
905
|
+
addLinkedDevice = (device) => {
|
|
906
|
+
try {
|
|
907
|
+
const devices = this.getLinkedDevices();
|
|
908
|
+
const existing = devices.find((d) => d.id === device.id);
|
|
909
|
+
if (existing) {
|
|
910
|
+
existing.name = device.name;
|
|
911
|
+
} else {
|
|
912
|
+
devices.push({
|
|
913
|
+
id: device.id,
|
|
914
|
+
name: device.name,
|
|
915
|
+
linkedAt: Date.now()
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
919
|
+
} catch (error) {
|
|
920
|
+
console.error("Failed to add linked device:", error);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
/**
|
|
924
|
+
* Remove a device from the linked devices list
|
|
925
|
+
* For future use when user wants to unlink a device
|
|
926
|
+
*/
|
|
927
|
+
removeLinkedDevice = (id) => {
|
|
928
|
+
try {
|
|
929
|
+
const devices = this.getLinkedDevices().filter((d) => d.id !== id);
|
|
930
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
931
|
+
console.log(`Removed linked device: ${id}`);
|
|
932
|
+
} catch (error) {
|
|
933
|
+
console.error("Failed to remove linked device:", error);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
/**
|
|
937
|
+
* Update the hostname of a device (system-level name)
|
|
938
|
+
*/
|
|
939
|
+
updateDeviceName = (id, name) => {
|
|
940
|
+
try {
|
|
941
|
+
const devices = this.getLinkedDevices();
|
|
942
|
+
const device = devices.find((d) => d.id === id);
|
|
943
|
+
if (device) {
|
|
944
|
+
device.name = name;
|
|
945
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
946
|
+
}
|
|
947
|
+
} catch (error) {
|
|
948
|
+
console.error("Failed to update device name:", error);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* Set a custom user-defined name for a device
|
|
953
|
+
*/
|
|
954
|
+
setCustomName = (id, customName) => {
|
|
955
|
+
try {
|
|
956
|
+
const devices = this.getLinkedDevices();
|
|
957
|
+
const device = devices.find((d) => d.id === id);
|
|
958
|
+
if (device) {
|
|
959
|
+
device.customName = customName.trim() || void 0;
|
|
960
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
961
|
+
}
|
|
962
|
+
} catch (error) {
|
|
963
|
+
console.error("Failed to set custom device name:", error);
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
/**
|
|
967
|
+
* Check if a device is linked
|
|
968
|
+
*/
|
|
969
|
+
isLinked = (id) => {
|
|
970
|
+
return this.getLinkedDevices().some((d) => d.id === id);
|
|
971
|
+
};
|
|
972
|
+
};
|
|
899
973
|
export {
|
|
974
|
+
DevicePairingManager,
|
|
900
975
|
KeyTransportServer,
|
|
901
976
|
useKeyExchangeServer
|
|
902
977
|
};
|
package/dist/vite.d.mts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vite plugin that automatically externalizes native Node.js modules
|
|
5
|
+
* required by @cryptforge/key-exchange for Electron main process builds.
|
|
6
|
+
*
|
|
7
|
+
* This prevents Vite from trying to bundle native modules, which would fail.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // vite.main.config.ts
|
|
12
|
+
* import { defineConfig } from "vite";
|
|
13
|
+
* import { cryptforgeMainPlugin } from "@cryptforge/key-exchange/vite";
|
|
14
|
+
*
|
|
15
|
+
* export default defineConfig({
|
|
16
|
+
* plugins: [cryptforgeMainPlugin()],
|
|
17
|
+
* // ... rest of config
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
declare const cryptforgeMainPlugin: () => Plugin;
|
|
22
|
+
|
|
23
|
+
export { cryptforgeMainPlugin };
|