2023-02-09 18:05:45 +00:00
import "./Login.css" ;
import { CSSProperties , useEffect , useState } from "react" ;
2022-12-29 22:23:41 +00:00
import { useNavigate } from "react-router-dom" ;
2023-02-12 12:31:48 +00:00
import { useIntl , FormattedMessage } from "react-intl" ;
2023-03-16 18:30:50 +00:00
import { HexKey } from "@snort/nostr" ;
2022-12-29 22:23:41 +00:00
2023-03-25 22:55:34 +00:00
import { bech32ToHex , unwrap } from "Util" ;
2023-02-09 18:05:45 +00:00
import ZapButton from "Element/ZapButton" ;
2023-03-16 18:30:50 +00:00
import useImgProxy from "Hooks/useImgProxy" ;
2023-04-14 11:33:19 +00:00
import Icon from "Icons/Icon" ;
import useLogin from "Hooks/useLogin" ;
import { generateNewLogin , LoginStore } from "Login" ;
import AsyncButton from "Element/AsyncButton" ;
2023-04-19 12:10:41 +00:00
import useLoginHandler from "Hooks/useLoginHandler" ;
2023-02-12 12:31:48 +00:00
2023-02-09 18:05:45 +00:00
interface ArtworkEntry {
name : string ;
pubkey : HexKey ;
link : string ;
}
2023-04-14 11:33:19 +00:00
const KarnageKey = bech32ToHex ( "npub1r0rs5q2gk0e3dk3nlc7gnu378ec6cnlenqp8a3cjhyzu6f8k5sgs4sq9ac" ) ;
2023-02-09 18:05:45 +00:00
// todo: fill more
const Artwork : Array < ArtworkEntry > = [
{
name : "" ,
2023-04-14 11:33:19 +00:00
pubkey : KarnageKey ,
2023-02-09 18:49:12 +00:00
link : "https://void.cat/d/VKhPayp9ekeXYZGzAL9CxP" ,
2023-02-09 18:05:45 +00:00
} ,
{
name : "" ,
2023-04-14 11:33:19 +00:00
pubkey : KarnageKey ,
2023-02-09 18:49:12 +00:00
link : "https://void.cat/d/3H2h8xxc3aEN6EVeobd8tw" ,
2023-02-09 18:05:45 +00:00
} ,
{
name : "" ,
2023-04-14 11:33:19 +00:00
pubkey : KarnageKey ,
2023-02-09 18:49:12 +00:00
link : "https://void.cat/d/7i9W9PXn3TV86C4RUefNC9" ,
2023-02-09 18:05:45 +00:00
} ,
2023-02-09 18:49:12 +00:00
{
name : "" ,
2023-04-14 11:33:19 +00:00
pubkey : KarnageKey ,
2023-02-09 18:51:50 +00:00
link : "https://void.cat/d/KtoX4ei6RYHY7HESg3Ve3k" ,
} ,
2023-02-09 18:05:45 +00:00
] ;
2022-12-27 23:46:13 +00:00
2023-02-27 13:17:13 +00:00
export async function getNip05PubKey ( addr : string ) : Promise < string > {
const [ username , domain ] = addr . split ( "@" ) ;
2023-03-31 09:51:50 +00:00
const rsp = await fetch (
` https:// ${ domain } /.well-known/nostr.json?name= ${ encodeURIComponent ( username . toLocaleLowerCase ( ) ) } `
) ;
2023-02-27 13:17:13 +00:00
if ( rsp . ok ) {
const data = await rsp . json ( ) ;
2023-03-31 09:51:50 +00:00
const pKey = data . names [ username . toLowerCase ( ) ] ;
2023-02-27 13:17:13 +00:00
if ( pKey ) {
return pKey ;
}
}
throw new Error ( "User key not found" ) ;
}
2022-12-18 14:51:47 +00:00
export default function LoginPage() {
2023-02-07 20:04:50 +00:00
const navigate = useNavigate ( ) ;
2023-04-14 11:33:19 +00:00
const login = useLogin ( ) ;
2023-02-07 20:04:50 +00:00
const [ key , setKey ] = useState ( "" ) ;
const [ error , setError ] = useState ( "" ) ;
2023-02-09 18:05:45 +00:00
const [ art , setArt ] = useState < ArtworkEntry > ( ) ;
2023-04-08 17:23:20 +00:00
const [ isMasking , setMasking ] = useState ( true ) ;
2023-02-12 12:31:48 +00:00
const { formatMessage } = useIntl ( ) ;
2023-03-16 18:30:50 +00:00
const { proxy } = useImgProxy ( ) ;
2023-04-19 12:10:41 +00:00
const loginHandler = useLoginHandler ( ) ;
2023-03-16 18:30:50 +00:00
const hasNip7 = "nostr" in window ;
2023-03-31 12:08:50 +00:00
const hasSubtleCrypto = window . crypto . subtle !== undefined ;
2022-12-27 23:46:13 +00:00
2023-02-07 20:04:50 +00:00
useEffect ( ( ) = > {
2023-04-14 11:33:19 +00:00
if ( login . publicKey ) {
2023-02-07 20:04:50 +00:00
navigate ( "/" ) ;
2023-01-02 23:36:30 +00:00
}
2023-04-14 11:33:19 +00:00
} , [ login , navigate ] ) ;
2023-01-02 23:36:30 +00:00
2023-02-09 18:05:45 +00:00
useEffect ( ( ) = > {
const ret = unwrap ( Artwork . at ( Artwork . length * Math . random ( ) ) ) ;
2023-04-18 11:47:01 +00:00
const url = proxy ( ret . link ) ;
setArt ( { . . . ret , link : url } ) ;
2023-02-09 18:05:45 +00:00
} , [ ] ) ;
2023-02-07 20:04:50 +00:00
async function doLogin() {
try {
2023-04-19 12:10:41 +00:00
await loginHandler . doLogin ( key ) ;
2023-02-07 20:04:50 +00:00
} catch ( e ) {
2023-03-16 18:30:50 +00:00
if ( e instanceof Error ) {
setError ( e . message ) ;
} else {
setError (
formatMessage ( {
defaultMessage : "Unknown login error" ,
} )
) ;
}
2023-02-07 20:04:50 +00:00
console . error ( e ) ;
2022-12-27 23:46:13 +00:00
}
2023-02-07 20:04:50 +00:00
}
2022-12-27 23:46:13 +00:00
2023-02-07 20:04:50 +00:00
async function makeRandomKey() {
2023-04-14 15:02:15 +00:00
await generateNewLogin ( ) ;
2023-02-07 20:04:50 +00:00
navigate ( "/new" ) ;
}
2023-01-01 10:44:38 +00:00
2023-02-07 20:04:50 +00:00
async function doNip07Login() {
2023-04-14 11:33:19 +00:00
const relays = "getRelays" in window . nostr ? await window . nostr . getRelays ( ) : undefined ;
2023-02-07 19:47:57 +00:00
const pubKey = await window . nostr . getPublicKey ( ) ;
2023-04-14 11:33:19 +00:00
LoginStore . loginWithPubkey ( pubKey , relays ) ;
2023-02-07 20:04:50 +00:00
}
2022-12-29 10:51:32 +00:00
2023-02-07 20:04:50 +00:00
function altLogins() {
2023-03-16 18:30:50 +00:00
if ( ! hasNip7 ) {
return ;
2022-12-29 10:51:32 +00:00
}
2022-12-18 14:51:47 +00:00
return (
2023-02-09 18:05:45 +00:00
< button type = "button" onClick = { doNip07Login } >
2023-02-10 10:40:16 +00:00
< FormattedMessage
defaultMessage = "Login with Extension (NIP-07)"
description = "Login button for NIP7 key manager extension"
/ >
2023-02-09 18:05:45 +00:00
< / button >
2022-12-18 14:51:47 +00:00
) ;
2023-02-07 20:04:50 +00:00
}
2023-03-16 18:30:50 +00:00
function installExtension() {
2023-03-31 12:08:50 +00:00
if ( hasSubtleCrypto ) return ;
2023-03-16 18:30:50 +00:00
return (
< >
< div className = "flex login-or" >
< FormattedMessage defaultMessage = "OR" description = "Seperator text for Login / Generate Key" / >
< div className = "divider w-max" > < / div >
< / div >
< h1 dir = "auto" >
< FormattedMessage
defaultMessage = "Install Extension"
description = "Heading for install key manager extension"
/ >
< / h1 >
< p >
< FormattedMessage defaultMessage = "Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:" / >
< / p >
< ul >
< li >
< a href = "https://getalby.com/" target = "_blank" rel = "noreferrer" >
Alby
< / a >
< / li >
< li >
< a
href = "https://chrome.google.com/webstore/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
target = "_blank"
rel = "noreferrer" >
nos2x
< / a >
< / li >
< / ul >
< p >
< FormattedMessage
defaultMessage = "If you want to try out some others, check out {link} for more!"
values = { {
link : < a href = "https://github.com/aljazceru/awesome-nostr#browser-extensions" > awesome - nostr < / a > ,
} }
/ >
< / p >
< p >
< FormattedMessage defaultMessage = "Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow." / >
< / p >
{ hasNip7 ? (
< div className = "login-actions" >
< button type = "button" onClick = { ( ) = > doNip07Login ( ) . then ( ( ) = > navigate ( "/new/username" ) ) } >
< FormattedMessage defaultMessage = "Setup Profile" / >
< / button >
< / div >
) : (
< b className = "error" >
< FormattedMessage defaultMessage = "Hmm, can't find a key manager extension.. try reloading the page." / >
< / b >
) }
< / >
) ;
}
2023-02-07 20:04:50 +00:00
return (
2023-02-09 18:05:45 +00:00
< div className = "login" >
< div >
< div className = "login-container" >
2023-04-18 12:17:50 +00:00
< h1 className = "logo" onClick = { ( ) = > navigate ( "/" ) } >
2023-02-09 18:05:45 +00:00
Snort
2023-04-18 12:17:50 +00:00
< / h1 >
2023-02-13 16:57:51 +00:00
< h1 dir = "auto" >
2023-02-09 18:05:45 +00:00
< FormattedMessage defaultMessage = "Login" description = "Login header" / >
< / h1 >
2023-02-13 16:57:51 +00:00
< p dir = "auto" >
2023-02-09 18:05:45 +00:00
< FormattedMessage defaultMessage = "Your key" description = "Label for key input" / >
< / p >
2023-02-12 12:31:48 +00:00
< div className = "flex" >
2023-02-09 18:05:45 +00:00
< input
2023-02-13 16:57:51 +00:00
dir = "auto"
2023-04-08 13:24:45 +00:00
type = { isMasking ? "password" : "text" }
2023-04-19 12:10:41 +00:00
placeholder = { formatMessage ( {
defaultMessage : "nsec, npub, nip-05, hex, mnemonic" ,
} ) }
2023-02-09 18:05:45 +00:00
className = "f-grow"
onChange = { e = > setKey ( e . target . value ) }
/ >
2023-04-08 13:24:45 +00:00
< Icon
name = { isMasking ? "openeye" : "closedeye" }
size = { 30 }
className = "highlight btn-sm pointer"
2023-04-10 18:16:44 +00:00
onClick = { ( ) = > setMasking ( ! isMasking ) }
2023-04-08 13:24:45 +00:00
/ >
2023-02-09 18:05:45 +00:00
< / div >
{ error . length > 0 ? < b className = "error" > { error } < / b > : null }
2023-02-12 12:31:48 +00:00
< p className = "login-note" >
2023-02-09 18:05:45 +00:00
< FormattedMessage
defaultMessage = "Only the secret key can be used to publish (sign events), everything else logs you in read-only mode."
description = "Explanation for public key only login is read-only"
/ >
< / p >
2023-02-13 16:57:51 +00:00
< div dir = "auto" className = "login-actions" >
2023-02-09 18:05:45 +00:00
< button type = "button" onClick = { doLogin } >
< FormattedMessage defaultMessage = "Login" description = "Login button" / >
< / button >
2023-04-18 12:17:50 +00:00
< AsyncButton onClick = { ( ) = > makeRandomKey ( ) } >
< FormattedMessage defaultMessage = "Create Account" / >
< / AsyncButton >
2023-02-09 18:05:45 +00:00
{ altLogins ( ) }
< / div >
2023-03-16 18:30:50 +00:00
{ installExtension ( ) }
2023-02-09 18:05:45 +00:00
< / div >
2023-02-07 20:04:50 +00:00
< / div >
2023-02-09 18:05:45 +00:00
< div >
2023-02-12 12:31:48 +00:00
< div className = "artwork" style = { { [ "--img-src" ] : ` url(' ${ art ? . link } ') ` } as CSSProperties } >
< div className = "attribution" >
2023-02-09 18:05:45 +00:00
< FormattedMessage
defaultMessage = "Art by {name}"
description = "Artwork attribution label"
values = { {
2023-02-12 12:31:48 +00:00
name : < span className = "artist" > Karnage < / span > ,
2023-02-09 18:05:45 +00:00
} }
/ >
< ZapButton pubkey = { art ? . pubkey ? ? "" } / >
< / div >
< / div >
2023-02-07 20:04:50 +00:00
< / div >
< / div >
) ;
2023-01-25 18:08:53 +00:00
}