diff --git a/js/nostr/client.js b/js/nostr/client.js index a50eaabc..9797993b 100644 --- a/js/nostr/client.js +++ b/js/nostr/client.js @@ -181,6 +181,8 @@ import { decodeNpubToHex, encodeHexToNpub, normalizeNostrPubkey, +} from "./nip46Client.js"; +import { summarizeHexForLog, summarizeSecretForLog, summarizeMetadataForLog, @@ -189,7 +191,7 @@ import { summarizeRpcParamsForLog, summarizeRpcResultForLog, summarizeRelayPublishResultsForLog, -} from "./nip46Client.js"; +} from "./nip46LoggingUtils.js"; import { profileCache } from "../state/profileCache.js"; import { createPrivateKeyCipherClosures } from "./signerHelpers.js"; import { diff --git a/js/nostr/nip46Client.js b/js/nostr/nip46Client.js index 701076e0..b3ab6d76 100644 --- a/js/nostr/nip46Client.js +++ b/js/nostr/nip46Client.js @@ -32,6 +32,16 @@ import { import { devLogger, userLogger } from "../utils/logger.js"; import { Nip46RequestQueue, NIP46_PRIORITY } from "./nip46Queue.js"; import { HEX64_REGEX } from "../utils/hex.js"; +import { + summarizeHexForLog, + summarizeSecretForLog, + summarizeMetadataForLog, + summarizeUrlForLog, + summarizePayloadPreviewForLog, + summarizeRpcParamsForLog, + summarizeRpcResultForLog, + summarizeRelayPublishResultsForLog, +} from "./nip46LoggingUtils.js"; export const NIP46_RPC_KIND = 24_133; const NIP46_SESSION_STORAGE_KEY = "bitvid:nip46:session:v1"; @@ -1175,160 +1185,6 @@ export async function decryptNip46PayloadWithKeys(privateKey, remotePubkey, ciph throw failure; } -export function summarizeHexForLog(value) { - if (typeof value !== "string" || !value.trim()) { - return ""; - } - - const normalized = value.trim().toLowerCase(); - if (normalized.length <= 12) { - return `${normalized} (len:${normalized.length})`; - } - return `${normalized.slice(0, 8)}…${normalized.slice(-4)} (len:${normalized.length})`; -} - -export function summarizeSecretForLog(value) { - if (typeof value !== "string" || !value.trim()) { - return ""; - } - - const trimmed = value.trim(); - const visible = trimmed.length <= 4 ? "*".repeat(trimmed.length) : `${"*".repeat(3)}…`; - return `${visible} (len:${trimmed.length})`; -} - -export function summarizeMetadataForLog(metadata) { - if (!metadata || typeof metadata !== "object") { - return []; - } - return Object.keys(metadata).slice(0, 12); -} - -export function summarizeUrlForLog(value) { - if (typeof value !== "string" || !value.trim()) { - return ""; - } - - const trimmed = value.trim(); - try { - const url = new URL(trimmed); - return { - origin: url.origin, - pathname: url.pathname, - hasQuery: Boolean(url.search), - hasHash: Boolean(url.hash), - length: trimmed.length, - }; - } catch (error) { - const length = trimmed.length; - if (length <= 64) { - return `${trimmed} (len:${length})`; - } - return `${trimmed.slice(0, 32)}…${trimmed.slice(-8)} (len:${length})`; - } -} - -export function summarizePayloadPreviewForLog(value) { - if (typeof value !== "string") { - return { type: typeof value }; - } - - const trimmed = value.trim(); - if (!trimmed) { - return { type: "string", length: 0 }; - } - - return { - type: "string", - length: trimmed.length, - preview: trimmed.length <= 96 ? trimmed : `${trimmed.slice(0, 64)}…`, - }; -} - -export function summarizeRpcParamsForLog(method, params) { - if (!Array.isArray(params)) { - return []; - } - - return params.map((param, index) => { - if (typeof param === "string") { - if (method === "connect" && index === 1) { - return { index, secret: summarizeSecretForLog(param) }; - } - const trimmed = param.trim(); - if (!trimmed) { - return { index, type: "string", length: 0 }; - } - if (method === "sign_event") { - return { index, type: "string", length: trimmed.length }; - } - if (trimmed.length <= 64) { - return { index, value: trimmed, length: trimmed.length }; - } - return { - index, - type: "string", - length: trimmed.length, - preview: `${trimmed.slice(0, 32)}…${trimmed.slice(-8)}`, - }; - } - - if (param && typeof param === "object") { - return { - index, - type: Array.isArray(param) ? "array" : "object", - keys: Object.keys(param).slice(0, 6), - }; - } - - return { index, type: typeof param }; - }); -} - -export function summarizeRpcResultForLog(method, result) { - if (typeof result === "string") { - const trimmed = result.trim(); - if (!trimmed) { - return { type: "string", length: 0 }; - } - if (method === "connect") { - return { type: "string", length: trimmed.length, secret: summarizeSecretForLog(trimmed) }; - } - if (trimmed.length <= 96) { - return { type: "string", length: trimmed.length, value: trimmed }; - } - return { - type: "string", - length: trimmed.length, - preview: `${trimmed.slice(0, 48)}…${trimmed.slice(-12)}`, - }; - } - - if (!result) { - return { type: typeof result }; - } - - if (typeof result === "object") { - return { - type: Array.isArray(result) ? "array" : "object", - keys: Object.keys(result).slice(0, 6), - }; - } - - return { type: typeof result }; -} - -export function summarizeRelayPublishResultsForLog(results) { - if (!Array.isArray(results)) { - return []; - } - - return results.map((entry) => ({ - relay: entry?.relay || "", - success: Boolean(entry?.ok), - reason: entry?.error ? entry.error?.message || String(entry.error) : null, - })); -} export function createNip46RequestId() { try { diff --git a/js/nostr/nip46LoggingUtils.js b/js/nostr/nip46LoggingUtils.js new file mode 100644 index 00000000..e7973c14 --- /dev/null +++ b/js/nostr/nip46LoggingUtils.js @@ -0,0 +1,158 @@ +/** + * Logging utilities for NIP-46 (Nostr Connect) client and diagnostics. + */ + +export function summarizeHexForLog(value) { + if (typeof value !== "string" || !value.trim()) { + return ""; + } + + const normalized = value.trim().toLowerCase(); + if (normalized.length <= 12) { + return `${normalized} (len:${normalized.length})`; + } + return `${normalized.slice(0, 8)}…${normalized.slice(-4)} (len:${normalized.length})`; +} + +export function summarizeSecretForLog(value) { + if (typeof value !== "string" || !value.trim()) { + return ""; + } + + const trimmed = value.trim(); + const visible = trimmed.length <= 4 ? "*".repeat(trimmed.length) : `${"*".repeat(3)}…`; + return `${visible} (len:${trimmed.length})`; +} + +export function summarizeMetadataForLog(metadata) { + if (!metadata || typeof metadata !== "object") { + return []; + } + return Object.keys(metadata).slice(0, 12); +} + +export function summarizeUrlForLog(value) { + if (typeof value !== "string" || !value.trim()) { + return ""; + } + + const trimmed = value.trim(); + try { + const url = new URL(trimmed); + return { + origin: url.origin, + pathname: url.pathname, + hasQuery: Boolean(url.search), + hasHash: Boolean(url.hash), + length: trimmed.length, + }; + } catch (error) { + const length = trimmed.length; + if (length <= 64) { + return `${trimmed} (len:${length})`; + } + return `${trimmed.slice(0, 32)}…${trimmed.slice(-8)} (len:${length})`; + } +} + +export function summarizePayloadPreviewForLog(value) { + if (typeof value !== "string") { + return { type: typeof value }; + } + + const trimmed = value.trim(); + if (!trimmed) { + return { type: "string", length: 0 }; + } + + return { + type: "string", + length: trimmed.length, + preview: trimmed.length <= 96 ? trimmed : `${trimmed.slice(0, 64)}…`, + }; +} + +export function summarizeRpcParamsForLog(method, params) { + if (!Array.isArray(params)) { + return []; + } + + return params.map((param, index) => { + if (typeof param === "string") { + if (method === "connect" && index === 1) { + return { index, secret: summarizeSecretForLog(param) }; + } + const trimmed = param.trim(); + if (!trimmed) { + return { index, type: "string", length: 0 }; + } + if (method === "sign_event") { + return { index, type: "string", length: trimmed.length }; + } + if (trimmed.length <= 64) { + return { index, value: trimmed, length: trimmed.length }; + } + return { + index, + type: "string", + length: trimmed.length, + preview: `${trimmed.slice(0, 32)}…${trimmed.slice(-8)}`, + }; + } + + if (param && typeof param === "object") { + return { + index, + type: Array.isArray(param) ? "array" : "object", + keys: Object.keys(param).slice(0, 6), + }; + } + + return { index, type: typeof param }; + }); +} + +export function summarizeRpcResultForLog(method, result) { + if (typeof result === "string") { + const trimmed = result.trim(); + if (!trimmed) { + return { type: "string", length: 0 }; + } + if (method === "connect") { + return { type: "string", length: trimmed.length, secret: summarizeSecretForLog(trimmed) }; + } + if (trimmed.length <= 96) { + return { type: "string", length: trimmed.length, value: trimmed }; + } + return { + type: "string", + length: trimmed.length, + preview: `${trimmed.slice(0, 48)}…${trimmed.slice(-12)}`, + }; + } + + if (!result) { + return { type: typeof result }; + } + + if (typeof result === "object") { + return { + type: Array.isArray(result) ? "array" : "object", + keys: Object.keys(result).slice(0, 6), + }; + } + + return { type: typeof result }; +} + +export function summarizeRelayPublishResultsForLog(results) { + if (!Array.isArray(results)) { + return []; + } + + return results.map((entry) => ({ + relay: entry?.relay || "", + success: Boolean(entry?.ok), + reason: entry?.error ? entry.error?.message || String(entry.error) : null, + })); +} diff --git a/js/services/authProviders/nip46.js b/js/services/authProviders/nip46.js index f6108a05..3e421c87 100644 --- a/js/services/authProviders/nip46.js +++ b/js/services/authProviders/nip46.js @@ -1,27 +1,9 @@ import { devLogger } from "../../utils/logger.js"; import { accessControl } from "../../accessControl.js"; - -function summarizeHexForLog(value) { - if (typeof value !== "string" || !value.trim()) { - return ""; - } - - const normalized = value.trim().toLowerCase(); - if (normalized.length <= 12) { - return `${normalized} (len:${normalized.length})`; - } - return `${normalized.slice(0, 8)}…${normalized.slice(-4)} (len:${normalized.length})`; -} - -function summarizeSecretForLog(value) { - if (typeof value !== "string" || !value.trim()) { - return ""; - } - - const trimmed = value.trim(); - const visible = trimmed.length <= 4 ? "*".repeat(trimmed.length) : `${"*".repeat(3)}…`; - return `${visible} (len:${trimmed.length})`; -} +import { + summarizeHexForLog, + summarizeSecretForLog, +} from "../../nostr/nip46LoggingUtils.js"; function sanitizeNip46UriForLog(value) { if (typeof value !== "string" || !value) {