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 { useAppSelector } from '@/store/hooks/redux'
|
||||
import { selectKeys } from '@/store'
|
||||
import { isValidPassphase, isWeakPassphase } from '@/modules/keys'
|
||||
|
||||
type ModalSettingsProps = {
|
||||
isSynced: boolean
|
||||
@ -58,8 +59,9 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
||||
}
|
||||
|
||||
const handlePasswordChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setIsPasswordInvalid(false)
|
||||
setEnteredPassword(e.target.value)
|
||||
const password = e.target.value
|
||||
setIsPasswordInvalid(!!password && !isValidPassphase(password))
|
||||
setEnteredPassword(password)
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
@ -76,7 +78,7 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
||||
e.preventDefault()
|
||||
setIsPasswordInvalid(false)
|
||||
|
||||
if (enteredPassword.trim().length < 6) {
|
||||
if (!isValidPassphase(enteredPassword)) {
|
||||
return setIsPasswordInvalid(true)
|
||||
}
|
||||
try {
|
||||
@ -114,18 +116,30 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
||||
{...inputProps}
|
||||
onChange={handlePasswordChange}
|
||||
value={enteredPassword}
|
||||
helperText={isPasswordInvalid ? 'Invalid password' : ''}
|
||||
// helperText={isPasswordInvalid ? 'Invalid password' : ''}
|
||||
placeholder="Enter a password"
|
||||
helperTextProps={{
|
||||
sx: {
|
||||
'&.helper_text': {
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
}}
|
||||
// helperTextProps={{
|
||||
// sx: {
|
||||
// '&.helper_text': {
|
||||
// color: 'red',
|
||||
// },
|
||||
// },
|
||||
// }}
|
||||
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'}>
|
||||
To change your password, type a new one and sync.
|
||||
</Typography>
|
||||
@ -139,7 +153,7 @@ export const ModalSettings: FC<ModalSettingsProps> = ({ isSynced }) => {
|
||||
Sync {isLoading && <CircularProgress sx={{ marginLeft: '0.5rem' }} size={'1rem'} />}
|
||||
</StyledButton>
|
||||
</StyledSettingContainer>
|
||||
<Button onClick={onClose}>Done</Button>
|
||||
{/* <Button onClick={onClose}>Done</Button> */}
|
||||
</Stack>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -21,11 +21,31 @@ const ALGO = 'aes-256-cbc'
|
||||
const IV_SIZE = 16
|
||||
|
||||
// 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 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 {
|
||||
subtle: any
|
||||
|
||||
@ -33,10 +53,6 @@ export class Keys {
|
||||
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 }> {
|
||||
const salt = Buffer.from(pubkey, 'hex')
|
||||
|
||||
@ -45,7 +61,7 @@ export class Keys {
|
||||
// We could use string.normalize() to make sure all JS implementations
|
||||
// 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
|
||||
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) => {
|
||||
// NOTE: we should use Argon2 or scrypt later, for now
|
||||
|
Loading…
x
Reference in New Issue
Block a user