login with email

This commit is contained in:
zmeyer44 2023-11-03 14:05:59 -04:00
parent 06fc618def
commit 9ef6086e76
5 changed files with 115 additions and 14 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -12,6 +12,7 @@ import { Label } from "@/components/ui/label";
import AddPassphrase from "./AddPassphrase";
import { decryptMessage } from "@/lib/nostr";
import { toast } from "sonner";
import { generateSchnorrKeyPair } from "@/lib/keys";
export default function LoginModal() {
const { loginWithNip07, loginWithSecret } = useNDK();
@ -19,8 +20,10 @@ export default function LoginModal() {
const [isLoading, setIsLoading] = useState(false);
const [showExtensionLogin, setShowExtensionLogin] = useState(true);
const [showPassphraseLogin, setShowPassphraseLogin] = useState(false);
const [showEmailLogin, setShowEmailLogin] = useState(false);
const [nsec, setNsec] = useState("");
const [passphrase, setPassphrase] = useState("");
const [email, setEmail] = useState("");
const [encryptedNsec, setEncryptedNsec] = useState("");
const modal = useModal();
@ -92,6 +95,25 @@ export default function LoginModal() {
setIsLoading(false);
modal?.hide();
}
async function handleLoginEmail() {
if (!email || !passphrase) return;
setIsLoading(true);
const seedString = email + passphrase;
const { privateKey, publicKey } = generateSchnorrKeyPair(seedString);
console.log("privateKey", privateKey, "publicKey", publicKey);
const emailNsec = nip19.nsecEncode(privateKey);
const user = await loginWithSecret(emailNsec);
console.log("User", user);
if (!user) {
throw new Error("NO auth");
}
await loginWithPubkey(nip19.decode(user.npub).data.toString());
if (typeof window.webln !== "undefined") {
await window.webln.enable();
}
setIsLoading(false);
modal?.hide();
}
async function handleLoginPassphrase() {
if (!encryptedNsec || !passphrase) return;
setIsLoading(true);
@ -138,7 +160,51 @@ export default function LoginModal() {
Connect with extension
</Button>
)}
{showPassphraseLogin ? (
{showEmailLogin ? (
<div className="space-y-3">
<div className="space-y-2">
<Label>Email</Label>
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="email"
type="email"
className="text-[16px]"
/>
</div>
<div className="space-y-2">
<Label>Password</Label>
<Input
value={passphrase}
onChange={(e) => setPassphrase(e.target.value)}
placeholder="password..."
type="password"
className="text-[16px]"
/>
</div>
<Button
variant={"outline"}
onClick={() => void handleLoginEmail()}
loading={isLoading}
className="w-full"
>
Login
</Button>
<div className="center">
<Button
variant={"link"}
size={"sm"}
className="h-0 pt-1"
onClick={() => {
setShowEmailLogin(false);
setShowPassphraseLogin(false);
}}
>
Or, use Nsec
</Button>
</div>
</div>
) : showPassphraseLogin ? (
<div className="space-y-3">
<Label>Passphrase</Label>
<Input
@ -184,18 +250,27 @@ export default function LoginModal() {
>
Connect with Nsec
</Button>
<div className="center text-xs font-medium text-primary">
Or, use
{!!encryptedNsec && (
<div className="center">
<Button
variant={"link"}
size={"sm"}
className="h-0 pt-1"
<>
<button
className="ml-1 hover:underline"
onClick={() => setShowPassphraseLogin(true)}
>
Or, use Passphrase
</Button>
</div>
Passphrase
</button>
<span className="mx-1">or</span>
</>
)}
<button
className="ml-1 hover:underline"
onClick={() => setShowEmailLogin(true)}
>
Email
</button>
</div>
</div>
)}
</div>

View File

@ -12,7 +12,7 @@ export const useKeyboardShortcut = (keys: Key[], callback: () => void) => {
(key === "ctrl" && (event.metaKey || event.ctrlKey)) ||
(key === "shift" && event.shiftKey) ||
(key === "alt" && event.altKey) ||
(typeof key === "string" && event.key.toLowerCase() === key),
(typeof key === "string" && event.key?.toLowerCase() === key),
)
) {
callback();

24
lib/keys/index.ts Normal file
View File

@ -0,0 +1,24 @@
import { createHmac } from "crypto";
import { ec as EC } from "elliptic";
export function generateSchnorrKeyPair(seed: string): {
privateKey: string;
publicKey: string;
} {
// Use HMAC-SHA256 with your seed as the message and a secret key (salt)
const hmac = createHmac("sha256", "secret-salt");
hmac.update(seed);
const derivedKey = hmac.digest();
// Create a key pair using the derived private key
const ec = new EC("secp256k1");
const keyPair = ec.keyFromPrivate(derivedKey);
// Get the public key in hexadecimal format
const publicKey = keyPair.getPublic("hex");
return {
privateKey: derivedKey.toString("hex"),
publicKey,
};
}

View File

@ -44,6 +44,7 @@
"dayjs": "^1.11.10",
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.6",
"elliptic": "^6.5.4",
"focus-trap-react": "^10.2.3",
"framer-motion": "^10.16.4",
"jotai": "^2.4.3",
@ -75,6 +76,7 @@
"@tailwindcss/typography": "^0.5.10",
"@total-typescript/ts-reset": "^0.5.1",
"@types/crypto-js": "^4.1.2",
"@types/elliptic": "^6.4.16",
"@types/latlon-geohash": "^2.0.2",
"@types/node": "^20",
"@types/ramda": "^0.29.6",