mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
The login modal now shows <bitlogin-auth> -- a portable Nostr identity behind a login name and password -- as the default sign-in path, styled with bitvid's own brand tokens (accent-strong, surfaces, radii). The existing NIP-07 extension, nsec, and NIP-46 remote-signer options still work exactly as before, just collapsed under a new "Other login options" fold instead of a flat "Available methods" grid; nip07 no longer carries the stale "Recommended" eyebrow now that BitLogin has that role. BitLogin isn't a single button-click-then-await-a-promise flow like the other providers -- it's a whole multi-screen sign-in/create/recover UI -- so it gets a permanent, statically-declared widget in components/login-modal.html (js/ui/bitloginModalIntegration.js relocates it, never destroys and recreates it, since removal tears down its crypto Web Worker) instead of a grid button. It still goes through the exact same session-establishment path as every other signer: a new "bitlogin" provider (js/services/authProviders/bitlogin.js) lets AuthService resolve and activate it via the normal requestLogin -> handleAuthLogin path, while providersForModal excludes it from the grid so it isn't rendered twice. Two things this needed beyond the wiring itself: - js/app.js is one line from its lint/file-size ceiling, so the only change there is renaming an import binding (providers -> providersForModal), a net-zero line change. The actual widget/event wiring lives in a new, unconstrained module instead. - The login modal's HTML (including the permanent widget element) loads asynchronously after bootstrap runs, so wireBitloginLogin() waits via MutationObserver rather than assuming a specific call order. Vendored via scripts/build-bitlogin-widget.mjs (mirrors the existing Bitcoin Connect/Blossom vendor steps): BitLogin isn't published to npm, so the widget build is copied verbatim from the sibling ../bitlogin checkout into committed vendor/bitlogin/, then lazy-imported (like Bitcoin Connect) so its ~350KB never weighs on visitors who never open the login modal. Gated behind FEATURE_BITLOGIN (config/instance-config.js), default on for this unstable-branch experiment per AGENTS.md §1 -- reset to false before this reaches main until verified end-to-end against production relays. Verified: npm run lint (clean), the full auth/login test suite (43/43, including new coverage for the provider + adapter), and a manual Chrome pass against the built dist/ -- widget renders themed correctly, "Other login options" still shows the original four methods unchanged.
90 lines
2.3 KiB
JavaScript
90 lines
2.3 KiB
JavaScript
import { accessControl } from "../../accessControl.js";
|
|
|
|
const PROVIDER_ID = "nip07";
|
|
const PROVIDER_LABEL = "extension (nip-07)";
|
|
const PROVIDER_DESCRIPTION =
|
|
"Authorize with a NIP-07 browser extension like Alby or nos2x.";
|
|
const PROVIDER_CAPABILITIES = Object.freeze([
|
|
Object.freeze({
|
|
id: "signing",
|
|
label: "Signs Nostr events",
|
|
variant: "info",
|
|
}),
|
|
Object.freeze({
|
|
id: "session",
|
|
label: "Loads your public key",
|
|
variant: "neutral",
|
|
}),
|
|
]);
|
|
const PROVIDER_BUTTON = Object.freeze({
|
|
variant: "primary",
|
|
});
|
|
const PROVIDER_MESSAGES = Object.freeze({
|
|
loading: "Connecting to your extension…",
|
|
slow: "Waiting for the extension prompt…",
|
|
error: "Failed to login with your browser extension. Please try again.",
|
|
});
|
|
|
|
function normalizePubkey(result) {
|
|
if (typeof result === "string") {
|
|
return result;
|
|
}
|
|
|
|
if (!result || typeof result !== "object") {
|
|
return "";
|
|
}
|
|
|
|
if (typeof result.pubkey === "string") {
|
|
return result.pubkey;
|
|
}
|
|
|
|
if (typeof result.publicKey === "string") {
|
|
return result.publicKey;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
export default {
|
|
id: PROVIDER_ID,
|
|
label: PROVIDER_LABEL,
|
|
description: PROVIDER_DESCRIPTION,
|
|
tone: "accent",
|
|
badgeVariant: "info",
|
|
capabilities: PROVIDER_CAPABILITIES,
|
|
button: PROVIDER_BUTTON,
|
|
messages: PROVIDER_MESSAGES,
|
|
errorMessage: PROVIDER_MESSAGES.error,
|
|
async login({ nostrClient, options } = {}) {
|
|
if (!nostrClient || typeof nostrClient.loginWithExtension !== "function") {
|
|
const error = new Error("Extension login is not available in this environment.");
|
|
error.code = "provider-unavailable";
|
|
throw error;
|
|
}
|
|
|
|
const validator = (pubkey) => {
|
|
if (!accessControl.canAccess(pubkey)) {
|
|
if (accessControl.isBlacklisted(pubkey)) {
|
|
throw new Error("Your account has been blocked on this platform.");
|
|
}
|
|
throw new Error("Access restricted to admins and moderators users only.");
|
|
}
|
|
return true;
|
|
};
|
|
|
|
const result = await nostrClient.loginWithExtension({ ...options, validator });
|
|
const pubkey = normalizePubkey(result);
|
|
const signer =
|
|
result && typeof result === "object" && result.signer
|
|
? result.signer
|
|
: null;
|
|
|
|
return {
|
|
authType: PROVIDER_ID,
|
|
pubkey,
|
|
signer,
|
|
rawResult: result,
|
|
};
|
|
},
|
|
};
|