Skip to content

Commit

Permalink
Add minimal anti-bruteforce measures
Browse files Browse the repository at this point in the history
  • Loading branch information
serjonya-trili committed Oct 21, 2024
1 parent ae08e86 commit 4baf710
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
3 changes: 2 additions & 1 deletion packages/crypto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
]
},
"dependencies": {
"@taquito/utils": "^20.0.1"
"@taquito/utils": "^20.0.1",
"date-fns": "^4.1.0"
}
}
25 changes: 24 additions & 1 deletion packages/crypto/src/AES.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { buf2hex, hex2Bytes } from "@taquito/utils";
import { differenceInMinutes } from "date-fns";

import { AES_MODE } from "./AES_MODE";
import { derivePasswordBasedKeyV1, derivePasswordBasedKeyV2 } from "./KDF";
Expand Down Expand Up @@ -33,13 +34,25 @@ export const encrypt = async (data: string, password: string): Promise<Encrypted

type DecryptMode = "V1" | "V2";

const TOO_MANY_ATTEMPTS_ERROR =
"Too many unsuccessful attempts. Please wait a few minutes before trying again.";

export const decrypt = async (
data: EncryptedData,
password: string,
mode: DecryptMode = "V2"
): Promise<string> => {
const { iv, salt, data: encrypted } = data;
try {
if (getAttemptsCount() >= 3) {
const minutesSinceLastAttempt = differenceInMinutes(
new Date(),
new Date(localStorage.getItem("failedDecryptTime")!)
);
if (minutesSinceLastAttempt < 5) {
throw new Error(TOO_MANY_ATTEMPTS_ERROR);
}
}
const derivedKey =
mode === "V2"
? await derivePasswordBasedKeyV2(password, hex2Bytes(salt))
Expand All @@ -52,8 +65,18 @@ export const decrypt = async (
derivedKey,
hex2Bytes(encrypted)
);
setAttemptsCount(0);
localStorage.removeItem("failedDecryptTime");
return Buffer.from(decrypted).toString("utf-8");
} catch (_) {
} catch (err: any) {
if (err?.message === TOO_MANY_ATTEMPTS_ERROR) {
throw err;
}
setAttemptsCount(getAttemptsCount() + 1);
localStorage.setItem("failedDecryptTime", new Date().toISOString());
throw new Error("Error decrypting data: Invalid password");
}
};

const getAttemptsCount = () => Number(localStorage.getItem("passwordAttempts") || 0);
const setAttemptsCount = (count: number) => localStorage.setItem("passwordAttempts", String(count));
7 changes: 5 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4baf710

Please sign in to comment.