diff --git a/src/actions/nostr.ts b/src/actions/nostr.ts new file mode 100644 index 000000000..4a155c435 --- /dev/null +++ b/src/actions/nostr.ts @@ -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 }; \ No newline at end of file diff --git a/src/features/auth-login/components/registration-form.tsx b/src/features/auth-login/components/registration-form.tsx index f3b4fbbdd..1b19b0b37 100644 --- a/src/features/auth-login/components/registration-form.tsx +++ b/src/features/auth-login/components/registration-form.tsx @@ -245,46 +245,52 @@ const RegistrationForm: React.FC = ({ inviteToken }) => { /> - - - - - + {!features.nostrSignup && ( - + )} + + {!features.nostrSignup && ( + <> + + + + + + + )} {birthdayRequired && ( { 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 = () => { ) : ( <> -
- setUsername(event.target.value)} - type='text' - placeholder={intl.formatMessage(features.logInWithUsername ? messages.username : messages.email)} - className='max-w-[200px]' - /> + {features.nostrSignup ? ( +
+ +
+ ) : ( + + setUsername(event.target.value)} + type='text' + placeholder={intl.formatMessage(features.logInWithUsername ? messages.username : messages.email)} + className='max-w-[200px]' + /> - setPassword(event.target.value)} - type='password' - placeholder={intl.formatMessage(messages.password)} - className='max-w-[200px]' - /> + setPassword(event.target.value)} + type='password' + placeholder={intl.formatMessage(messages.password)} + className='max-w-[200px]' + /> - - - - - + + + + + + +
+ )} + +
- - -
- - {isOpen && ( + {(isOpen) && ( diff --git a/src/utils/features.ts b/src/utils/features.ts index f0207bfac..a1224eda2 100644 --- a/src/utils/features.ts +++ b/src/utils/features.ts @@ -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