support # channels

This commit is contained in:
ajvpot
2025-09-15 23:03:29 +02:00
parent ed9943e091
commit ea32ccea77
2 changed files with 40 additions and 3 deletions
+15 -3
View File
@@ -1,6 +1,6 @@
"use client";
import React, { createContext, useContext, useState, useEffect, useRef, useLayoutEffect, ReactNode } from "react";
import { getChannelIdFromKey } from "@/lib/meshcore";
import { getChannelIdFromKey, deriveKeyFromChannelName } from "@/lib/meshcore";
import { getRegionFriendlyNames } from "@/lib/regions";
import Modal from "./Modal";
@@ -353,7 +353,19 @@ function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setC
value={key.channelName}
onChange={e => {
const updated = [...(config.meshcoreKeys || [])];
updated[idx] = { ...updated[idx], channelName: e.target.value };
const newChannelName = e.target.value;
const updatedKey = { ...updated[idx], channelName: newChannelName };
// Auto-populate private key for # channels
if (newChannelName.startsWith('#') && newChannelName.length > 1) {
try {
updatedKey.privateKey = deriveKeyFromChannelName(newChannelName);
} catch (error) {
// If derivation fails, leave the key as is
}
}
updated[idx] = updatedKey;
setConfig({ ...config, meshcoreKeys: updated });
}}
/>
@@ -373,7 +385,7 @@ function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setC
<input
className={`flex-1 p-1 border rounded font-mono ${keyError ? 'border-red-500' : ''}`}
type="text"
placeholder="Base64 or Hex Private Key"
placeholder="Base64 or Hex Private Key (auto-filled for # channels)"
value={key.privateKey}
onChange={e => {
const updated = [...(config.meshcoreKeys || [])];
+25
View File
@@ -1,6 +1,31 @@
import { createHash, createHmac } from "crypto";
import aesjs from "aes-js";
/**
* Derives a 128-bit encryption key from a channel name that starts with '#'.
* Applies filtering: converts to lowercase and keeps only a-z, 0-9, and hyphen.
* Uses SHA256 hash of the filtered channel name (including '#') as ASCII bytes,
* then truncates to first 128 bits (16 bytes) and returns as hex.
*/
export function deriveKeyFromChannelName(channelName: string): string {
if (!channelName.startsWith('#')) {
throw new Error('Channel name must start with #');
}
// Apply filtering: lowercase and keep only a-z, 0-9, hyphen
const filteredName = '#' + channelName.slice(1)
.toLowerCase()
.replace(/[^a-z0-9-]/g, '');
// Convert filtered channel name to ASCII bytes and hash with SHA256
const nameBytes = Buffer.from(filteredName, 'ascii');
const hash = createHash('sha256').update(nameBytes).digest();
// Truncate to first 128 bits (16 bytes) and return as hex
const key128bit = hash.slice(0, 16);
return key128bit.toString('hex');
}
// Module-level cache for channel IDs
const channelIdCache: Record<string, string> = {};