diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index 69389105..361f607c 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -22,7 +22,7 @@ Ready to jump in? Here's everything you need to know to start watching and shari ### Step 2: Prepare Your Video -1. **Format:** We accept **.mp4, .webm, .mov, .mkv, .ts, .m3u8, .mpg, .mpeg** (Max 2GB recommended). For detailed requirements and troubleshooting, see our [Upload Guide](../guides/upload-content.md). +1. **Format:** We accept **.mp4, .webm, .mov, .mkv, .ts, .m3u8, .mpg, .mpeg** (Max 2GB recommended). For detailed requirements and troubleshooting, see our [Upload Guide](guides/upload-content.md). 2. **Hosting:** You can upload directly via bitvid (requires your own Cloudflare R2 or S3 bucket) or host your video elsewhere (CDN, Cloudflare Stream, etc.) and provide the HTTPS URL. For external hosting, ensure the format is streamable (MP4/WebM/HLS/DASH). 3. **(Optional) WebTorrent:** If hosting externally, you can generate a WebTorrent magnet so viewers can fall back to peer-to-peer delivery. diff --git a/js/nostr/client.js b/js/nostr/client.js index 02630b1c..13bed5b9 100644 --- a/js/nostr/client.js +++ b/js/nostr/client.js @@ -800,8 +800,6 @@ export class NostrClient { get sessionActorCipherClosuresPrivateKey() { return this.signerManager.sessionActorCipherClosuresPrivateKey; } set sessionActorCipherClosuresPrivateKey(val) { this.signerManager.sessionActorCipherClosuresPrivateKey = val; } - get extensionPermissionCache() { return this.signerManager.extensionPermissionCache; } - get pool() { return this.connectionManager.pool; } set pool(val) { this.connectionManager.pool = val; } @@ -816,6 +814,11 @@ export class NostrClient { get writeRelays() { return this.connectionManager.writeRelays; } set writeRelays(val) { this.connectionManager.writeRelays = val; } + + get unreachableRelays() { return this.connectionManager.unreachableRelays; } + + get extensionPermissionCache() { return this.signerManager.extensionPermissionCache; } + /** * Records a deletion timestamp for a video identifier (Tombstoning). * @@ -942,23 +945,6 @@ export class NostrClient { } } - resolveEventDTag(event, fallbackEvent = null) { - if (!event || typeof event !== "object") { - if (fallbackEvent) { - return this.resolveEventDTag(fallbackEvent); - } - return ""; - } - const val = getDTagValueFromTags(event.tags); - if (val) { - return val; - } - if (fallbackEvent) { - return this.resolveEventDTag(fallbackEvent); - } - return ""; - } - getActiveKey(video) { return getActiveKey(video); } @@ -2992,21 +2978,6 @@ export class NostrClient { return this.signerManager.ensureActiveSignerForPubkey(pubkey); } - async registerPrivateKeySigner({ privateKey, pubkey }) { - if (!privateKey) { - throw new Error("Private key is required."); - } - const adapter = await createNsecAdapter({ privateKey, pubkey }); - this.signerManager.setActiveSigner(adapter); - this.sessionActor = { - pubkey: adapter.pubkey, - privateKey: privateKey, - source: "nsec", - createdAt: Date.now(), - }; - return adapter; - } - async loginWithExtension(options) { return this.signerManager.loginWithExtension(options); } @@ -3015,10 +2986,6 @@ export class NostrClient { return this.signerManager.connectRemoteSigner(params); } - installNip46Client(client) { - this.signerManager.installNip46Client(client); - } - async useStoredRemoteSigner(options) { return this.signerManager.useStoredRemoteSigner(options); } diff --git a/js/nostr/managers/SignerManager.js b/js/nostr/managers/SignerManager.js index 182d1d4f..f361cdda 100644 --- a/js/nostr/managers/SignerManager.js +++ b/js/nostr/managers/SignerManager.js @@ -47,7 +47,6 @@ import { summarizeUrlForLog, } from "../nip46LoggingUtils.js"; -import { bytesToHex } from "../../../vendor/crypto-helpers.bundle.min.js"; import { devLogger, userLogger } from "../../utils/logger.js"; import { createPrivateKeyCipherClosures } from "../signerHelpers.js"; import { queueSignEvent } from "../signRequestQueue.js"; @@ -264,9 +263,12 @@ export class SignerManager { this.extensionReady = false; this.extensionPermissionsGranted = false; this.extensionPermissionCache = new Map(); - const storedPermissions = readStoredNip07Permissions(); - for (const method of storedPermissions) { - this.extensionPermissionCache.set(method, true); + const stored = readStoredNip07Permissions(); + if (stored && stored.size > 0) { + this.extensionPermissionsGranted = true; + for (const method of stored) { + this.extensionPermissionCache.set(method, true); + } } this.sessionActorCipherClosures = null; this.sessionActorCipherClosuresPrivateKey = null; @@ -316,45 +318,21 @@ export class SignerManager { async ensureSessionActor() { if (this.sessionActor) { - return this.sessionActor.pubkey; + return this.sessionActor; } if (this.lockedSessionActor) { - return this.lockedSessionActor.pubkey; + return this.lockedSessionActor; } const storedEntry = readStoredSessionActorEntry(); if (storedEntry) { this.lockedSessionActor = storedEntry; this.sessionActor = storedEntry; - return storedEntry.pubkey; + return storedEntry; } - const tools = await ensureNostrTools(); - let privateKey = ""; - if (tools && typeof tools.generateSecretKey === "function") { - const secret = tools.generateSecretKey(); - privateKey = bytesToHex(secret); - } else if (tools && typeof tools.generatePrivateKey === "function") { - privateKey = tools.generatePrivateKey(); - } else { - throw new Error("Failed to generate session actor: nostr-tools missing key generation."); - } - - let pubkey = ""; - if (tools && typeof tools.getPublicKey === "function") { - pubkey = tools.getPublicKey(privateKey); - } - - const newActor = { - pubkey, - privateKey, - source: "generated", - createdAt: Date.now(), - }; - - this.sessionActor = newActor; - return pubkey; + return null; } clearStoredSessionActor() { @@ -473,7 +451,7 @@ export class SignerManager { writeStoredNip07Permissions(missing); this.extensionPermissionsGranted = true; this.extensionPermissionCache.set(cacheKey, true); - for (const method of missing) { + for (const method of methods) { this.extensionPermissionCache.set(method, true); } return { ok: true }; @@ -546,7 +524,7 @@ export class SignerManager { ); } - const permissionResult = await this.ensureExtensionPermissions( + const permissionResult = await this.client.ensureExtensionPermissions( DEFAULT_NIP07_PERMISSION_METHODS, { context: "login", logMetrics: true, showStatus: false }, ); @@ -583,16 +561,6 @@ export class SignerManager { return { pubkey: normalized, signer: adapter }; } - installNip46Client(client) { - if (!client) { - return; - } - this.nip46Client = client; - this.pubkey = client.userPubkey || client.remotePubkey; // Fallback - this.setActiveSigner(client.getActiveSigner()); - this.emitRemoteSignerChange(); - } - async connectRemoteSigner({ connectionString, remember = true, @@ -939,10 +907,6 @@ export class SignerManager { }; } - signEventWithPrivateKey(event, privateKey) { - return signEventWithPrivateKey(event, privateKey); - } - logout() { const previousPubkey = this.pubkey; this.pubkey = null; diff --git a/js/nostr/relayBatchFetcher.js b/js/nostr/relayBatchFetcher.js index 5fdf0910..7afe346e 100644 --- a/js/nostr/relayBatchFetcher.js +++ b/js/nostr/relayBatchFetcher.js @@ -5,9 +5,6 @@ import { normalizeNostrPubkey, sanitizeRelayList } from "./nip46Client.js"; import { DEFAULT_RELAY_URLS, RELAY_URLS } from "./toolkit.js"; export class RelayBatchFetcher { - /** - * @param {import("./client.js").NostrClient} client - */ constructor(client) { this.client = client; } diff --git a/js/nostr/sessionActor.js b/js/nostr/sessionActor.js index 4088b37a..bbbafc2f 100644 --- a/js/nostr/sessionActor.js +++ b/js/nostr/sessionActor.js @@ -484,17 +484,7 @@ export function clearStoredSessionActor() { export function isSessionActor(nostrClient) { const sa = nostrClient?.sessionActor; - if (!sa) { - return false; - } - if ( - nostrClient?.pubkey && - sa.pubkey && - nostrClient.pubkey !== sa.pubkey - ) { - return false; - } - return sa.source !== "nsec"; + return !!sa && sa.source !== "nsec"; } function _closeSessionActorDb() { diff --git a/tests/nostr-login-permissions.test.mjs b/tests/nostr-login-permissions.test.mjs index 60ba42c9..8193512b 100644 --- a/tests/nostr-login-permissions.test.mjs +++ b/tests/nostr-login-permissions.test.mjs @@ -458,11 +458,10 @@ describe("NIP-07 Login Permissions", () => { it("NIP-07 login does not wait for deferred permission grants", async () => { clearStoredPermissions(); const env = setupLoginEnvironment(); - const target = nostrClient.signerManager || nostrClient; - const originalEnsurePermissions = target.ensureExtensionPermissions; + const originalEnsurePermissions = nostrClient.ensureExtensionPermissions; let completionPromise; - target.ensureExtensionPermissions = async () => { + nostrClient.ensureExtensionPermissions = async () => { completionPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error("permission denied")), 300); }); @@ -485,7 +484,7 @@ describe("NIP-07 Login Permissions", () => { "deferred permission grants should still reject", ); } finally { - target.ensureExtensionPermissions = originalEnsurePermissions; + nostrClient.ensureExtensionPermissions = originalEnsurePermissions; env.restore(); nostrClient.logout(); clearStoredPermissions(); diff --git a/tests/nostr-signer-race.test.mjs b/tests/nostr-signer-race.test.mjs index a5d8e3bb..3cb34217 100644 --- a/tests/nostr-signer-race.test.mjs +++ b/tests/nostr-signer-race.test.mjs @@ -15,11 +15,7 @@ test("ensureActiveSignerForPubkey prefers concurrent login over late extension i const client = new NostrClient(); client.pubkey = HEX_PUBKEY; // Pre-condition: Cache permissions to trigger the waitForNip07Extension logic - if (typeof client.extensionPermissionCache.add === 'function') { - client.extensionPermissionCache.add("sign_event"); - } else if (typeof client.extensionPermissionCache.set === 'function') { - client.extensionPermissionCache.set("sign_event", true); - } + client.extensionPermissionCache.add("sign_event"); // Mock a NIP-46 signer that might be set during the race const mockNip46Signer = {