mobile: improve verification flow before changing app lock

This commit is contained in:
Ammar Ahmed
2024-02-15 16:07:33 +05:00
parent f8c8a2b913
commit 20f322a98d
9 changed files with 127 additions and 123 deletions

View File

@@ -43,6 +43,7 @@ const DialogProvider = () => {
return (
<>
<AppLockPassword />
<LoadingDialog />
<Dialog context="global" />
<PremiumDialog colors={colors} />
@@ -61,7 +62,6 @@ const DialogProvider = () => {
<SessionExpired />
<PDFPreview />
<JumpToSectionDialog />
<AppLockPassword />
</>
);
};

View File

@@ -91,7 +91,7 @@ export const AppLockPassword = () => {
setVisible(false);
};
return (
return !visible ? null : (
<BaseDialog
onShow={async () => {
await sleep(100);

View File

@@ -17,9 +17,13 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { presentDialog } from "../../components/dialog/functions";
import { ToastManager } from "../../services/event-manager";
import { db } from "../../common/database";
import { validateAppLockPassword } from "../../common/database/encryption";
import { presentDialog } from "../../components/dialog/functions";
import BiometicService from "../../services/biometrics";
import { ToastManager } from "../../services/event-manager";
import SettingsService from "../../services/settings";
import { useUserStore } from "../../stores/use-user-store";
import { sleep } from "../../utils/time";
export async function verifyUser(
@@ -69,3 +73,54 @@ export async function verifyUser(
}
});
}
export async function verifyUserWithApplock() {
const keyboardType = SettingsService.getProperty("applockKeyboardType");
return new Promise((resolve) => {
if (SettingsService.getProperty("appLockHasPasswordSecurity")) {
presentDialog({
title: "Verify it's you",
input: true,
inputPlaceholder: `Enter app lock ${
keyboardType === "numeric" ? "pin" : "password"
}`,
paragraph: `Please enter your app lock ${
keyboardType === "numeric" ? "pin" : "password"
}`,
positiveText: "Disable",
secureTextEntry: true,
negativeText: "Cancel",
positivePress: async (value) => {
try {
const verified = await validateAppLockPassword(value);
resolve(verified);
} catch (e) {
resolve(false);
}
}
});
} else {
BiometicService.isBiometryAvailable().then((available) => {
if (available) {
BiometicService.validateUser("Verify it's you").then((verified) => {
resolve(verified);
});
} else if (useUserStore.getState().user) {
let verified = false;
verifyUser(
null,
() => {
resolve(true);
},
false,
() => {
resolve(verified);
}
);
} else {
resolve(true);
}
});
}
});
}

View File

@@ -40,6 +40,7 @@ interface PickerOptions<T> {
premium?: boolean;
onCheckOptionIsPremium?: (item: T) => boolean;
requiresVerification?: () => boolean;
onVerify?: () => Promise<boolean>;
}
export function SettingsPicker<T>({
@@ -51,7 +52,8 @@ export function SettingsPicker<T>({
getItemKey,
premium,
onCheckOptionIsPremium = () => true,
requiresVerification = () => false
requiresVerification = () => false,
onVerify
}: PickerOptions<T>) {
const { colors } = useThemeColors("contextMenu");
const menuRef = useRef<any>();
@@ -105,6 +107,7 @@ export function SettingsPicker<T>({
anchor={
<PressableButton
onPress={async () => {
if (onVerify && !(await onVerify())) return;
menuRef.current?.show();
}}
type="grayBg"

View File

@@ -27,6 +27,7 @@ import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/dist/common";
import dayjs from "dayjs";
import { useUserStore } from "../../../stores/use-user-store";
import { verifyUserWithApplock } from "../functions";
export const FontPicker = createSettingsPicker({
getValue: () => useSettingStore.getState().settings.defaultFontFamily,
@@ -156,5 +157,7 @@ export const ApplockTimerPicker = createSettingsPicker({
getItemKey: (item) => item.toString(),
options: [-1, 0, 1, 5, 15, 30],
compareValue: (current, item) => current === item,
premium: true
onVerify: () => {
return verifyUserWithApplock();
}
});

View File

@@ -104,17 +104,26 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
borderRadius: 0,
...styles
}}
onPress={() => {
onPress={async () => {
switch (item.type) {
case "screen":
navigation.dispatch(StackActions.push("SettingsGroup", item));
useNavigationStore.getState().update("Settings");
{
if (item.onVerify && !(await item.onVerify())) return;
navigation.dispatch(StackActions.push("SettingsGroup", item));
useNavigationStore.getState().update("Settings");
}
break;
case "switch":
onChangeSettings();
{
if (item.onVerify && !(await item.onVerify())) return;
onChangeSettings();
}
break;
default:
item.modifer && item.modifer(current);
{
if (item.onVerify && !(await item.onVerify())) return;
item.modifer && item.modifer(current);
}
break;
}
}}

View File

@@ -25,7 +25,6 @@ import { getVersion } from "react-native-device-info";
import * as RNIap from "react-native-iap";
import { enabled } from "react-native-privacy-snapshot";
import { db } from "../../common/database";
import { validateAppLockPassword } from "../../common/database/encryption";
import { MMKV } from "../../common/database/mmkv";
import { AttachmentDialog } from "../../components/attachments";
import { ChangePassword } from "../../components/auth/change-password";
@@ -53,6 +52,7 @@ import PremiumService from "../../services/premium";
import SettingsService from "../../services/settings";
import Sync from "../../services/sync";
import { clearAllStores } from "../../stores";
import { refreshAllStores } from "../../stores/create-db-collection-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
@@ -67,10 +67,9 @@ import { NotesnookModule } from "../../utils/notesnook-module";
import { sleep } from "../../utils/time";
import { MFARecoveryCodes, MFASheet } from "./2fa";
import { useDragState } from "./editor/state";
import { verifyUser } from "./functions";
import { verifyUser, verifyUserWithApplock } from "./functions";
import { SettingSection } from "./types";
import { getTimeLeft } from "./user-section";
import { refreshAllStores } from "../../stores/create-db-collection-store";
type User = any;
export const settingsGroups: SettingSection[] = [
@@ -790,94 +789,33 @@ export const settingsGroups: SettingSection[] = [
icon: "lock",
type: "switch",
property: "appLockEnabled",
onChange: async () => {
onVerify: async () => {
const verified = await verifyUserWithApplock();
if (!verified) return false;
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 ${
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 {
const verified = await validateAppLockPassword(value);
if (!verified) {
SettingsService.setProperty("appLockEnabled", true);
return false;
} else {
SettingsService.setProperty("appLockEnabled", false);
}
} catch (e) {
SettingsService.setProperty("appLockEnabled", true);
return false;
}
}
});
} else {
if (await BiometicService.isBiometryAvailable()) {
const verified = await BiometicService.validateUser(
"Verify it's you"
);
if (!verified) {
SettingsService.setProperty("appLockEnabled", true);
return;
} else {
SettingsService.setProperty("appLockEnabled", false);
}
} else if (useUserStore.getState().user) {
let verified = false;
verifyUser(
null,
() => {
SettingsService.setProperty("appLockEnabled", false);
verified = true;
},
false,
() => {
if (!verified)
SettingsService.setProperty("appLockEnabled", true);
}
);
}
}
return;
}
if (
!(await BiometicService.isBiometryAvailable()) &&
!SettingsService.getProperty("appLockHasPasswordSecurity")
) {
ToastManager.show({
heading: "Biometrics not enrolled",
type: "error",
message:
"To use app lock, you must enable biometrics such as Fingerprint lock or Face ID on your phone."
});
SettingsService.setProperty("appLockEnabled", false);
return;
}
if (!SettingsService.getProperty("appLockHasPasswordSecurity")) {
const verified = await BiometicService.validateUser(
"Verify it's you"
);
if (verified) {
if (
!SettingsService.getProperty("appLockHasPasswordSecurity") &&
(await BiometicService.isBiometryAvailable())
) {
SettingsService.setProperty("biometricsAuthEnabled", true);
} else {
SettingsService.setProperty("appLockEnabled", false);
return;
}
if (
!(await BiometicService.isBiometryAvailable()) &&
!SettingsService.getProperty("appLockHasPasswordSecurity")
) {
ToastManager.show({
heading: "Biometrics not enrolled",
type: "error",
message:
"To use app lock, you must enable biometrics such as Fingerprint lock or Face ID on your phone."
});
return false;
}
}
return verified;
}
},
{
@@ -907,8 +845,12 @@ export const settingsGroups: SettingSection[] = [
"appLockHasPasswordSecurity"
);
},
onVerify: () => {
return verifyUserWithApplock();
},
property: "appLockHasPasswordSecurity",
modifer: () => {
console.log("called modifier..");
AppLockPassword.present("create");
}
},
@@ -962,32 +904,23 @@ export const settingsGroups: SettingSection[] = [
description: "Allow biometric authentication to unlock the app",
type: "switch",
property: "biometricsAuthEnabled",
onChange: async () => {
if (await BiometicService.isBiometryAvailable()) {
const verified = await BiometicService.validateUser(
"Verify it's you"
);
if (!verified) {
SettingsService.setProperty("biometricsAuthEnabled", false);
onVerify: async () => {
const verified = await verifyUserWithApplock();
if (!verified) return false;
if (SettingsService.getProperty("biometricsAuthEnabled")) {
if (
!SettingsService.getProperty("appLockHasPasswordSecurity")
) {
SettingsService.setProperty("appLockEnabled", false);
ToastManager.show({
heading: "App lock disabled",
type: "success"
});
}
} else {
ToastManager.error(
new Error(
"Biometric authentication is unavailable on this device."
)
);
SettingsService.setProperty("biometricsAuthEnabled", false);
}
if (
!SettingsService.getProperty("biometricsAuthEnabled") &&
!SettingsService.getProperty("appLockHasPasswordSecurity")
) {
SettingsService.setProperty("appLockEnabled", false);
ToastManager.show({
heading: "App lock disabled",
type: "success"
});
}
return verified;
},
icon: "fingerprint"
}

View File

@@ -45,6 +45,7 @@ export type SettingSection = {
options?: any[];
minInputValue?: number;
maxInputValue?: number;
onVerify?: () => Promise<boolean>;
};
export type SettingsGroup = {

View File

@@ -154,7 +154,7 @@ async function updateNextBackupTime() {
* @param {string} context
* @returns {Promise<{path?: string, error?: Error}}>
*/
async function run(progress, context) {
async function run(progress, context = "global") {
let androidBackupDirectory = await checkBackupDirExists(false, context);
if (!androidBackupDirectory)
return {