Merge branch 'refactor/sync-npub' of https://github.com/nostrband/noauth into refactor/sync-npub

This commit is contained in:
Bekbolsun
2024-02-02 14:31:27 +06:00
9 changed files with 100 additions and 59 deletions

3
.env
View File

@ -2,4 +2,5 @@
# change if you're using a different noauthd server # change if you're using a different noauthd server
REACT_APP_WEB_PUSH_PUBKEY=BNW_39YcKbV4KunFxFhvMW5JUs8AljfFnGUeZpaerO-gwCoWyQat5ol0xOGB8MLaqqCbz0iptd2Qv3SToSGynMk REACT_APP_WEB_PUSH_PUBKEY=BNW_39YcKbV4KunFxFhvMW5JUs8AljfFnGUeZpaerO-gwCoWyQat5ol0xOGB8MLaqqCbz0iptd2Qv3SToSGynMk
#REACT_APP_NOAUTHD_URL=http://localhost:8000 #REACT_APP_NOAUTHD_URL=http://localhost:8000
REACT_APP_NOAUTHD_URL=https://noauthd.login.nostrapps.org REACT_APP_NOAUTHD_URL=https://noauthd.login.nostrapps.org
REACT_APP_DOMAIN=nsec.app

View File

@ -56,6 +56,7 @@ export const ModalImportKeys = () => {
value={enteredNsec} value={enteredNsec}
onChange={handleNsecChange} onChange={handleNsecChange}
fullWidth fullWidth
type='password'
/> />
<Button type='submit'>Import nsec</Button> <Button type='submit'>Import nsec</Button>
</Stack> </Stack>

View File

@ -19,7 +19,7 @@ import { CheckmarkIcon } from '@/assets'
import { Input } from '@/shared/Input/Input' import { Input } from '@/shared/Input/Input'
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined' import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined' import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'
import { ChangeEvent, FC, useState } from 'react' import { ChangeEvent, FC, useEffect, useState } from 'react'
import { Checkbox } from '@/shared/Checkbox/Checkbox' import { Checkbox } from '@/shared/Checkbox/Checkbox'
import { useEnqueueSnackbar } from '@/hooks/useEnqueueSnackbar' import { useEnqueueSnackbar } from '@/hooks/useEnqueueSnackbar'
import { swicCall } from '@/modules/swic' import { swicCall } from '@/modules/swic'
@ -47,6 +47,9 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
useEffect(() => setIsChecked(isSynced), [isModalOpened])
const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => { const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => {
setIsPasswordInvalid(false) setIsPasswordInvalid(false)
setEnteredPassword(e.target.value) setEnteredPassword(e.target.value)
@ -104,61 +107,61 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
checked={isChecked} checked={isChecked}
/> />
<Typography variant='caption'> <Typography variant='caption'>
Use this login on multiple devices Use this key on multiple devices
</Typography> </Typography>
</Box> </Box>
<Input
fullWidth
endAdornment={
<IconButton
size='small'
onClick={handlePasswordTypeChange}
>
{isPasswordShown ? (
<VisibilityOffOutlinedIcon htmlColor='#6b6b6b' />
) : (
<VisibilityOutlinedIcon htmlColor='#6b6b6b' />
)}
</IconButton>
}
type={isPasswordShown ? 'text' : 'password'}
onChange={handlePasswordChange}
value={enteredPassword}
helperText={
isPasswordInvalid ? 'Invalid password' : ''
}
placeholder='Enter a password'
helperTextProps={{
sx: {
'&.helper_text': {
color: 'red',
},
},
}}
disabled={!isChecked}
/>
{isSynced ? ( {isSynced ? (
<Typography variant='body2' color={'GrayText'}> <Typography variant='body2' color={'GrayText'}>
This uploads your <u>private key</u>, encrypted by To change your password, type a new one and sync.
your password, to Nsec App's server.
</Typography> </Typography>
) : ( ) : (
<> <Typography variant='body2' color={'GrayText'}>
<Input This key will be encrypted and stored on our server. You can use the password to download this key onto another device.
fullWidth </Typography>
endAdornment={
<IconButton
size='small'
onClick={handlePasswordTypeChange}
>
{isPasswordShown ? (
<VisibilityOffOutlinedIcon htmlColor='#6b6b6b' />
) : (
<VisibilityOutlinedIcon htmlColor='#6b6b6b' />
)}
</IconButton>
}
type={isPasswordShown ? 'text' : 'password'}
onChange={handlePasswordChange}
value={enteredPassword}
helperText={
isPasswordInvalid ? 'Invalid password' : ''
}
placeholder='Enter a password'
helperTextProps={{
sx: {
'&.helper_text': {
color: 'red',
},
},
}}
disabled={!isChecked}
/>
<StyledButton
type='submit'
fullWidth
disabled={!isChecked}
>
Sync{' '}
{isLoading && (
<CircularProgress
sx={{ marginLeft: '0.5rem' }}
size={'1rem'}
/>
)}
</StyledButton>
</>
)} )}
<StyledButton
type='submit'
fullWidth
disabled={!isChecked}
>
Sync{' '}
{isLoading && (
<CircularProgress
sx={{ marginLeft: '0.5rem' }}
size={'1rem'}
/>
)}
</StyledButton>
</StyledSettingContainer> </StyledSettingContainer>
<Button onClick={onClose}>Done</Button> <Button onClick={onClose}>Done</Button>
</Stack> </Stack>

View File

@ -63,7 +63,7 @@ export interface DbSchema extends Dexie {
export const db = new Dexie('noauthdb') as DbSchema export const db = new Dexie('noauthdb') as DbSchema
db.version(7).stores({ db.version(8).stores({
keys: 'npub', keys: 'npub',
apps: 'appNpub,npub,name,timestamp', apps: 'appNpub,npub,name,timestamp',
perms: 'id,npub,appNpub,perm,value,timestamp', perms: 'id,npub,appNpub,perm,value,timestamp',

View File

@ -1,12 +1,13 @@
import { Fragment } from 'react' import { Fragment } from 'react'
import { ItemKey } from './components/ItemKey' import { ItemKey } from './components/ItemKey'
import { Box, Stack, Typography } from '@mui/material' import { Box, Stack, Typography } from '@mui/material'
import { AddAccountButton } from './styled' import { AddAccountButton, GetStartedButton, LearnMoreButton } from './styled'
import { useAppSelector } from '@/store/hooks/redux' import { useAppSelector } from '@/store/hooks/redux'
import { selectKeys } from '@/store' import { selectKeys } from '@/store'
import { SectionTitle } from '@/shared/SectionTitle/SectionTitle' import { SectionTitle } from '@/shared/SectionTitle/SectionTitle'
import { useModalSearchParams } from '@/hooks/useModalSearchParams' import { useModalSearchParams } from '@/hooks/useModalSearchParams'
import { MODAL_PARAMS_KEYS } from '@/types/modal' import { MODAL_PARAMS_KEYS } from '@/types/modal'
import { DOMAIN } from '@/utils/consts'
const HomePage = () => { const HomePage = () => {
const keys = useAppSelector(selectKeys) const keys = useAppSelector(selectKeys)
@ -15,16 +16,34 @@ const HomePage = () => {
const { handleOpen } = useModalSearchParams() const { handleOpen } = useModalSearchParams()
const handleClickAddAccount = () => handleOpen(MODAL_PARAMS_KEYS.INITIAL) const handleClickAddAccount = () => handleOpen(MODAL_PARAMS_KEYS.INITIAL)
const handleLearnMore = () => {
// @ts-ignore
window.open(`https://info.${DOMAIN}`, '_blank').focus();
}
return ( return (
<Stack maxHeight={'100%'} overflow={'auto'}> <Stack maxHeight={'100%'} overflow={'auto'}>
<SectionTitle marginBottom={'0.5rem'}> <SectionTitle marginBottom={'0.5rem'}>
{isNoKeys ? 'Welcome!' : 'Keys:'} {isNoKeys ? 'Welcome' : 'Keys:'}
</SectionTitle> </SectionTitle>
<Stack gap={'0.5rem'} overflow={'auto'}> <Stack gap={'0.5rem'} overflow={'auto'}>
{isNoKeys && ( {isNoKeys && (
<Typography textAlign={'center'} variant='h5'> <>
Hello, this is a key storage app for Nostr <Typography textAlign={'left'} variant='h6' paddingTop='1em'>
</Typography> Nsec.app is a novel key storage app for Nostr.
</Typography>
<GetStartedButton onClick={handleClickAddAccount}>
Get started
</GetStartedButton>
<Typography textAlign={'left'} variant='h6' paddingTop='2em'>
Your keys are stored in your browser and
can be used in many Nostr apps without the
need for a browser extension.
</Typography>
<LearnMoreButton onClick={handleLearnMore}>
Learn more
</LearnMoreButton>
</>
)} )}
{!isNoKeys && ( {!isNoKeys && (
<Fragment> <Fragment>

View File

@ -1,6 +1,8 @@
import { AppButtonProps, Button } from '@/shared/Button/Button' import { AppButtonProps, Button } from '@/shared/Button/Button'
import { styled } from '@mui/material' import { styled } from '@mui/material'
import PersonAddAltRoundedIcon from '@mui/icons-material/PersonAddAltRounded' import PersonAddAltRoundedIcon from '@mui/icons-material/PersonAddAltRounded'
import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'
import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined'
export const AddAccountButton = styled((props: AppButtonProps) => ( export const AddAccountButton = styled((props: AppButtonProps) => (
<Button {...props} startIcon={<PersonAddAltRoundedIcon />} /> <Button {...props} startIcon={<PersonAddAltRoundedIcon />} />
@ -8,3 +10,17 @@ export const AddAccountButton = styled((props: AppButtonProps) => (
alignSelf: 'center', alignSelf: 'center',
padding: '0.35rem 1rem', padding: '0.35rem 1rem',
})) }))
export const GetStartedButton = styled((props: AppButtonProps) => (
<Button {...props} startIcon={<PlayArrowOutlinedIcon />} />
))(() => ({
alignSelf: 'left',
padding: '0.35rem 1rem',
}))
export const LearnMoreButton = styled((props: AppButtonProps) => (
<Button {...props} startIcon={<HelpOutlineOutlinedIcon />} />
))(() => ({
alignSelf: 'left',
padding: '0.35rem 1rem',
}))

View File

@ -19,12 +19,12 @@ export const useBackgroundSigning = () => {
try { try {
await askNotificationPermission() await askNotificationPermission()
const result = await swicCall('enablePush') const result = await swicCall('enablePush')
if (!result) throw new Error('Failed to enable push subscription') if (!result) throw new Error('Failed to activate the push subscription')
notify('Push notifications enabled!', 'success') notify('Push notifications enabled!', 'success')
setShowWarning(false) setShowWarning(false)
} catch (error: any) { } catch (error: any) {
notify( notify(
`Failed to enable push subscription: ${error.message}`, `Failed to enable push subscription: ${error}`,
'error', 'error',
) )
} }

View File

@ -21,7 +21,7 @@ const AppRoutes = () => {
<Routes> <Routes>
<Route path='/' element={<Layout />}> <Route path='/' element={<Layout />}>
<Route path='/' element={<Navigate to={'/home'} />} /> <Route path='/' element={<Navigate to={'/home'} />} />
<Route path='/welcome' element={<WelcomePage />} /> {/* <Route path='/welcome' element={<WelcomePage />} /> */}
<Route path='/home' element={<HomePage />} /> <Route path='/home' element={<HomePage />} />
<Route path='/key/:npub' element={<KeyPage />} /> <Route path='/key/:npub' element={<KeyPage />} />
<Route <Route

View File

@ -1,6 +1,7 @@
export const NIP46_RELAYS = ['wss://relay.login.nostrapps.org'] export const NIP46_RELAYS = ['wss://relay.login.nostrapps.org']
export const NOAUTHD_URL = process.env.REACT_APP_NOAUTHD_URL export const NOAUTHD_URL = process.env.REACT_APP_NOAUTHD_URL
export const WEB_PUSH_PUBKEY = process.env.REACT_APP_WEB_PUSH_PUBKEY export const WEB_PUSH_PUBKEY = process.env.REACT_APP_WEB_PUSH_PUBKEY
export const DOMAIN = process.env.REACT_APP_DOMAIN
export enum ACTION_TYPE { export enum ACTION_TYPE {
BASIC = 'basic', BASIC = 'basic',