Skip to content

Commit

Permalink
encryption system developed & import and export developed
Browse files Browse the repository at this point in the history
  • Loading branch information
matteo-convertino committed Oct 18, 2023
1 parent 258b385 commit 1e2f4c2
Show file tree
Hide file tree
Showing 27 changed files with 262 additions and 100,192 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This way, the migration from Google Authenticator to OTP Manager will be quick a
* [Official Android App](https://play.google.com/store/apps/details?id=com.convertino.otp_manager)
]]>
</description>
<version>0.2.0</version>
<version>0.3.0</version>
<licence>agpl</licence>
<author mail="[email protected]" homepage="https://www.convertino.cloud">Matteo Convertino</author>
<namespace>OtpManager</namespace>
Expand Down
99,757 changes: 3 additions & 99,754 deletions js/otpmanager-main.js

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions js/otpmanager-main.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/

/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */

/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @preserve
* Counter block mode compatible with Dr Brian Gladman fileenc.c
* derived from CryptoJS.mode.CTR
* Jan Hruby [email protected]
*/
2 changes: 1 addition & 1 deletion js/otpmanager-main.js.map

Large diffs are not rendered by default.

38 changes: 22 additions & 16 deletions lib/Controller/AccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use OCA\OtpManager\Utils\Encryption;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;

class AccountController extends Controller
Expand Down Expand Up @@ -78,8 +77,12 @@ private function validateFields($data)
$errors["digits"] = "Digits must be one of those listed";

$regexBase32 = '/^[A-Z2-7]+=*$/i';

$data["secret"] = $this->encryption->decrypt($data["secret"], $this->userId);

if (!array_key_exists("secret", $data) || strlen($data["secret"]) < 16 || strlen($data["secret"]) > 256)
if($data["secret"] === false)
$errors["secret"] = "Not able to decrypt secret key";
else if (!array_key_exists("secret", $data) || strlen($data["secret"]) < 16 || strlen($data["secret"]) > 256)
$errors["secret"] = "Secret key must be 16-256 characters long";
else if (!preg_match($regexBase32, $data["secret"]))
$errors["secret"] = "Secret key is not Base32-encodable";
Expand All @@ -104,19 +107,15 @@ private function convertAlgorithmToInt($algorithm)
* @NoAdminRequired
*/
public function create($data)
{
{
$errors = $this->validateFields($data);

if (count($errors) > 0) {
return $errors;
} else {
$data["secret"] = strtoupper($data["secret"]);
$encrypted_secret = $this->encryption->encrypt($data["secret"], $this->userId);
if ($encrypted_secret === false) return (new Response())->setStatus(403);

$data["algorithm"] = $this->convertAlgorithmToInt($data["algorithm"]);

$account = $this->accountMapper->find("secret", $encrypted_secret, $this->userId);
$account = $this->accountMapper->find("secret", $data["secret"], $this->userId);

if ($account != null && $account->getDeletedAt() == null) {
$errors["secret"] = "This secret key already exists";
Expand All @@ -133,7 +132,7 @@ public function create($data)
if ($account == null) {
$account = new Account();

$account->setSecret($encrypted_secret);
$account->setSecret($data["secret"]);
$account->setName($data["name"]);
$account->setIssuer($data["issuer"]);
$account->setDigits($data["digits"]);
Expand Down Expand Up @@ -274,7 +273,13 @@ private function compareAccounts(array $localAccounts)
foreach ($localAccounts as $localAccount) {
$serverAccount = $this->accountMapper->find("secret", $localAccount["secret"], $this->userId);

if ($localAccount["isNew"]) {
if ($localAccount["deleted"]) {
if($serverAccount != null) {
$serverAccount->setPosition(null);
$serverAccount->setDeletedAt(date("Y-m-d H:i:s"));
$this->accountMapper->update($serverAccount);
}
} else if ($localAccount["isNew"]) {
$position = $this->adjustPosition($localAccount["position"]);

if ($serverAccount != null) {
Expand Down Expand Up @@ -314,10 +319,6 @@ private function compareAccounts(array $localAccounts)
}
} else if ($serverAccount == null || $serverAccount->getDeletedAt() != null) {
array_push($ris["toDelete"], $localAccount["id"]);
} else if ($localAccount["deleted"]) {
$serverAccount->setPosition(null);
$serverAccount->setDeletedAt(date("Y-m-d H:i:s"));
$this->accountMapper->update($serverAccount);
}

if ($localAccount["toUpdate"] && $serverAccount->getDeletedAt() == null) {
Expand Down Expand Up @@ -377,16 +378,17 @@ private function compareAccounts(array $localAccounts)
* @NoAdminRequired
* @NoCSRFRequired
*/
public function sync(array $data)
public function sync(array $accounts)
{
return $this->compareAccounts($data["accounts"]);
return $this->compareAccounts($accounts);
}

/**
* @NoAdminRequired
*/
public function import(array $data, string | null $password)
{
if(!array_key_exists("accounts", $data)) return new JSONResponse(["error" => "Invalid JSON file"], 400);
if (array_key_exists("iv", $data) && empty($password)) return new JSONResponse(["error" => "Password is required to decrypt accounts"], 400);

foreach ($data["accounts"] as $importedAccount) {
Expand All @@ -395,6 +397,10 @@ public function import(array $data, string | null $password)
if ($importedAccount["secret"] === false) return new JSONResponse(["error" => "Password incorrect"], 400);
}

$importedAccount["secret"] = strtoupper($importedAccount["secret"]);
$importedAccount["secret"] = $this->encryption->encrypt($importedAccount["secret"], $this->userId);
if ($importedAccount === false) return new JsonResponse([], 403);

$this->create($importedAccount);
}

Expand Down
10 changes: 5 additions & 5 deletions lib/Controller/PasswordController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@

namespace OCA\OtpManager\Controller;

use OCA\OtpManager\Db\AccountMapper;
use OCA\OtpManager\Db\Setting;
use OCA\OtpManager\Db\SettingMapper;
use OCA\OtpManager\Utils\Encryption;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;


Expand Down Expand Up @@ -103,8 +100,10 @@ public function update(string $oldPassword, string $newPassword): JSONResponse

$setting = $this->settingMapper->find($this->userId);

//return new JSONResponse(["a" => hash_equals($setting->getPassword(), hash("sha256", $oldPassword)), "b" => $oldPassword, "c" => $setting->getPassword(), "d" => hash("sha256", $oldPassword)]);

if (is_null($setting->getPassword())) return new JSONResponse(["error" => "No password set yet"], 400);
else if (hash_equals($setting->getPassword(), hash("sha256", $oldPassword, true))) return new JSONResponse(["error" => "The old password is incorrect"], 400);
else if (!hash_equals($setting->getPassword(), hash("sha256", $oldPassword))) return new JSONResponse(["error" => "The old password is incorrect"], 400);

$newPassword = hash("sha256", $newPassword);

Expand All @@ -121,11 +120,12 @@ public function update(string $oldPassword, string $newPassword): JSONResponse

/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function check(string $password): JSONResponse
{
$setting = $this->settingMapper->find($this->userId);
if (is_null($setting->getPassword())) return new JSONResponse(["error" => "No password set yet"], 400);
if (is_null($setting) || is_null($setting->getPassword())) return new JSONResponse(["error" => "No password set yet"], 400);

if (hash_equals($setting->getPassword(), hash("sha256", $password))) {
return new JSONResponse(["iv" => $setting->getIv()]);
Expand Down
8 changes: 4 additions & 4 deletions src/js/OtpLayout.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useState, useEffect, useContext } from "react";
import React, { useContext, useEffect, useState } from "react";

import { Box } from "@mantine/core";

import { MantineProvider, createEmotionCache } from "@mantine/core";
import { NotificationsProvider } from "@mantine/notifications";
import { MantineProvider } from "@mantine/core";
import { ModalsProvider } from "@mantine/modals";
import { Password } from "./Password";
import { NotificationsProvider } from "@mantine/notifications";
import { Password } from "./utils/Password";

import { UserSettingContext } from "./utils/UserSettingProvider";

Expand Down
10 changes: 0 additions & 10 deletions src/js/appShell/AppShell.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export default function MainAppShell({ children }) {
const [showApps, setShowApps] = useState(false);
const [showChangePassword, setShowChangePassword] = useState(false);
const [showImportExport, setShowImportExport] = useState(false);
/*const [showExportAccounts, setShowExportAccounts] = useState(false);
const [showImportAccounts, setShowImportAccounts] = useState(false);*/

// user settings
const [showSettings, setShowSettings] = useState(false);
Expand All @@ -35,8 +33,6 @@ export default function MainAppShell({ children }) {
setShowSettings={setShowSettings}
setShowApps={setShowApps}
setShowChangePassword={setShowChangePassword}
/*setShowExportAccounts={setShowExportAccounts}
setShowImportAccounts={setShowImportAccounts}*/
setShowImportExport={setShowImportExport}
/>

Expand All @@ -50,8 +46,6 @@ export default function MainAppShell({ children }) {
setShowSettings={setShowSettings}
setShowChangePassword={setShowChangePassword}
setShowApps={setShowApps}
/*setShowExportAccounts={setShowExportAccounts}
setShowImportAccounts={setShowImportAccounts}*/
setShowImportExport={setShowImportExport}
/>
}
Expand All @@ -71,10 +65,6 @@ export default function MainAppShell({ children }) {
setShowApps={setShowApps}
setShowChangePassword={setShowChangePassword}
showChangePassword={showChangePassword}
/*showExportAccounts={showExportAccounts}
setShowExportAccounts={setShowExportAccounts}
showImportAccounts={showImportAccounts}
setShowImportAccounts={setShowImportAccounts}*/
showImportExport={showImportExport}
setShowImportExport={setShowImportExport}
/>
Expand Down
20 changes: 2 additions & 18 deletions src/js/appShell/Content.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,8 @@ export function AppShellContent({
setShowApps,
setShowChangePassword,
showChangePassword,
/*setShowExportAccounts,
showExportAccounts,
setShowImportAccounts,
showImportAccounts,*/
showImportExport,
setShowImportExport
setShowImportExport,
}) {
const [showCreateAccount, setShowCreateAccount] = useState(false);
const [showEditOtpAccount, setShowEditOtpAccount] = useState(false);
Expand Down Expand Up @@ -118,19 +114,7 @@ export function AppShellContent({
setFetchState={setFetchState}
/>

{/*<ExportAccounts
setShowExportAccounts={setShowExportAccounts}
showExportAccounts={showExportAccounts}
accounts={accounts}
/>
<ImportAccounts
setShowImportAccounts={setShowImportAccounts}
showImportAccounts={showImportAccounts}
setAccounts={setAccounts}
setFetchState={setFetchState}
/>*/}
<ImportExport
<ImportExport
showImportExport={showImportExport}
setShowImportExport={setShowImportExport}
accounts={accounts}
Expand Down
Loading

0 comments on commit 1e2f4c2

Please sign in to comment.