Nostr: enable Nostr login

environments/review-nostr-mach-rhfii1/deployments/4088
Alex Gleason 2023-10-04 18:03:26 -05:00
rodzic 3cebd961ca
commit 28731f6087
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
4 zmienionych plików z 123 dodań i 70 usunięć

Wyświetl plik

@ -0,0 +1,18 @@
import { nip19 } from 'nostr-tools';
import { getPublicKey } from 'soapbox/features/nostr/sign';
import { type AppDispatch } from 'soapbox/store';
import { verifyCredentials } from './auth';
/** Log in with a Nostr pubkey. */
function nostrLogIn() {
return async (dispatch: AppDispatch) => {
const pubkey = await getPublicKey();
const npub = nip19.npubEncode(pubkey);
return dispatch(verifyCredentials(npub));
};
}
export { nostrLogIn };

Wyświetl plik

@ -245,46 +245,52 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
/>
</FormGroup>
<Input
type='email'
name='email'
placeholder={intl.formatMessage(messages.email)}
autoComplete='off'
autoCorrect='off'
autoCapitalize='off'
onChange={onInputChange}
value={params.get('email', '')}
required
/>
<Input
type='password'
name='password'
placeholder={intl.formatMessage(messages.password)}
autoComplete='off'
autoCorrect='off'
autoCapitalize='off'
onChange={onPasswordChange}
value={params.get('password', '')}
required
/>
<FormGroup
errors={passwordMismatch ? [intl.formatMessage(messages.passwordMismatch)] : undefined}
>
{!features.nostrSignup && (
<Input
type='password'
name='password_confirmation'
placeholder={intl.formatMessage(messages.confirm)}
type='email'
name='email'
placeholder={intl.formatMessage(messages.email)}
autoComplete='off'
autoCorrect='off'
autoCapitalize='off'
onChange={onPasswordConfirmChange}
onBlur={onPasswordConfirmBlur}
value={passwordConfirmation}
onChange={onInputChange}
value={params.get('email', '')}
required
/>
</FormGroup>
)}
{!features.nostrSignup && (
<>
<Input
type='password'
name='password'
placeholder={intl.formatMessage(messages.password)}
autoComplete='off'
autoCorrect='off'
autoCapitalize='off'
onChange={onPasswordChange}
value={params.get('password', '')}
required
/>
<FormGroup
errors={passwordMismatch ? [intl.formatMessage(messages.passwordMismatch)] : undefined}
>
<Input
type='password'
name='password_confirmation'
placeholder={intl.formatMessage(messages.confirm)}
autoComplete='off'
autoCorrect='off'
autoCapitalize='off'
onChange={onPasswordConfirmChange}
onBlur={onPasswordConfirmBlur}
value={passwordConfirmation}
required
/>
</FormGroup>
</>
)}
{birthdayRequired && (
<BirthdayInput

Wyświetl plik

@ -5,6 +5,7 @@ import { Link, Redirect } from 'react-router-dom';
import { logIn, verifyCredentials } from 'soapbox/actions/auth';
import { fetchInstance } from 'soapbox/actions/instance';
import { nostrLogIn } from 'soapbox/actions/nostr';
import { openSidebar } from 'soapbox/actions/sidebar';
import SiteLogo from 'soapbox/components/site-logo';
import { Avatar, Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui';
@ -38,6 +39,12 @@ const Navbar = () => {
const onOpenSidebar = () => dispatch(openSidebar());
const handleNostrLogin = async () => {
setLoading(true);
await dispatch(nostrLogIn()).catch(console.error);
setLoading(false);
};
const handleSubmit: React.FormEventHandler = (event) => {
event.preventDefault();
setLoading(true);
@ -107,50 +114,66 @@ const Navbar = () => {
</div>
) : (
<>
<Form className='hidden items-center space-x-2 rtl:space-x-reverse lg:flex' onSubmit={handleSubmit}>
<Input
required
value={username}
onChange={(event) => setUsername(event.target.value)}
type='text'
placeholder={intl.formatMessage(features.logInWithUsername ? messages.username : messages.email)}
className='max-w-[200px]'
/>
{features.nostrSignup ? (
<div className='hidden items-center xl:flex'>
<Button
theme='primary'
onClick={handleNostrLogin}
disabled={isLoading}
>
{intl.formatMessage(messages.login)}
</Button>
</div>
) : (
<Form className='hidden items-center space-x-2 rtl:space-x-reverse xl:flex' onSubmit={handleSubmit}>
<Input
required
value={username}
onChange={(event) => setUsername(event.target.value)}
type='text'
placeholder={intl.formatMessage(features.logInWithUsername ? messages.username : messages.email)}
className='max-w-[200px]'
/>
<Input
required
value={password}
onChange={(event) => setPassword(event.target.value)}
type='password'
placeholder={intl.formatMessage(messages.password)}
className='max-w-[200px]'
/>
<Input
required
value={password}
onChange={(event) => setPassword(event.target.value)}
type='password'
placeholder={intl.formatMessage(messages.password)}
className='max-w-[200px]'
/>
<Link to='/reset-password'>
<Tooltip text={intl.formatMessage(messages.forgotPassword)}>
<IconButton
src={require('@tabler/icons/help.svg')}
className='cursor-pointer bg-transparent text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200'
iconClassName='h-5 w-5'
/>
</Tooltip>
</Link>
<Link to='/reset-password'>
<Tooltip text={intl.formatMessage(messages.forgotPassword)}>
<IconButton
src={require('@tabler/icons/help.svg')}
className='cursor-pointer bg-transparent text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200'
iconClassName='h-5 w-5'
/>
</Tooltip>
</Link>
<Button
theme='primary'
type='submit'
disabled={isLoading}
>
{intl.formatMessage(messages.login)}
</Button>
</Form>
)}
<div className='space-x-1.5 xl:hidden'>
<Button
theme='primary'
type='submit'
disabled={isLoading}
theme='tertiary'
size='sm'
{...(features.nostrSignup ? { onClick: handleNostrLogin } : { to: '/login' })}
>
{intl.formatMessage(messages.login)}
</Button>
</Form>
<div className='space-x-1.5 lg:hidden'>
<Button theme='tertiary' to='/login' size='sm'>
<FormattedMessage id='account.login' defaultMessage='Log In' />
</Button>
{isOpen && (
{(isOpen) && (
<Button theme='primary' to='/signup' size='sm'>
<FormattedMessage id='account.register' defaultMessage='Sign up' />
</Button>

Wyświetl plik

@ -685,6 +685,12 @@ const getInstanceFeatures = (instance: Instance) => {
*/
nostrSign: v.software === DITTO,
/**
* Whether the backend uses Ditto's Nosteric way of registration.
* @see POST /api/v1/accounts
*/
nostrSignup: v.software === DITTO,
/**
* Add private notes to accounts.
* @see POST /api/v1/accounts/:id/note