-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+ getMessage());
+ }
+}
\ No newline at end of file
diff --git a/langs/en/login.json b/langs/en/login.json
new file mode 100644
index 0000000..9add11c
--- /dev/null
+++ b/langs/en/login.json
@@ -0,0 +1,12 @@
+{
+ "Login to {app}": "Login to {app}",
+ "Username not found.": "Username not found.",
+ "Password for {user}": "Password for {user}",
+ "Password incorrect.": "Password incorrect.",
+ "Two-factor code": "Two-factor code",
+ "Code incorrect.": "Code incorrect.",
+ "Current password for {user}": "Current password for {user}",
+ "New password": "New password",
+ "New password (again)": "New password (again)",
+ "Fill in all three boxes.": "Fill in all three boxes."
+}
diff --git a/langs/en/titles.json b/langs/en/titles.json
index ea261ca..d1be568 100644
--- a/langs/en/titles.json
+++ b/langs/en/titles.json
@@ -4,5 +4,6 @@
"account options": "Account options",
"sync": "Sync settings",
"settings": "Settings",
- "account": "Account"
+ "account": "Account",
+ "Home": "Home"
}
diff --git a/lib/LoginKeys.lib.php b/lib/LoginKeys.lib.php
new file mode 100644
index 0000000..d445568
--- /dev/null
+++ b/lib/LoginKeys.lib.php
@@ -0,0 +1,33 @@
+has('userloginkeys', ['key' => $code]));
+
+ $database->insert('userloginkeys', ['key' => $code, 'expires' => date("Y-m-d H:i:s", time() + 600), 'appname' => $appname]);
+
+ return $code;
+ }
+
+ public static function getuid(string $code): int {
+ global $database;
+ if (!$database->has('userloginkeys', ["AND" => ['key' => $code, 'uid[!]' => null]])) {
+ throw new Exception();
+ }
+
+ $uid = $database->get('userloginkeys', 'uid', ['key' => $code]);
+
+ return $uid;
+ }
+
+}
diff --git a/login/index.php b/login/index.php
new file mode 100644
index 0000000..2aaca5d
--- /dev/null
+++ b/login/index.php
@@ -0,0 +1,150 @@
+delete("userloginkeys", ["expires[<]" => date("Y-m-d H:i:s")]);
+
+if (!$database->has("userloginkeys", ["AND" => ["key" => $_GET["code"]], "expires[>]" => date("Y-m-d H:i:s"), "uid" => null])) {
+ header("Location: $_GET[redirect]");
+ die("Invalid auth code.");
+}
+
+$APPNAME = $database->get("userloginkeys", "appname", ["key" => $_GET["code"]]);
+
+if (empty($_SESSION['thisstep'])) {
+ $_SESSION['thisstep'] = "username";
+}
+
+$error = "";
+
+function sendUserBack($code, $url, $uid) {
+ global $database;
+ $database->update("userloginkeys", ["uid" => $uid], ["key" => $code]);
+ header("Location: $url");
+ die("
Click here");
+}
+
+if (!empty($_SESSION['check'])) {
+ switch ($_SESSION['check']) {
+ case "username":
+ if (empty($_POST['username'])) {
+ $_SESSION['thisstep'] = "username";
+ break;
+ }
+ $user = User::byUsername($_POST['username']);
+ if ($user->exists()) {
+ $_SESSION['login_uid'] = $user->getUID();
+ switch ($user->getStatus()->get()) {
+ case AccountStatus::LOCKED_OR_DISABLED:
+ $error = $Strings->get("account locked", false);
+ break;
+ case AccountStatus::TERMINATED:
+ $error = $Strings->get("account terminated", false);
+ break;
+ case AccountStatus::ALERT_ON_ACCESS:
+ $mail_resp = $user->sendAlertEmail();
+ case AccountStatus::NORMAL:
+ $_SESSION['thisstep'] = "password";
+ break;
+ case AccountStatus::CHANGE_PASSWORD:
+ $_SESSION['thisstep'] = "change_password";
+ break;
+ }
+ } else {
+ $error = $Strings->get("Username not found.", false);
+ }
+ break;
+ case "password":
+ if (empty($_POST['password'])) {
+ $_SESSION['thisstep'] = "password";
+ break;
+ }
+ if (empty($_SESSION['login_uid'])) {
+ $_SESSION['thisstep'] = "username";
+ break;
+ }
+ $user = new User($_SESSION['login_uid']);
+ if ($user->checkPassword($_POST['password'])) {
+ $_SESSION['login_pwd'] = true;
+ if ($user->has2fa()) {
+ $_SESSION['thisstep'] = "totp";
+ } else {
+ sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
+ }
+ } else {
+ $error = $Strings->get("Password incorrect.", false);
+ }
+ break;
+ case "change_password":
+ if (empty($_POST['oldpassword']) || empty($_POST['newpassword']) || empty($_POST['newpassword2'])) {
+ $_SESSION['thisstep'] = "change_password";
+ $error = $Strings->get("Fill in all three boxes.", false);
+ break;
+ }
+
+ $user = new User($_SESSION['login_uid']);
+ try {
+ $result = $user->changePassword($_POST['oldpassword'], $_POST['newpassword'], $_POST['newpassword2']);
+
+ if ($result === TRUE) {
+ if ($user->has2fa()) {
+ $_SESSION['thisstep'] = "totp";
+ } else {
+ sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
+ }
+ }
+ } catch (PasswordMatchException $e) {
+ $error = $Strings->get(MESSAGES["passwords_same"]["string"], false);
+ } catch (PasswordMismatchException $e) {
+ $error = $Strings->get(MESSAGES["new_password_mismatch"]["string"], false);
+ } catch (IncorrectPasswordException $e) {
+ $error = $Strings->get(MESSAGES["old_password_mismatch"]["string"], false);
+ } catch (WeakPasswordException $e) {
+ $error = $Strings->get(MESSAGES["weak_password"]["string"], false);
+ }
+ break;
+ case "totp":
+ if (empty($_POST['totp']) || empty($_SESSION['login_uid'])) {
+ $_SESSION['thisstep'] = "username";
+ break;
+ }
+ $user = new User($_SESSION['login_uid']);
+ if ($user->check2fa($_POST['totp'])) {
+ sendUserBack($_GET['code'], $_GET['redirect'], $_SESSION['login_uid']);
+ } else {
+ $error = $Strings->get("Code incorrect.", false);
+ }
+ break;
+ }
+}
+
+include __DIR__ . "/parts/header.php";
+
+switch ($_SESSION['thisstep']) {
+ case "username":
+ require __DIR__ . "/parts/username.php";
+ break;
+ case "password":
+ require __DIR__ . "/parts/password.php";
+ break;
+ case "change_password":
+ require __DIR__ . "/parts/change_password.php";
+ break;
+ case "totp":
+ require __DIR__ . "/parts/totp.php";
+ break;
+}
+
+include __DIR__ . "/parts/footer.php";
diff --git a/login/parts/change_password.php b/login/parts/change_password.php
new file mode 100644
index 0000000..2402bb9
--- /dev/null
+++ b/login/parts/change_password.php
@@ -0,0 +1,51 @@
+getUsername();
+?>
+
+
\ No newline at end of file
diff --git a/login/parts/footer.php b/login/parts/footer.php
new file mode 100644
index 0000000..2896d7f
--- /dev/null
+++ b/login/parts/footer.php
@@ -0,0 +1,15 @@
+
+
+