mobile: applock with pin and password

This commit is contained in:
Ammar Ahmed
2024-02-07 13:03:25 +05:00
committed by Abdullah Atta
parent bad138d2fa
commit 9722fab8f3
10 changed files with 139 additions and 51 deletions

View File

@@ -47,6 +47,9 @@ const AppLockedOverlay = () => {
const password = useRef<string>();
const appState = useAppState();
const biometricUnlockAwaitingUserInput = useRef(false);
const keyboardType = useSettingStore(
(state) => state.settings.applockKeyboardType
);
const appLockHasPasswordSecurity = useSettingStore(
(state) => state.settings.appLockHasPasswordSecurity
);
@@ -186,11 +189,13 @@ const AppLockedOverlay = () => {
fwdRef={passwordInputRef}
secureTextEntry
keyboardType={
appLockHasPasswordSecurity ? "number-pad" : "default"
appLockHasPasswordSecurity ? keyboardType : "default"
}
placeholder={`Enter ${
appLockHasPasswordSecurity
? `app lock pin`
? `app lock ${
keyboardType === "numeric" ? "pin" : "password"
}`
: "account password"
}`}
onChangeText={(v) => (password.current = v)}

View File

@@ -31,22 +31,30 @@ import {
eSubscribeEvent
} from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { useSettingStore } from "../../../stores/use-setting-store";
import { getElevationStyle } from "../../../utils/elevation";
import {
eCloseAppLocKPasswordDailog,
eOpenAppLockPasswordDialog
} from "../../../utils/events";
import { SIZE } from "../../../utils/size";
import { sleep } from "../../../utils/time";
import BaseDialog from "../../dialog/base-dialog";
import DialogButtons from "../../dialog/dialog-buttons";
import DialogHeader from "../../dialog/dialog-header";
import { Toast } from "../../toast";
import { IconButton } from "../../ui/icon-button";
import Input from "../../ui/input";
import Seperator from "../../ui/seperator";
export const AppLockPassword = () => {
const { colors } = useThemeColors();
const [mode, setMode] = useState<"create" | "change" | "remove">("create");
const [keyboardType, setKeyboardType] = useState<"pin" | "password">(
useSettingStore.getState().settings.applockKeyboardType === "default"
? "password"
: "pin"
);
const [visible, setVisible] = useState(false);
const currentPasswordInputRef = useRef<TextInput>(null);
const passwordInputRef = useRef<TextInput>(null);
@@ -56,6 +64,7 @@ export const AppLockPassword = () => {
password?: string;
confirmPassword?: string;
}>({});
const [secureTextEntry, setSecureTextEntry] = useState(true);
useEffect(() => {
const subs = [
@@ -72,7 +81,7 @@ export const AppLockPassword = () => {
})
];
return () => {
subs.forEach((sub) => sub.unsubscribe());
subs.forEach((sub) => sub?.unsubscribe());
};
}, []);
@@ -85,7 +94,11 @@ export const AppLockPassword = () => {
<BaseDialog
onShow={async () => {
await sleep(100);
passwordInputRef.current?.focus();
if (mode !== "change") {
passwordInputRef.current?.focus();
} else {
currentPasswordInputRef.current?.focus();
}
}}
statusBarTranslucent={false}
onRequestClose={close}
@@ -103,17 +116,17 @@ export const AppLockPassword = () => {
<DialogHeader
title={
mode === "change"
? "Change app lock pin"
? `Change app lock ${keyboardType}`
: mode === "remove"
? "Remove app lock pin"
: "Set up app lock pin"
? `Remove app lock ${keyboardType}`
: `Set up app lock ${keyboardType}`
}
paragraph={
mode === "change"
? "Change app lock pin"
? `Change app lock ${keyboardType}`
: mode === "remove"
? "Remove app lock pin"
: "Set up a custom app lock pin to unlock the app"
? `Remove app lock ${keyboardType}`
: `Set up a custom app lock ${keyboardType} to unlock the app`
}
icon="shield"
padding={12}
@@ -135,12 +148,13 @@ export const AppLockPassword = () => {
onSubmit={() => {
passwordInputRef.current?.focus();
}}
defaultValue={values.current.currentPassword}
autoComplete="password"
returnKeyLabel="Next"
keyboardType="number-pad"
keyboardType={keyboardType === "pin" ? "number-pad" : "default"}
returnKeyType="next"
secureTextEntry
placeholder={"Current pin"}
secureTextEntry={secureTextEntry}
placeholder={`Current ${keyboardType}`}
/>
) : null}
@@ -153,12 +167,37 @@ export const AppLockPassword = () => {
onSubmit={() => {
confirmPasswordInputRef.current?.focus();
}}
keyboardType="number-pad"
defaultValue={values.current.password}
keyboardType={keyboardType === "pin" ? "number-pad" : "default"}
autoComplete="password"
returnKeyLabel={mode !== "remove" ? "Next" : "Remove"}
returnKeyType={mode !== "remove" ? "next" : "done"}
secureTextEntry
placeholder={mode === "change" ? "New pin" : "Pin"}
secureTextEntry={secureTextEntry}
buttonLeft={
<IconButton
name={keyboardType === "password" ? "numeric" : "keyboard"}
onPress={() => {
setKeyboardType(
keyboardType === "password" ? "pin" : "password"
);
setSecureTextEntry(false);
setImmediate(() => {
setSecureTextEntry(true);
});
}}
customStyle={{
width: 25,
height: 25,
marginRight: 5
}}
size={SIZE.lg}
/>
}
placeholder={
mode === "change"
? `New ${keyboardType}`
: `${keyboardType === "pin" ? "Pin" : "Password"}`
}
/>
{mode !== "remove" ? (
@@ -171,14 +210,15 @@ export const AppLockPassword = () => {
onSubmit={() => {
confirmPasswordInputRef.current?.focus();
}}
keyboardType="number-pad"
defaultValue={values.current.confirmPassword}
keyboardType={keyboardType === "pin" ? "number-pad" : "default"}
customValidator={() => values.current.password || ""}
validationType="confirmPassword"
autoComplete="password"
returnKeyLabel="Done"
returnKeyType="done"
secureTextEntry
placeholder={"Confirm pin"}
secureTextEntry={secureTextEntry}
placeholder={`Confirm ${keyboardType}`}
/>
) : null}
</View>
@@ -198,7 +238,11 @@ export const AppLockPassword = () => {
if (values.current.password !== values.current.confirmPassword) {
ToastManager.error(
new Error("Pin does not match"),
new Error(
`${
keyboardType === "pin" ? "Pin" : "Password"
} does not match`
),
undefined,
"local"
);
@@ -222,7 +266,11 @@ export const AppLockPassword = () => {
if (values.current.password !== values.current.confirmPassword) {
ToastManager.error(
new Error("Pin does not match"),
new Error(
`${
keyboardType === "pin" ? "Pin" : "Password"
} does not match`
),
undefined,
"local"
);
@@ -235,7 +283,9 @@ export const AppLockPassword = () => {
if (!isCurrentPasswordCorrect) {
ToastManager.error(
new Error("Pin incorrect"),
new Error(
`${keyboardType === "pin" ? "Pin" : "Password"} incorrect`
),
undefined,
"local"
);
@@ -259,13 +309,23 @@ export const AppLockPassword = () => {
);
if (!isCurrentPasswordCorrect) {
ToastManager.error(new Error("Pin incorrect"), "local");
ToastManager.error(
new Error(
`${keyboardType === "pin" ? "Pin" : "Password"} incorrect`
),
"local"
);
return;
}
clearAppLockVerificationCipher();
SettingsService.setProperty("appLockHasPasswordSecurity", false);
}
SettingsService.setProperty(
"applockKeyboardType",
keyboardType === "password" ? "default" : "numeric"
);
close();
}}
positiveTitle="Save"

View File

@@ -18,18 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/dist/common";
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useState } from "react";
import { Platform, View } from "react-native";
import { db } from "../../../common/database";
import { MMKV } from "../../../common/database/mmkv";
import BackupService from "../../../services/backup";
import {
ToastManager,
eSendEvent,
presentSheet,
ToastManager
presentSheet
} from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { useThemeColors } from "@notesnook/theme";
import { eCloseSheet } from "../../../utils/events";
import { sleep } from "../../../utils/time";
import { Dialog } from "../../dialog";
@@ -122,10 +122,13 @@ export default function Migrate() {
<View
style={{
paddingHorizontal: 12,
paddingTop: 12
paddingTop: 12,
height: "100%",
alignItems: "center",
justifyContent: "center"
}}
>
{!loading ? (
{!loading && !error ? (
<DialogHeader
title="Save a backup of your notes"
centered
@@ -140,33 +143,39 @@ export default function Migrate() {
<>
<View
style={{
width: 200,
height: 100,
alignSelf: "center",
justifyContent: "center"
}}
>
<ProgressBarComponent
height={5}
width={200}
animated={true}
useNativeDriver
indeterminate
unfilledColor={colors.secondary.background}
color={colors.primary.accent}
borderWidth={0}
/>
<Paragraph
style={{
marginTop: 5,
marginBottom: 10,
textAlign: "center"
}}
>
Updating {progress ? progress?.collection : null}
Migrating database{progress ? `(${progress?.collection})` : null}
{progress ? `(${progress.current}/${progress.total}) ` : null}...
please wait
</Paragraph>
<View
style={{
width: 200
}}
>
<ProgressBarComponent
height={5}
width={200}
animated={true}
useNativeDriver
indeterminate
unfilledColor={colors.secondary.background}
color={colors.primary.accent}
borderWidth={0}
/>
</View>
</View>
</>
) : error ? (
@@ -198,6 +207,7 @@ export default function Migrate() {
width={250}
onPress={async () => {
MMKV.clearStore();
await db.reset();
setReset(true);
}}
style={{

View File

@@ -120,7 +120,8 @@ const SheetWrapper = ({
width: 100,
backgroundColor: colors.secondary.background
}}
drawUnderStatusBar={false}
statusBarTranslucent
drawUnderStatusBar={true}
containerStyle={style}
gestureEnabled={gestureEnabled}
initialOffsetFromBottom={1}

View File

@@ -57,10 +57,11 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
return;
}
if (!item.property) return;
item.onChange?.(!settings[item.property]);
const nextValue = !settings[item.property];
SettingsService.set({
[item.property]: !settings[item.property]
[item.property]: nextValue
});
setImmediate(() => item.onChange?.(nextValue));
};
const styles =

View File

@@ -799,19 +799,25 @@ export const settingsGroups: SettingSection[] = [
property: "appLockEnabled",
onChange: async () => {
if (!SettingsService.getProperty("appLockEnabled")) {
const keyboardType = SettingsService.getProperty(
"applockKeyboardType"
);
if (SettingsService.getProperty("appLockHasPasswordSecurity")) {
presentDialog({
title: "Verify it's you",
input: true,
inputPlaceholder: "Enter app lock pin",
paragraph:
"Please enter your app lock pin to disable app lock",
inputPlaceholder: `Enter app lock ${
keyboardType === "numeric" ? "pin" : "password"
}`,
paragraph: `Please enter your app lock ${
keyboardType === "numeric" ? "pin" : "password"
} to disable app lock`,
positiveText: "Disable",
secureTextEntry: true,
negativeText: "Cancel",
positivePress: async (value) => {
try {
let verified = await validateAppLockPassword(value);
const verified = await validateAppLockPassword(value);
if (!verified) {
SettingsService.setProperty("appLockEnabled", true);
return false;
@@ -892,8 +898,8 @@ export const settingsGroups: SettingSection[] = [
},
{
id: "app-lock-pin",
name: "Setup app lock pin",
description: "Set up a new pin for app lock",
name: "Setup app lock password",
description: "Setup a new app lock password for app lock",
hidden: () => {
return !!SettingsService.getProperty(
"appLockHasPasswordSecurity"

View File

@@ -80,6 +80,7 @@ export type Settings = {
appLockHasPasswordSecurity?: boolean;
biometricsAuthEnabled?: boolean;
backgroundSync?: boolean;
applockKeyboardType: "numeric" | "default";
};
type DimensionsType = {
@@ -122,6 +123,7 @@ export interface SettingStore extends State {
const { width, height } = Dimensions.get("window");
export const defaultSettings: SettingStore["settings"] = {
applockKeyboardType: "numeric",
appLockTimer: 0,
showToolbarOnTop: false,
showKeyboardOnOpen: false,

View File

@@ -48,5 +48,6 @@ hermesEnabled=true
# fdroid
fdroidBuild=false
org.gradle.java.home=/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home
# -DSQLITE_USER_AUTHENTICATION=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1
quickSqliteFlags=-DSQLITE3MC_OMIT_AES_HARDWARE_SUPPORT -DHAVE_CIPHER_AES_128_CBC=0 -DHAVE_CIPHER_AES_256_CBC=0 -DHAVE_CIPHER_SQLCIPHER=0 -DHAVE_CIPHER_RC4=0 -DHAVE_CIPHER_CHACHA20=1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_USE_ALLOCA=1

View File

@@ -72,7 +72,9 @@ const EXTRA_ICON_NAMES = [
"qrcode",
"text",
"cloud",
"restore"
"restore",
"keyboard",
"numeric"
];
const __filename = fileURLToPath(import.meta.url);