mirror of
https://github.com/ajvpot/meshexplorer.git
synced 2026-08-07 00:52:45 +02:00
hex keys
This commit is contained in:
@@ -226,15 +226,31 @@ function ConfigPopover({ config, setConfig, onClose, anchorRef, onOpenKeyModal }
|
||||
);
|
||||
}
|
||||
|
||||
function validateMeshcoreKey(base64Key: string): string | null {
|
||||
if (!base64Key) return null;
|
||||
// Add a helper to decode base64 or hex
|
||||
function decodeKeyString(key: string): Buffer | null {
|
||||
if (!key) return null;
|
||||
// Try base64 first
|
||||
try {
|
||||
const bytes = Buffer.from(base64Key, 'base64');
|
||||
if (bytes.length !== 16) {
|
||||
return 'Key must decode to exactly 16 bytes.';
|
||||
}
|
||||
} catch {
|
||||
return 'Invalid base64 encoding.';
|
||||
const b = Buffer.from(key, 'base64');
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
// Try hex (with or without 0x)
|
||||
let hex = key.trim();
|
||||
if (hex.startsWith('0x')) hex = hex.slice(2);
|
||||
if (/^[0-9a-fA-F]{32}$/.test(hex)) {
|
||||
try {
|
||||
const b = Buffer.from(hex, 'hex');
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateMeshcoreKey(key: string): string | null {
|
||||
if (!key) return null;
|
||||
const decoded = decodeKeyString(key);
|
||||
if (!decoded) {
|
||||
return 'Key must be 16 bytes, in base64 or hex (32 hex digits)';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -263,7 +279,17 @@ function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setC
|
||||
disabled
|
||||
readOnly
|
||||
/>
|
||||
<span className="text-xs text-gray-500">ID: <span className="font-mono">{getChannelIdFromKey(PUBLIC_MESHCORE_KEY.privateKey)}</span></span>
|
||||
{/* Only show ID if valid */}
|
||||
{(() => {
|
||||
try {
|
||||
const id = getChannelIdFromKey(PUBLIC_MESHCORE_KEY.privateKey);
|
||||
return (
|
||||
<span className="text-xs text-gray-500">ID: <span className="font-mono">{id}</span></span>
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<input
|
||||
@@ -298,13 +324,23 @@ function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setC
|
||||
setConfig({ ...config, meshcoreKeys: updated });
|
||||
}}
|
||||
/>
|
||||
<span className="text-xs text-gray-500">ID: <span className="font-mono">{getChannelIdFromKey(key.privateKey)}</span></span>
|
||||
{/* Only show ID if valid */}
|
||||
{(() => {
|
||||
try {
|
||||
const id = getChannelIdFromKey(key.privateKey);
|
||||
return (
|
||||
<span className="text-xs text-gray-500">ID: <span className="font-mono">{id}</span></span>
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<input
|
||||
className={`flex-1 p-1 border rounded font-mono ${keyError ? 'border-red-500' : ''}`}
|
||||
type="text"
|
||||
placeholder="Base64 Private Key"
|
||||
placeholder="Base64 or Hex Private Key"
|
||||
value={key.privateKey}
|
||||
onChange={e => {
|
||||
const updated = [...(config.meshcoreKeys || [])];
|
||||
|
||||
+23
-4
@@ -3,16 +3,35 @@ import { createHash } from "crypto";
|
||||
// Module-level cache for channel IDs
|
||||
const channelIdCache: Record<string, string> = {};
|
||||
|
||||
// Add a helper to decode base64 or hex
|
||||
function decodeKeyString(key: string): Buffer {
|
||||
// Try base64 first
|
||||
try {
|
||||
const b = Buffer.from(key, 'base64');
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
// Try hex (with or without 0x)
|
||||
let hex = key.trim();
|
||||
if (hex.startsWith('0x')) hex = hex.slice(2);
|
||||
if (/^[0-9a-fA-F]{32}$/.test(hex)) {
|
||||
try {
|
||||
const b = Buffer.from(hex, 'hex');
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
}
|
||||
throw new Error('Invalid key format: must be 16 bytes, base64 or hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
export function getChannelIdFromKey(key: string): string {
|
||||
if (channelIdCache[key]) return channelIdCache[key];
|
||||
const keyBytes = decodeKeyString(key);
|
||||
const hash = createHash('sha256').update(keyBytes).digest();
|
||||
const id = hash[0].toString(16).padStart(2, '0');
|
||||
channelIdCache[base64Key] = id;
|
||||
channelIdCache[key] = id;
|
||||
return id;
|
||||
}
|
||||
@@ -17,6 +17,28 @@ function base64ToBytes(b64: string): Uint8Array {
|
||||
return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
// Add a helper to decode base64 or hex
|
||||
function decodeKeyString(key: string): Uint8Array {
|
||||
// Try base64 first
|
||||
try {
|
||||
const b = Uint8Array.from(atob(key), c => c.charCodeAt(0));
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
// Try hex (with or without 0x)
|
||||
let hex = key.trim();
|
||||
if (hex.startsWith('0x')) hex = hex.slice(2);
|
||||
if (/^[0-9a-fA-F]{32}$/.test(hex)) {
|
||||
try {
|
||||
const b = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
b[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
||||
}
|
||||
if (b.length === 16) return b;
|
||||
} catch {}
|
||||
}
|
||||
throw new Error('Invalid key format: must be 16 bytes, base64 or hex');
|
||||
}
|
||||
|
||||
// Helper: HMAC-SHA256, returns Uint8Array
|
||||
async function hmacSha256(key: Uint8Array, data: Uint8Array): Promise<Uint8Array> {
|
||||
if (window.crypto?.subtle) {
|
||||
@@ -89,7 +111,7 @@ export async function decryptMeshcoreGroupMessage({
|
||||
for (const base64Key of knownKeys) {
|
||||
let keyBytes: Uint8Array;
|
||||
try {
|
||||
keyBytes = base64ToBytes(base64Key);
|
||||
keyBytes = decodeKeyString(base64Key);
|
||||
} catch (e) {
|
||||
console.warn("Skipping invalid base64 meshcore key:", base64Key, e);
|
||||
failures.push({ key: base64Key, reason: `base64 decode error: ${e}` });
|
||||
|
||||
Reference in New Issue
Block a user