diff --git a/app/static/js/path-analyzer.js b/app/static/js/path-analyzer.js
index 56eb573..3f4eb50 100644
--- a/app/static/js/path-analyzer.js
+++ b/app/static/js/path-analyzer.js
@@ -93,7 +93,10 @@ async function paLoadContacts() {
const resp = await fetch('/api/contacts/cached?format=full');
if (resp.ok) {
const data = await resp.json();
- if (data.success) paContacts = data.contacts || [];
+ if (data.success) {
+ paContacts = data.contacts || [];
+ paTokenNameCache = new Map();
+ }
}
} catch (e) {
console.error('Failed to load contacts:', e);
@@ -107,6 +110,19 @@ function paMatchContacts(token) {
return paContacts.filter(c => (c.public_key || '').toLowerCase().startsWith(prefix));
}
+// token -> lowercase candidate contact names, memoized (contacts are
+// static per page load; cache is rebuilt when they arrive)
+let paTokenNameCache = new Map();
+
+function paTokenNames(token) {
+ let names = paTokenNameCache.get(token);
+ if (!names) {
+ names = paMatchContacts(token).map(c => (c.name || '').toLowerCase());
+ paTokenNameCache.set(token, names);
+ }
+ return names;
+}
+
// Split an echo's path hex into per-hop tokens using that echo's own
// hash_size (same logic as showPathsPopup in app.js; trailing partial kept)
function paDecodeEcho(echo) {
@@ -133,8 +149,15 @@ function paMessageMatchesFilters(msg) {
if (!ok) return false;
}
if (paFilters.token) {
- const t = paFilters.token;
- const ok = msg.echoView.some(e => e.tokens.some(tok => tok.startsWith(t)));
+ const raw = paFilters.token; // lowercase
+ const isHex = /^[0-9a-f]+$/.test(raw);
+ const hexPrefix = raw.toUpperCase();
+ // Hex input matches hash tokens by prefix; any input also matches
+ // the names of contacts the token resolves to
+ const ok = msg.echoView.some(e => e.tokens.some(tok =>
+ (isHex && tok.startsWith(hexPrefix)) ||
+ paTokenNames(tok).some(n => n.includes(raw))
+ ));
if (!ok) return false;
}
if (paFilters.sender) {
@@ -754,9 +777,7 @@ async function paLoadMessages() {
function paReadFilters() {
paFilters.hops = document.getElementById('paHopsFilter').value;
paFilters.hashSize = document.getElementById('paHashSizeFilter').value;
- // Normalize token input to hex characters only (matches chip display casing)
- paFilters.token = document.getElementById('paTokenFilter').value
- .replace(/[^0-9a-fA-F]/g, '').toUpperCase();
+ paFilters.token = document.getElementById('paTokenFilter').value.trim().toLowerCase();
paFilters.sender = document.getElementById('paSenderFilter').value.trim().toLowerCase();
paFilters.content = document.getElementById('paContentFilter').value.trim().toLowerCase();
document.getElementById('paClearFiltersBtn').classList.toggle('d-none', !paFiltersActive());
diff --git a/app/templates/path-analyzer.html b/app/templates/path-analyzer.html
index ae36ad6..ecde3ef 100644
--- a/app/templates/path-analyzer.html
+++ b/app/templates/path-analyzer.html
@@ -367,8 +367,9 @@
-
+