Add hyphen and underscore as valid password symbols, increase valid password to 6 chars, add password validity and strength indicator
This commit is contained in:
parent
8d205d9d93
commit
0b56813ece
@ -16,6 +16,7 @@ import { dbi } from '@/modules/db'
|
|||||||
import { usePassword } from '@/hooks/usePassword'
|
import { usePassword } from '@/hooks/usePassword'
|
||||||
import { useAppSelector } from '@/store/hooks/redux'
|
import { useAppSelector } from '@/store/hooks/redux'
|
||||||
import { selectKeys } from '@/store'
|
import { selectKeys } from '@/store'
|
||||||
|
import { isValidPassphase, isWeakPassphase } from '@/modules/keys'
|
||||||
|
|
||||||
type ModalSettingsProps = {
|
type ModalSettingsProps = {
|
||||||
isSynced: boolean
|
isSynced: boolean
|
||||||
@ -58,8 +59,9 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setIsPasswordInvalid(false)
|
const password = e.target.value
|
||||||
setEnteredPassword(e.target.value)
|
setIsPasswordInvalid(!!password && !isValidPassphase(password))
|
||||||
|
setEnteredPassword(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
@ -76,7 +78,7 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setIsPasswordInvalid(false)
|
setIsPasswordInvalid(false)
|
||||||
|
|
||||||
if (enteredPassword.trim().length < 6) {
|
if (!isValidPassphase(enteredPassword)) {
|
||||||
return setIsPasswordInvalid(true)
|
return setIsPasswordInvalid(true)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -114,18 +116,30 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
|||||||
{...inputProps}
|
{...inputProps}
|
||||||
onChange={handlePasswordChange}
|
onChange={handlePasswordChange}
|
||||||
value={enteredPassword}
|
value={enteredPassword}
|
||||||
helperText={isPasswordInvalid ? 'Invalid password' : ''}
|
// helperText={isPasswordInvalid ? 'Invalid password' : ''}
|
||||||
placeholder="Enter a password"
|
placeholder="Enter a password"
|
||||||
helperTextProps={{
|
// helperTextProps={{
|
||||||
sx: {
|
// sx: {
|
||||||
'&.helper_text': {
|
// '&.helper_text': {
|
||||||
color: 'red',
|
// color: 'red',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
}}
|
// }}
|
||||||
disabled={!isChecked}
|
disabled={!isChecked}
|
||||||
/>
|
/>
|
||||||
{isSynced ? (
|
{isPasswordInvalid ? (
|
||||||
|
<Typography variant="body2" color={'red'}>
|
||||||
|
Password must include 6+ English letters, numbers or punctuation marks.
|
||||||
|
</Typography>
|
||||||
|
) : !!enteredPassword && isWeakPassphase(enteredPassword) ? (
|
||||||
|
<Typography variant="body2" color={'orange'}>
|
||||||
|
Weak password
|
||||||
|
</Typography>
|
||||||
|
) : !!enteredPassword && !isPasswordInvalid ? (
|
||||||
|
<Typography variant="body2" color={'green'}>
|
||||||
|
Good password
|
||||||
|
</Typography>
|
||||||
|
) : isSynced ? (
|
||||||
<Typography variant="body2" color={'GrayText'}>
|
<Typography variant="body2" color={'GrayText'}>
|
||||||
To change your password, type a new one and sync.
|
To change your password, type a new one and sync.
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -139,7 +153,7 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
|||||||
Sync {isLoading && <CircularProgress sx={{ marginLeft: '0.5rem' }} size={'1rem'} />}
|
Sync {isLoading && <CircularProgress sx={{ marginLeft: '0.5rem' }} size={'1rem'} />}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</StyledSettingContainer>
|
</StyledSettingContainer>
|
||||||
<Button onClick={onClose}>Done</Button>
|
{/* <Button onClick={onClose}>Done</Button> */}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
|
@ -21,11 +21,31 @@ const ALGO = 'aes-256-cbc'
|
|||||||
const IV_SIZE = 16
|
const IV_SIZE = 16
|
||||||
|
|
||||||
// valid passwords are a limited ASCII only, see notes below
|
// valid passwords are a limited ASCII only, see notes below
|
||||||
const ASCII_REGEX = /^[A-Za-z0-9!@#$%^&*()]{4,}$/
|
const ASCII_REGEX = /^[A-Za-z0-9!@#$%^&*()\-_]{6,}$/
|
||||||
|
|
||||||
const ALGO_LOCAL = 'AES-CBC'
|
const ALGO_LOCAL = 'AES-CBC'
|
||||||
const KEY_SIZE_LOCAL = 256
|
const KEY_SIZE_LOCAL = 256
|
||||||
|
|
||||||
|
export function isValidPassphase(passphrase: string): boolean {
|
||||||
|
return ASCII_REGEX.test(passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWeakPassphase(passphrase: string): boolean {
|
||||||
|
const BIG_LETTER_REGEX = /[A-Z]+/
|
||||||
|
const SMALL_LETTER_REGEX = /[a-z]+/
|
||||||
|
const NUMBER_REGEX = /[0-9]+/
|
||||||
|
const PUNCT_REGEX = /[!@#$%^&*()\-_]+/
|
||||||
|
const big = BIG_LETTER_REGEX.test(passphrase) ? 1 : 0
|
||||||
|
const small = SMALL_LETTER_REGEX.test(passphrase) ? 1 : 0
|
||||||
|
const number = NUMBER_REGEX.test(passphrase) ? 1 : 0
|
||||||
|
const punct = PUNCT_REGEX.test(passphrase) ? 1 : 0
|
||||||
|
const base = big * 26 + small * 26 + number * 10 + punct * 12
|
||||||
|
const compl = Math.pow(base, passphrase.length)
|
||||||
|
const thresh = Math.pow(11, 14)
|
||||||
|
// console.log({ big, small, number, punct, base, compl, thresh });
|
||||||
|
return compl < thresh;
|
||||||
|
}
|
||||||
|
|
||||||
export class Keys {
|
export class Keys {
|
||||||
subtle: any
|
subtle: any
|
||||||
|
|
||||||
@ -33,10 +53,6 @@ export class Keys {
|
|||||||
this.subtle = cryptoSubtle
|
this.subtle = cryptoSubtle
|
||||||
}
|
}
|
||||||
|
|
||||||
public isValidPassphase(passphrase: string): boolean {
|
|
||||||
return ASCII_REGEX.test(passphrase)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async generatePassKey(pubkey: string, passphrase: string): Promise<{ passkey: Buffer; pwh: string }> {
|
public async generatePassKey(pubkey: string, passphrase: string): Promise<{ passkey: Buffer; pwh: string }> {
|
||||||
const salt = Buffer.from(pubkey, 'hex')
|
const salt = Buffer.from(pubkey, 'hex')
|
||||||
|
|
||||||
@ -45,7 +61,7 @@ export class Keys {
|
|||||||
// We could use string.normalize() to make sure all JS implementations
|
// We could use string.normalize() to make sure all JS implementations
|
||||||
// are compatible, but since we're looking to make this thing a standard
|
// are compatible, but since we're looking to make this thing a standard
|
||||||
// then the simplest way is to exclude unicode and only work with ASCII
|
// then the simplest way is to exclude unicode and only work with ASCII
|
||||||
if (!this.isValidPassphase(passphrase)) throw new Error('Password must be 4+ ASCII chars')
|
if (!isValidPassphase(passphrase)) throw new Error('Password must be 4+ ASCII chars')
|
||||||
|
|
||||||
return new Promise((ok, fail) => {
|
return new Promise((ok, fail) => {
|
||||||
// NOTE: we should use Argon2 or scrypt later, for now
|
// NOTE: we should use Argon2 or scrypt later, for now
|
||||||
|
Loading…
x
Reference in New Issue
Block a user