diff --git a/src/Settings/index.tsx b/src/Settings/index.tsx index 903425c..579193f 100644 --- a/src/Settings/index.tsx +++ b/src/Settings/index.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from "react"; +import * as Etebase from "etebase"; import { useSelector, useDispatch } from "react-redux"; import Select from "@material-ui/core/Select"; @@ -13,12 +14,17 @@ import Switch from "@material-ui/core/Switch"; import InputLabel from "@material-ui/core/InputLabel"; import { StoreState } from "../store"; -import { setSettings } from "../store/actions"; +import { setSettings, login, pushMessage } from "../store/actions"; import Container from "../widgets/Container"; import AppBarOverride from "../widgets/AppBarOverride"; import PrettyFingerprint from "../widgets/PrettyFingerprint"; import { useCredentials } from "../credentials"; +import { Button } from "@material-ui/core"; +import ConfirmationDialog from "../widgets/ConfirmationDialog"; +import PasswordField from "../widgets/PasswordField"; +import Alert from "@material-ui/lab/Alert"; +import { PASSWORD_MIN_LENGTH, startTask, enforcePasswordRules } from "../helpers"; function SecurityFingerprint() { const etebase = useCredentials()!; @@ -35,6 +41,133 @@ function SecurityFingerprint() { ); } +interface ChangePasswordFormErrors { + oldPassword?: string; + newPassword?: string; + + general?: string; +} + +function ChangePassword() { + const etebase = useCredentials()!; + const dispatch = useDispatch(); + const [showDialog, setShowDialog] = React.useState(false); + const [oldPassword, setOldPassword] = React.useState(""); + const [newPassword, setNewPassword] = React.useState(""); + const [errors, setErrors] = React.useState({}); + + const styles = { + infoAlert: { + marginTop: 20, + }, + textField: { + marginTop: 20, + width: "18em", + }, + }; + + function handleInputChange(func: (value: string) => void) { + return (event: React.ChangeEvent) => { + func(event.target.value); + }; + } + + async function onChangePassword() { + try { + const fieldNotEmpty = "Password can't be empty."; + const errors: ChangePasswordFormErrors = {}; + if (!oldPassword) { + errors.oldPassword = fieldNotEmpty; + } + if (!newPassword) { + errors.newPassword = fieldNotEmpty; + } else { + const passwordRulesError = enforcePasswordRules(newPassword); + if (passwordRulesError) { + errors.newPassword = passwordRulesError; + } + } + + setErrors(errors); + if (Object.keys(errors).length > 0) { + return; + } + + await startTask(async () => { + const serverUrl = etebase.serverUrl; + const username = etebase.user.username; + try { + const etebase = await Etebase.Account.login(username, oldPassword, serverUrl); + await etebase.logout(); + } catch (e) { + if (e instanceof Etebase.UnauthorizedError) { + setErrors({ oldPassword: "Error: wrong encryption password." }); + } else { + setErrors({ oldPassword: e.toString() }); + } + return; + } + + try { + await etebase.changePassword(newPassword); + dispatch(login(etebase)); + dispatch(pushMessage({ message: "Password successfully changed.", severity: "success" })); + setShowDialog(false); + } catch (e) { + setErrors({ newPassword: e.toString() }); + } + }); + } finally { + // Cleanup + } + } + + return ( + <> +

+ Change your password by clicking here; +

+ + setShowDialog(false)} + > + + + {errors.general && ( + {errors.general} + )} + + + Please make sure you remember your password, as it can't be recovered if lost! + + + + ); +} + export default React.memo(function Settings() { const etebase = useCredentials(); const dispatch = useDispatch(); @@ -58,6 +191,9 @@ export default React.memo(function Settings() {

Account

Security Fingerprint

+ +

Password

+ )}