From 0c3e3549b0c0c5a25f32dddba2ec2ae0073ecc30 Mon Sep 17 00:00:00 2001 From: riyu <66673988+riyuzenn@users.noreply.github.com> Date: Wed, 28 Sep 2022 06:15:02 +0800 Subject: [PATCH 1/9] Add confetti animation (#3607) riyuzenn * include confetti sound * include confetti-canvas * include canvas-confetti * include confetti sound * create confetti func * import confetti sound * add confetti * add confetti to daily leaderboard * change confetti color * revert to main color * save exact version * updated confetti parameters added one more color made duration shorter more particles higher spread * removed sound * only showing confetti if user already has a pb (doesn't show on the first pb) * regenerated package lock * not showing confetti if timer is slow Co-authored-by: Miodec --- frontend/package-lock.json | 36 +++++++++++++++++++++++++++--- frontend/package.json | 2 ++ frontend/src/ts/test/result.ts | 34 ++++++++++++++++++++++++++++ frontend/src/ts/test/test-logic.ts | 6 +++++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8616541c3..2040d2fe1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,8 +9,8 @@ "version": "1.14.3", "license": "GPL-3.0", "dependencies": { - "@types/throttle-debounce": "2.1.0", "axios": "0.21.4", + "canvas-confetti": "1.5.1", "chart.js": "3.7.1", "chartjs-adapter-date-fns": "2.0.0", "chartjs-plugin-annotation": "1.4.0", @@ -29,6 +29,7 @@ "throttle-debounce": "3.0.1" }, "devDependencies": { + "@types/canvas-confetti": "1.4.3", "@types/chartjs-plugin-trendline": "1.0.1", "@types/damerau-levenshtein": "1.0.0", "@types/grecaptcha": "3.0.4", @@ -36,6 +37,7 @@ "@types/jquery": "3.5.14", "@types/object-hash": "2.2.1", "@types/select2": "4.0.55", + "@types/throttle-debounce": "2.1.0", "@types/tinycolor2": "1.4.3", "buffer": "6.0.3", "circular-dependency-plugin": "5.2.2", @@ -951,6 +953,12 @@ "@types/node": "*" } }, + "node_modules/@types/canvas-confetti": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.4.3.tgz", + "integrity": "sha512-UwFPTsW1ZwVyo/ETp4hPSikSD7yl2V42E3VWBF5P/0+DHO4iajyceWv7hfNdZ2AX5tkZnuViiBWOqyCPohU2FQ==", + "dev": true + }, "node_modules/@types/chartjs-plugin-trendline": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/chartjs-plugin-trendline/-/chartjs-plugin-trendline-1.0.1.tgz", @@ -1158,7 +1166,8 @@ "node_modules/@types/throttle-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz", - "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==" + "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==", + "dev": true }, "node_modules/@types/tinycolor2": { "version": "1.4.3", @@ -2548,6 +2557,15 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/canvas-confetti": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.5.1.tgz", + "integrity": "sha512-Ncz+oZJP6OvY7ti4E1slxVlyAV/3g7H7oQtcCDXgwGgARxPnwYY9PW5Oe+I8uvspYNtuHviAdgA0LfcKFWJfpg==", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, "node_modules/centra": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/centra/-/centra-1.0.1.tgz", @@ -15157,6 +15175,12 @@ "@types/node": "*" } }, + "@types/canvas-confetti": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.4.3.tgz", + "integrity": "sha512-UwFPTsW1ZwVyo/ETp4hPSikSD7yl2V42E3VWBF5P/0+DHO4iajyceWv7hfNdZ2AX5tkZnuViiBWOqyCPohU2FQ==", + "dev": true + }, "@types/chartjs-plugin-trendline": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/chartjs-plugin-trendline/-/chartjs-plugin-trendline-1.0.1.tgz", @@ -15364,7 +15388,8 @@ "@types/throttle-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz", - "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==" + "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==", + "dev": true }, "@types/tinycolor2": { "version": "1.4.3", @@ -16453,6 +16478,11 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001309.tgz", "integrity": "sha512-Pl8vfigmBXXq+/yUz1jUwULeq9xhMJznzdc/xwl4WclDAuebcTHVefpz8lE/bMI+UN7TOkSSe7B7RnZd6+dzjA==" }, + "canvas-confetti": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.5.1.tgz", + "integrity": "sha512-Ncz+oZJP6OvY7ti4E1slxVlyAV/3g7H7oQtcCDXgwGgARxPnwYY9PW5Oe+I8uvspYNtuHviAdgA0LfcKFWJfpg==" + }, "centra": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/centra/-/centra-1.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 633a75ff8..a00b3005a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "npm": "8.1.2" }, "devDependencies": { + "@types/canvas-confetti": "1.4.3", "@types/chartjs-plugin-trendline": "1.0.1", "@types/damerau-levenshtein": "1.0.0", "@types/grecaptcha": "3.0.4", @@ -55,6 +56,7 @@ }, "dependencies": { "axios": "0.21.4", + "canvas-confetti": "1.5.1", "chart.js": "3.7.1", "chartjs-adapter-date-fns": "2.0.0", "chartjs-plugin-annotation": "1.4.0", diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index 84c51e0bc..286d3c9fa 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -18,11 +18,13 @@ import * as AdController from "../controllers/ad-controller"; import * as TestConfig from "./test-config"; import { Chart } from "chart.js"; import { Auth } from "../firebase"; +import * as SlowTimer from "../states/slow-timer"; // eslint-disable-next-line no-duplicate-imports -- need to ignore because eslint doesnt know what import type is import type { PluginChartOptions, ScaleChartOptions } from "chart.js"; import type { AnnotationOptions } from "chartjs-plugin-annotation"; import Ape from "../ape"; +import confetti from "canvas-confetti"; let result: MonkeyTypes.Result; let maxChartVal: number; @@ -343,6 +345,38 @@ export function showCrown(): void { PbCrown.show(); } +export function showConfetti(): void { + if (SlowTimer.get()) return; + const style = getComputedStyle(document.body); + const colors = [ + style.getPropertyValue("--main-color"), + style.getPropertyValue("--text-color"), + style.getPropertyValue("--sub-color"), + ]; + const duration = Date.now() + 125; + + (function f(): void { + confetti({ + particleCount: 5, + angle: 60, + spread: 75, + origin: { x: 0 }, + colors: colors, + }); + confetti({ + particleCount: 5, + angle: 120, + spread: 75, + origin: { x: 1 }, + colors: colors, + }); + + if (Date.now() < duration) { + requestAnimationFrame(f); + } + })(); +} + export function hideCrown(): void { PbCrown.hide(); $("#result .stats .wpm .crown").attr("aria-label", ""); diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 5b766129e..99988e585 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -1738,6 +1738,11 @@ async function saveResult( if (response?.data?.isPb) { //new pb + if ( + DB.getSnapshot()?.personalBests?.[Config.mode]?.[completedEvent.mode2] + ) { + Result.showConfetti(); + } Result.showCrown(); Result.updateCrown(); DB.saveLocalPB( @@ -1768,6 +1773,7 @@ async function saveResult( if (!response?.data?.dailyLeaderboardRank) { $("#result .stats .dailyLeaderboard").addClass("hidden"); } else { + Result.showConfetti(); $("#result .stats .dailyLeaderboard") .css({ maxWidth: "13rem", From 8fca782f301f8c2324be15d28a965c63d8bea81c Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 00:16:45 +0200 Subject: [PATCH 2/9] not using cache if requiring fresh token --- backend/src/middlewares/auth.ts | 2 +- backend/src/utils/auth.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/src/middlewares/auth.ts b/backend/src/middlewares/auth.ts index f1b696946..b1da61912 100644 --- a/backend/src/middlewares/auth.ts +++ b/backend/src/middlewares/auth.ts @@ -144,7 +144,7 @@ async function authenticateWithBearerToken( options: RequestAuthenticationOptions ): Promise { try { - const decodedToken = await verifyIdToken(token); + const decodedToken = await verifyIdToken(token, options.requireFreshToken); if (options.requireFreshToken) { const now = Date.now(); diff --git a/backend/src/utils/auth.ts b/backend/src/utils/auth.ts index 6294c0660..a6222f706 100644 --- a/backend/src/utils/auth.ts +++ b/backend/src/utils/auth.ts @@ -17,7 +17,14 @@ const tokenCache = new LRUCache({ const TOKEN_CACHE_BUFFER = 1000 * 60 * 5; // 5 minutes -export async function verifyIdToken(idToken: string): Promise { +export async function verifyIdToken( + idToken: string, + noCache = false +): Promise { + if (noCache) { + return await admin.auth().verifyIdToken(idToken, true); + } + setTokenCacheLength(tokenCache.size); setTokenCacheSize(tokenCache.calculatedSize ?? 0); From 5836a0a974d07a46e7a6625688e57257f93a00af Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 00:23:25 +0200 Subject: [PATCH 3/9] removed confetti on lb rank --- frontend/src/ts/test/test-logic.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 99988e585..9832af6e2 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -1773,7 +1773,6 @@ async function saveResult( if (!response?.data?.dailyLeaderboardRank) { $("#result .stats .dailyLeaderboard").addClass("hidden"); } else { - Result.showConfetti(); $("#result .stats .dailyLeaderboard") .css({ maxWidth: "13rem", From e16634dad4451ff9a14c121619946401e8373107 Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 12:19:53 +0200 Subject: [PATCH 4/9] deleting user if captcha fails --- backend/src/api/controllers/user.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/src/api/controllers/user.ts b/backend/src/api/controllers/user.ts index 826481de3..93fe12f6e 100644 --- a/backend/src/api/controllers/user.ts +++ b/backend/src/api/controllers/user.ts @@ -25,7 +25,16 @@ export async function createNewUser( const { name, captcha } = req.body; const { email, uid } = req.ctx.decodedToken; - await verifyCaptcha(captcha); + try { + await verifyCaptcha(captcha); + } catch (e) { + try { + await admin.auth().deleteUser(uid); + } catch (e) { + // user might be deleted on the frontend + } + throw e; + } if (email.endsWith("@tidal.lol") || email.endsWith("@selfbot.cc")) { throw new MonkeyError(400, "Invalid domain"); From d0b3cc6e96718e9f24b811d85fc12d327e57949b Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 12:20:20 +0200 Subject: [PATCH 5/9] try catching as the account might already be deleted --- frontend/src/ts/controllers/account-controller.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/ts/controllers/account-controller.ts b/frontend/src/ts/controllers/account-controller.ts index 42a3ebffb..fd226876c 100644 --- a/frontend/src/ts/controllers/account-controller.ts +++ b/frontend/src/ts/controllers/account-controller.ts @@ -620,8 +620,16 @@ async function signUp(): Promise { } catch (e) { //make sure to do clean up here if (createdAuthUser) { - await Ape.users.delete(); - await createdAuthUser.user.delete(); + try { + await Ape.users.delete(); + } catch (e) { + // account might already be deleted + } + try { + await createdAuthUser.user.delete(); + } catch (e) { + // account might already be deleted + } } console.log(e); const message = Misc.createErrorMessage(e, "Failed to create account"); From b26348fcce70576d844a836b49b85df51a1f110d Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 12:43:19 +0200 Subject: [PATCH 6/9] extracted strong password check to a util function --- .../src/ts/controllers/account-controller.ts | 40 ++++++++----------- frontend/src/ts/utils/misc.ts | 8 ++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/frontend/src/ts/controllers/account-controller.ts b/frontend/src/ts/controllers/account-controller.ts index fd226876c..8bb375a80 100644 --- a/frontend/src/ts/controllers/account-controller.ts +++ b/frontend/src/ts/controllers/account-controller.ts @@ -540,30 +540,6 @@ async function signUp(): Promise { return; } - // Force user to use a capital letter, number, special character when setting up an account and changing password - if (password.length < 8) { - Notifications.add("Password must be at least 8 characters", 0, 3); - LoginPage.hidePreloader(); - LoginPage.enableInputs(); - LoginPage.updateSignupButton(); - return; - } - - const hasCapital = password.match(/[A-Z]/); - const hasNumber = password.match(/[\d]/); - const hasSpecial = password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/); - if (!hasCapital || !hasNumber || !hasSpecial) { - Notifications.add( - "Password must contain at least one capital letter, number, and special character", - 0, - 3 - ); - LoginPage.hidePreloader(); - LoginPage.enableInputs(); - LoginPage.updateSignupButton(); - return; - } - if (password !== passwordVerify) { Notifications.add("Passwords do not match", 0, 3); LoginPage.hidePreloader(); @@ -572,6 +548,22 @@ async function signUp(): Promise { return; } + // Force user to use a capital letter, number, special character when setting up an account and changing password + if ( + window.location.hostname !== "localhost" && + !Misc.isPasswordStrong(password) + ) { + Notifications.add( + "Password must contain at least one capital letter, number, a special character and at least 8 characters long", + 0, + 4 + ); + LoginPage.hidePreloader(); + LoginPage.enableInputs(); + LoginPage.updateSignupButton(); + return; + } + authListener(); let createdAuthUser; diff --git a/frontend/src/ts/utils/misc.ts b/frontend/src/ts/utils/misc.ts index 5cb31d492..b72fa1f3f 100644 --- a/frontend/src/ts/utils/misc.ts +++ b/frontend/src/ts/utils/misc.ts @@ -1235,3 +1235,11 @@ export function abbreviateNumber(num: number): string { export async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } + +export function isPasswordStrong(password: string): boolean { + const hasCapital = !!password.match(/[A-Z]/); + const hasNumber = !!password.match(/[\d]/); + const hasSpecial = !!password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/); + const isLong = password.length >= 8; + return hasCapital && hasNumber && hasSpecial && isLong; +} From 8bf5d451bdd48a14837d5215fc2f0393e8293362 Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 12:43:39 +0200 Subject: [PATCH 7/9] enforcing strong passwords when changing password --- frontend/src/ts/popups/simple-popups.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frontend/src/ts/popups/simple-popups.ts b/frontend/src/ts/popups/simple-popups.ts index b96fc7efa..539e37744 100644 --- a/frontend/src/ts/popups/simple-popups.ts +++ b/frontend/src/ts/popups/simple-popups.ts @@ -20,6 +20,7 @@ import { unlink, updatePassword, } from "firebase/auth"; +import { isPasswordStrong } from "../utils/misc"; interface Input { placeholder?: string; @@ -524,6 +525,17 @@ list["updatePassword"] = new SimplePopup( Notifications.add("New passwords don't match", 0); return; } + if ( + window.location.hostname !== "localhost" && + !isPasswordStrong(newPass) + ) { + Notifications.add( + "New password must contain at least one capital letter, number, a special character and at least 8 characters long", + 0, + 4 + ); + return; + } Loader.show(); await reauthenticateWithCredential(user, credential); await updatePassword(user, newPass); From b9f1caadcd28b2f7eac54e15f3362922a2d1c240 Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 28 Sep 2022 12:46:11 +0200 Subject: [PATCH 8/9] enforcing strong passwords in the email handler --- frontend/static/email-handler.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/static/email-handler.html b/frontend/static/email-handler.html index 28d09d84e..af66f1564 100644 --- a/frontend/static/email-handler.html +++ b/frontend/static/email-handler.html @@ -175,6 +175,16 @@