From b19f6a459b5694c90c025a9196c385d4f0108ea5 Mon Sep 17 00:00:00 2001 From: ajvpot <553597+ajvpot@users.noreply.github.com> Date: Thu, 3 Jul 2025 00:00:00 +0000 Subject: [PATCH] private key management for meshcore --- src/components/ChatBox.tsx | 22 +++-- src/components/ConfigContext.tsx | 152 ++++++++++++++++++++++++++++++- src/lib/meshcore.ts | 18 ++++ 3 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 src/lib/meshcore.ts diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx index 7498078..6fa4f50 100644 --- a/src/components/ChatBox.tsx +++ b/src/components/ChatBox.tsx @@ -27,6 +27,20 @@ function formatLocalTime(utcString: string): string { return utcDate.toLocaleString(); } +function ChatMessageItem({ msg }: { msg: ChatMessage }) { + // Placeholder for decryption logic + // const decryptedMessage = decryptMessage(msg.encrypted_message); + return ( +
+
+ {formatLocalTime(msg.ingest_timestamp)} {msg.channel_hash} +
+
{formatHex(msg.encrypted_message)}
+
from: {msg.origin}
+
+ ); +} + export default function ChatBox() { const [minimized, setMinimized] = useState(true); const [messages, setMessages] = useState([]); @@ -100,13 +114,7 @@ export default function ChatBox() {
No chat messages found.
)} {messages.map((msg, i) => ( -
-
- {formatLocalTime(msg.ingest_timestamp)} {msg.channel_hash} -
-
{formatHex(msg.encrypted_message)}
-
from: {msg.origin}
-
+ ))} {hasMore && ( + + + ); +} + +function validateMeshcoreKey(base64Key: string): string | null { + if (!base64Key) return null; + try { + const bytes = Buffer.from(base64Key, 'base64'); + if (bytes.length !== 16) { + return 'Key must decode to exactly 16 bytes.'; + } + } catch { + return 'Invalid base64 encoding.'; + } + return null; +} + +function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setConfig: (c: Config) => void, onClose: () => void }) { + return ( +
+
+ +

Meshcore Private Keys

+

+ These keys will be used to decrypt messages. Your keys are never shared with the server, so your messages remain secure. +

+
+
+ + ID: {getChannelIdFromKey(PUBLIC_MESHCORE_KEY.privateKey)} +
+
+ + +
+
+ {(config.meshcoreKeys || []).map((key, idx) => { + const keyError = validateMeshcoreKey(key.privateKey); + return ( +
+
+ { + const updated = [...(config.meshcoreKeys || [])]; + updated[idx] = { ...updated[idx], channelName: e.target.value }; + setConfig({ ...config, meshcoreKeys: updated }); + }} + /> + ID: {getChannelIdFromKey(key.privateKey)} +
+
+ { + const updated = [...(config.meshcoreKeys || [])]; + updated[idx] = { ...updated[idx], privateKey: e.target.value }; + setConfig({ ...config, meshcoreKeys: updated }); + }} + /> + +
+ {keyError && ( +
{keyError}
+ )} +
+ ); + })} + +
); } \ No newline at end of file diff --git a/src/lib/meshcore.ts b/src/lib/meshcore.ts new file mode 100644 index 0000000..899667d --- /dev/null +++ b/src/lib/meshcore.ts @@ -0,0 +1,18 @@ +import { createHash } from "crypto"; + +// Module-level cache for channel IDs +const channelIdCache: Record = {}; + +/** + * Returns the channel id for a given base64-encoded key. + * Decodes the key, hashes it with SHA-256, and returns the first byte as hex. + * Results are cached for performance. + */ +export function getChannelIdFromKey(base64Key: string): string { + if (channelIdCache[base64Key]) return channelIdCache[base64Key]; + const keyBytes = Buffer.from(base64Key, 'base64'); + const hash = createHash('sha256').update(keyBytes).digest(); + const id = hash[0].toString(16).padStart(2, '0'); + channelIdCache[base64Key] = id; + return id; +} \ No newline at end of file