Moved firebase to new modular version 9 sdk (#2727)

* using modular sdk

* removing last script

* replacing more code

* unused code

* removed unused code

* removed unused code

* importing auth

* using analytics controller

* importing auth and analytics

* importing auth

* updated git ignore

* fixed path

* removed live config from gitignore

* added error message when failing to initialize firebase

* added live config
using live config when building production

* removed unused code

* fixed incorrect function use

* added example config

* added a step to the contributing guide

* optional steps

* fixed path

* using example in source code so that github actions dont cry like little babies

* using function correctly

* using function correctly

* ignoring live

* removed

* added action webpack config

* bruce said "no-no"

This reverts commit 0a1e5e1660.

* Fix

* Add ignore

* updated instructions

* using correct functions

* using correct function

* missing parameter

* using correct function

* using correct function

* removed ts ignores

* using new functions

* removed refresh

* using new functions

* merge fix

* fixed merge

* regenereated lockfile

* using correct function

* defaulting to the email thats already entered

* moved lines

Co-authored-by: Bruception <bberr022@fiu.edu>
This commit is contained in:
Jack 2022-03-19 12:33:25 +01:00 committed by GitHub
parent f7bd8a53f5
commit fe668e4811
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1351 additions and 747 deletions

View file

@ -5,7 +5,6 @@
"node": true
},
"globals": {
"firebase": "readonly",
"$": "readonly",
"jQuery": "readonly",
"html2canvas": "readonly",

View file

@ -40,6 +40,10 @@ jobs:
anti-cheat:
- 'backend/**/anticheat/**'
- name: Create stub firebase config
working-directory: ./frontend/src/scripts/constants
run: mv ./firebase-config-example.ts ./firebase-config-live.ts
- name: Check Anti-cheat
if: steps.filter.outputs.anti-cheat == 'true'
run: exit 1

4
.gitignore vendored
View file

@ -78,6 +78,8 @@ node_modules_bak/
.firebaserc
.firebaserc_copy
serviceAccountKey*.json
frontend/src/scripts/constants/firebase-config.ts
frontend/src/scripts/constants/firebase-config-live.ts
#generated files
dist/
@ -104,5 +106,3 @@ dep-graph.png
# TypeScript
build/
backend/worker.*
frontend/src/scripts/constants/firebase-config-live.ts
frontend/src/scripts/constants/firebase-config.ts

View file

@ -50,7 +50,7 @@ Alternatively, if you use `nvm` then you can run `nvm install` and `nvm use` (yo
1. Run `firebase login` on your terminal to log in to the same google account you just used to create the project.
1. Git clone this project.
- IMPORTANT: If you are on Windows, run `git config --global core.autocrlf false` before-hand to prevent CRLF errors.
1. Within the frontend directory, duplicate `.firebaserc_example`, rename the new file to `.firebaserc` and change the project name of default to the firebase project id you just created.
1. Within the `frontend` directory, duplicate `.firebaserc_example`, rename the new file to `.firebaserc` and change the project name of default to the firebase project id you just created.
- If `.firebaserc_example` does not exist after cloning, create your own with:
@ -64,18 +64,26 @@ Alternatively, if you use `nvm` then you can run `nvm install` and `nvm use` (yo
- Run `firebase projects:list` to find your firebase project id.
1. Generate a Firebase Admin private key
1. Within the `frontend/src/scripts/constants` directory, duplicate `firebase-config-example.ts`, rename it to `firebase-config.ts` and paste in your firebase config
- In your Firebase console, go to Project Settings > Service Accounts
- Click "Generate New Private Key"
- Save as `serviceAccountKey.json` inside the `backend/credentials/` directory.
- To find it, go to the Firebase console
- Navigate to `Project Settings > General > Your apps`
- If there are no apps in your project, create a new web app
- In the `SDK setup and configuration` section, select `npm`
- The Firebase config will be visible below
1. Enable Firebase Authentication
1. Enable Firebase Authentication (optional)
- In the Firebase console, go to `Authentication > Sign-in method`
- Click on `Email/Password`, enable it, and save
- Click on `Google`, add a support email and save
1. Generate a Firebase Admin private key (optional, only needed if you want to work on the backend)
- In your Firebase console, go to Project Settings > Service Accounts
- Click "Generate New Private Key"
- Save as `serviceAccountKey.json` inside the `backend/credentials/` directory.
#### Mongo Setup
Follow these steps if you want to work on anything involving the database/account system. Otherwise, you can skip this section.

File diff suppressed because it is too large Load diff

View file

@ -58,7 +58,7 @@
"crypto-browserify": "^3.12.0",
"damerau-levenshtein": "1.0.8",
"date-fns": "2.28.0",
"firebase": "^8.4.2",
"firebase": "9.6.0",
"howler": "^2.2.1",
"html2canvas": "1.4.1",
"node-object-hash": "2.3.10",

View file

@ -1,5 +1,7 @@
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import endpoints from "./endpoints";
import { Auth } from "../firebase";
import { getIdToken } from "firebase/auth";
const DEV_SERVER_HOST = "http://localhost:5005";
const PROD_SERVER_HOST = "https://api.monkeytype.com";
@ -13,8 +15,8 @@ const API_URL = `${BASE_URL}${API_PATH}`;
async function adaptRequestOptions(
options: Ape.RequestOptions
): Promise<AxiosRequestConfig> {
const currentUser = firebase.auth().currentUser;
const idToken = currentUser && (await currentUser.getIdToken());
const currentUser = Auth.currentUser;
const idToken = currentUser && (await getIdToken(currentUser));
return {
params: options.searchQuery,

View file

@ -8,6 +8,8 @@ import {
} from "./config-validation";
import * as ConfigEvent from "./observables/config-event";
import DefaultConfig from "./constants/default-config";
import { Auth } from "./firebase";
import * as AnalyticsController from "./controllers/analytics-controller";
export let localStorageConfig: MonkeyTypes.Config;
export let dbConfigLoaded = false;
@ -370,7 +372,7 @@ export function setPaceCaret(
}
if (document.readyState === "complete") {
if (val == "pb" && firebase.auth().currentUser === null) {
if (val == "pb" && Auth.currentUser === null) {
Notifications.add("PB pace caret is unavailable without an account", 0);
return false;
}
@ -1295,7 +1297,7 @@ export function setRandomTheme(
}
if (val === "custom") {
if (firebase.auth().currentUser === null) {
if (Auth.currentUser === null) {
config.randomTheme = val;
return false;
}
@ -1363,13 +1365,7 @@ export function setLanguage(language: string, nosave?: boolean): boolean {
if (!isConfigValueValid("language", language, ["string"])) return false;
config.language = language;
try {
firebase.analytics().logEvent("changedLanguage", {
language: language,
});
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("changedLanguage", { language });
saveToLocalStorage("language", nosave);
ConfigEvent.dispatch("language", config.language);
@ -1782,13 +1778,6 @@ export function apply(
try {
setEnableAds(configObj.enableAds, true);
// let addemo = false;
// if (
// firebase.app().options.projectId === "monkey-type-dev-67af4" ||
// window.location.hostname === "localhost"
// ) {
// addemo = true;
// }
if (config.enableAds === "max" || config.enableAds === "on") {
$("head").append(`

View file

@ -0,0 +1,14 @@
// To find your config, go to https://console.firebase.google.com/ and select your project
// Go to (top left) Settings > Project Settings > General
// scroll down to Your apps > Web Apps (if it doesnt exist, create one) > SDK setup and configuration > select npm
// your config should be visible there
export const firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
};

View file

@ -23,14 +23,31 @@ import * as CommandlineLists from "../elements/commandline-lists";
import * as TagController from "./tag-controller";
import * as ResultTagsPopup from "../popups/result-tags-popup";
import * as URLHandler from "../utils/url-handler";
export const gmailProvider = new firebase.auth.GoogleAuthProvider();
// const githubProvider = new firebase.auth.GithubAuthProvider();
import {
EmailAuthProvider,
GoogleAuthProvider,
browserSessionPersistence,
browserLocalPersistence,
createUserWithEmailAndPassword,
sendEmailVerification,
signInWithEmailAndPassword,
signInWithPopup,
setPersistence,
updateProfile,
linkWithPopup,
linkWithCredential,
reauthenticateWithPopup,
unlink as unlinkAuth,
getAdditionalUserInfo,
sendPasswordResetEmail,
} from "firebase/auth";
import { Auth } from "../firebase";
export const gmailProvider = new GoogleAuthProvider();
export function sendVerificationEmail() {
Loader.show();
let cu = firebase.auth().currentUser;
cu.sendEmailVerification()
let cu = Auth.currentUser;
sendEmailVerification(cu)
.then(() => {
Loader.hide();
Notifications.add("Email sent to " + cu.email, 4000);
@ -98,7 +115,7 @@ export async function getDataAndInit() {
ResultFilters.load();
});
let user = firebase.auth().currentUser;
let user = Auth.currentUser;
if (!snapshot.name) {
//verify username
if (Misc.isUsernameValid(user.name)) {
@ -251,7 +268,7 @@ async function loadUser(user) {
}
}
const authListener = firebase.auth().onAuthStateChanged(async function (user) {
const authListener = Auth.onAuthStateChanged(async function (user) {
// await UpdateConfig.loadPromise;
console.log(`auth state changed, user ${user ? true : false}`);
if (user) {
@ -307,50 +324,45 @@ export function signIn() {
let password = $(".pageLogin .login input")[1].value;
const persistence = $(".pageLogin .login #rememberMe input").prop("checked")
? firebase.auth.Auth.Persistence.LOCAL
: firebase.auth.Auth.Persistence.SESSION;
? browserLocalPersistence
: browserSessionPersistence;
firebase
.auth()
.setPersistence(persistence)
.then(function () {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(async (e) => {
await loadUser(e.user);
PageController.change("account");
if (TestLogic.notSignedInLastResult !== null) {
TestLogic.setNotSignedInUid(e.user.uid);
setPersistence(Auth, persistence).then(function () {
return signInWithEmailAndPassword(Auth, email, password)
.then(async (e) => {
await loadUser(e.user);
PageController.change("account");
if (TestLogic.notSignedInLastResult !== null) {
TestLogic.setNotSignedInUid(e.user.uid);
const response = await Ape.results.save(
TestLogic.notSignedInLastResult
const response = await Ape.results.save(
TestLogic.notSignedInLastResult
);
if (response.status !== 200) {
return Notifications.add(
"Failed to save last result: " + response.message,
-1
);
if (response.status !== 200) {
return Notifications.add(
"Failed to save last result: " + response.message,
-1
);
}
TestLogic.clearNotSignedInResult();
Notifications.add("Last test result saved", 1);
}
//TODO: redirect user to relevant page
})
.catch(function (error) {
let message = error.message;
if (error.code === "auth/wrong-password") {
message = "Incorrect password.";
} else if (error.code === "auth/user-not-found") {
message = "User not found.";
}
Notifications.add(message, -1);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .button").removeClass("disabled");
});
});
TestLogic.clearNotSignedInResult();
Notifications.add("Last test result saved", 1);
}
//TODO: redirect user to relevant page
})
.catch(function (error) {
let message = error.message;
if (error.code === "auth/wrong-password") {
message = "Incorrect password.";
} else if (error.code === "auth/user-not-found") {
message = "User not found.";
}
Notifications.add(message, -1);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .button").removeClass("disabled");
});
});
}
export async function signInWithGoogle() {
@ -361,13 +373,13 @@ export async function signInWithGoogle() {
let signedInUser;
try {
const persistence = $(".pageLogin .login #rememberMe input").prop("checked")
? firebase.auth.Auth.Persistence.LOCAL
: firebase.auth.Auth.Persistence.SESSION;
? browserLocalPersistence
: browserSessionPersistence;
await firebase.auth().setPersistence(persistence);
signedInUser = await firebase.auth().signInWithPopup(gmailProvider);
await setPersistence(Auth, persistence);
signedInUser = await signInWithPopup(Auth, gmailProvider);
if (signedInUser.additionalUserInfo.isNewUser) {
if (getAdditionalUserInfo(signedInUser)?.isNewUser) {
//ask for username
let nameGood = false;
let name = "";
@ -406,8 +418,8 @@ export async function signInWithGoogle() {
// return;
// }
if (response.status === 200) {
await signedInUser.user.updateProfile({ displayName: name });
await signedInUser.user.sendEmailVerification();
await updateProfile(signedInUser.user, { displayName: name });
await sendEmailVerification(signedInUser.user);
AllTimeStats.clear();
Notifications.add("Account created", 1, 3);
$("#menu .icon-button.account .text").text(name);
@ -444,7 +456,7 @@ export async function signInWithGoogle() {
Notifications.add("Failed to sign in with Google: " + e.message, -1);
$(".pageLogin .preloader").addClass("hidden");
$(".pageLogin .button").removeClass("disabled");
if (signedInUser?.additionalUserInfo?.isNewUser) {
if (getAdditionalUserInfo(signedInUser)?.isNewUser) {
await Ape.users.delete();
await signedInUser.user.delete();
}
@ -453,32 +465,9 @@ export async function signInWithGoogle() {
}
}
// export async function signInWithGitHub() {
// $(".pageLogin .preloader").removeClass("hidden");
// try{
// if ($(".pageLogin .login #rememberMe input").prop("checked")) {
// //remember me
// await firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);
// let signedInUser = await firebase.auth().signInWithPopup(githubProvider);
// console.log(signedInUser);
// } else {
// //dont remember
// await firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION);
// let signedInUser = await firebase.auth().signInWithPopup(githubProvider);
// console.log(signedInUser);
// }
// }catch(e){
// Notifications.add("Failed to sign in with GitHub: " + e.message, -1);
// $(".pageLogin .preloader").addClass("hidden");
// }
// }
export function addGoogleAuth() {
export async function addGoogleAuth() {
Loader.show();
firebase
.auth()
.currentUser.linkWithPopup(gmailProvider)
linkWithPopup(Auth.currentUser, gmailProvider)
.then(function () {
Loader.hide();
Notifications.add("Google authentication added", 1);
@ -494,20 +483,18 @@ export function addGoogleAuth() {
}
export async function removeGoogleAuth() {
let user = firebase.auth().currentUser;
let user = Auth.currentUser;
if (
user.providerData.find((provider) => provider.providerId === "password")
) {
Loader.show();
try {
await user.reauthenticateWithPopup(gmailProvider);
await reauthenticateWithPopup(user, gmailProvider);
} catch (e) {
Loader.hide();
return Notifications.add(e.message, -1);
}
firebase
.auth()
.currentUser.unlink("google.com")
unlinkAuth(user, "google.com")
.then(() => {
Notifications.add("Google authentication removed", 1);
Loader.hide();
@ -530,21 +517,20 @@ export async function removeGoogleAuth() {
export async function addPasswordAuth(email, password) {
Loader.show();
let user = firebase.auth().currentUser;
let user = Auth.currentUser;
if (
user.providerData.find((provider) => provider.providerId === "google.com")
) {
try {
await firebase.auth().currentUser.reauthenticateWithPopup(gmailProvider);
await reauthenticateWithPopup(user, gmailProvider);
} catch (e) {
Loader.hide();
return Notifications.add("Could not reauthenticate: " + e.message, -1);
}
}
let credential = firebase.auth.EmailAuthProvider.credential(email, password);
firebase
.auth()
.currentUser.linkWithCredential(credential)
let credential = EmailAuthProvider.credential(email, password);
linkWithCredential(user, credential)
.then(function () {
Loader.hide();
Notifications.add("Password authenication added", 1);
@ -560,9 +546,7 @@ export async function addPasswordAuth(email, password) {
}
export function signOut() {
firebase
.auth()
.signOut()
Auth.signOut()
.then(function () {
Notifications.add("Signed out", 0, 2);
AllTimeStats.clear();
@ -613,9 +597,11 @@ async function signUp() {
let createdAuthUser;
try {
createdAuthUser = await firebase
.auth()
.createUserWithEmailAndPassword(email, password);
createdAuthUser = await createUserWithEmailAndPassword(
Auth,
email,
password
);
const signInResponse = await Ape.users.create(
nname,
@ -626,8 +612,8 @@ async function signUp() {
throw signInResponse;
}
await createdAuthUser.user.updateProfile({ displayName: nname });
await createdAuthUser.user.sendEmailVerification();
await updateProfile(createdAuthUser.user, { displayName: nname });
await sendEmailVerification(createdAuthUser.user);
AllTimeStats.clear();
$("#menu .icon-button.account .text").text(nname);
$(".pageLogin .button").removeClass("disabled");
@ -675,11 +661,10 @@ async function signUp() {
}
$(".pageLogin #forgotPasswordButton").on("click", (e) => {
let email = prompt("Email address");
const emailField = $(".pageLogin .login input")[0].value || "";
let email = prompt("Email address", emailField);
if (email) {
firebase
.auth()
.sendPasswordResetEmail(email)
sendPasswordResetEmail(Auth, email)
.then(function () {
// Email sent.
Notifications.add("Email sent", 1, 2);
@ -730,10 +715,7 @@ $(".pageLogin .register .button").on("click", (e) => {
});
$(".pageSettings #addGoogleAuth").on("click", async (e) => {
await addGoogleAuth();
setTimeout(() => {
window.location.reload();
}, 1000);
addGoogleAuth();
});
$(".pageSettings #removeGoogleAuth").on("click", (e) => {

View file

@ -0,0 +1,13 @@
import { Analytics } from "../firebase";
import { logEvent } from "firebase/analytics";
export function log(
eventName: string,
params?: { [key: string]: string }
): void {
try {
logEvent(Analytics, eventName, params);
} catch (e) {
console.log("Analytics unavailable");
}
}

View file

@ -2,6 +2,7 @@
import * as PageController from "./page-controller";
// import Config from "../config";
import * as ActivePage from "../states/active-page";
import { Auth } from "../firebase";
const mappedRoutes = {
"/": "pageLoading",
@ -45,7 +46,7 @@ $(window).on("popstate", (e) => {
// show about
PageController.change("about");
} else if (state == "account" || state == "login") {
if (firebase.auth().currentUser) {
if (Auth.currentUser) {
PageController.change("account");
} else {
PageController.change("login");

View file

@ -7,6 +7,7 @@ import * as BackgroundFilter from "../elements/custom-background-filter";
import * as ConfigEvent from "../observables/config-event";
import * as DB from "../db";
import * as Notifications from "../elements/notifications";
import * as AnalyticsController from "../controllers/analytics-controller";
let isPreviewingTheme = false;
export let randomTheme: string | null = null;
@ -132,13 +133,7 @@ function apply(themeName: string, isCustom: boolean, isPreview = false): void {
});
}
try {
firebase.analytics().logEvent("changedTheme", {
theme: themeName,
});
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("changedTheme", { theme: themeName });
if (!isPreview) {
ThemeColors.getAll().then((colors) => {
$(".keymap-key").attr("style", "");

View file

@ -3,6 +3,7 @@ import * as AccountButton from "./elements/account-button";
import * as Notifications from "./elements/notifications";
import * as LoadingPage from "./pages/loading";
import DefaultConfig from "./constants/default-config";
import { Auth } from "./firebase";
let dbSnapshot: MonkeyTypes.Snapshot;
@ -52,7 +53,7 @@ export async function initSnapshot(): Promise<
};
const snap = defaultSnap;
try {
if (firebase.auth().currentUser == null) return false;
if (Auth.currentUser == null) return false;
// if (ActivePage.get() == "loading") {
// LoadingPage.updateBar(22.5);
// } else {
@ -171,7 +172,7 @@ export async function initSnapshot(): Promise<
}
export async function getUserResults(): Promise<boolean> {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user == null) return false;
if (dbSnapshot === null) return false;
if (dbSnapshot.results !== undefined) {
@ -240,7 +241,7 @@ export async function editCustomTheme(
themeId: string,
newTheme: MonkeyTypes.RawCustomTheme
): Promise<boolean> {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return false;
if (dbSnapshot === null) return false;
@ -271,7 +272,7 @@ export async function editCustomTheme(
}
export async function deleteCustomTheme(themeId: string): Promise<boolean> {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return false;
if (dbSnapshot === null) return false;
@ -732,7 +733,7 @@ export async function updateLbMemory<M extends MonkeyTypes.Mode>(
}
export async function saveConfig(config: MonkeyTypes.Config): Promise<void> {
if (firebase.auth().currentUser !== null) {
if (Auth.currentUser !== null) {
AccountButton.loading(true);
const response = await Ape.configs.save(config);

View file

@ -1,3 +1,4 @@
import { Auth } from "../firebase";
import * as Misc from "../utils/misc";
export function loading(truefalse: boolean): void {
@ -13,7 +14,7 @@ export function loading(truefalse: boolean): void {
}
export function update(): void {
if (firebase.auth().currentUser != null) {
if (Auth.currentUser != null) {
Misc.swapElements(
$("#menu .icon-button.login"),
$("#menu .icon-button.account"),

View file

@ -19,6 +19,7 @@ import * as PaceCaret from "../test/pace-caret";
import * as TestInput from "../test/test-input";
import * as ModesNotice from "../elements/modes-notice";
import * as ConfigEvent from "../observables/config-event";
import { Auth } from "../firebase";
export let current: MonkeyTypes.CommandsGroup[] = [];
@ -1152,7 +1153,7 @@ const commandsRandomTheme: MonkeyTypes.CommandsGroup = {
display: "custom",
configValue: "custom",
exec: (): void => {
if (firebase.auth().currentUser === null) {
if (Auth.currentUser === null) {
Notifications.add(
"Multiple custom themes are available to logged in users only",
0
@ -1257,7 +1258,7 @@ export const customThemeListCommands: MonkeyTypes.CommandsGroup = {
};
export function updateCustomThemeListCommands(): void {
if (firebase.auth().currentUser === null) {
if (Auth.currentUser === null) {
return;
}
@ -2857,7 +2858,7 @@ export const defaultCommands: MonkeyTypes.CommandsGroup = {
subgroup: customThemeListCommands,
beforeSubgroup: (): void => updateCustomThemeListCommands(),
available: (): boolean => {
return firebase.auth().currentUser !== null;
return Auth.currentUser !== null;
},
},
{

View file

@ -5,6 +5,8 @@ import * as CommandlineLists from "./commandline-lists";
import * as TestUI from "../test/test-ui";
import * as DB from "../db";
import * as Notifications from "../elements/notifications";
import * as AnalyticsController from "../controllers/analytics-controller";
import { Auth } from "../firebase";
let commandLineMouseMode = false;
@ -235,13 +237,7 @@ function trigger(command: string): void {
}
});
if (!subgroup && !input && !sticky) {
try {
firebase.analytics().logEvent("usedCommandLine", {
command: command,
});
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("usedCommandLine", { command });
hide();
}
}
@ -439,13 +435,7 @@ $("#commandInput input").on("keydown", (e) => {
}
}
});
try {
firebase.analytics().logEvent("usedCommandLine", {
command: command,
});
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("usedCommandLine", { command: command ?? "" });
hide();
}
return;
@ -697,7 +687,7 @@ $(document).on("click", "#testModesNotice .text-button", (event) => {
$(document).on("click", "#bottom .leftright .right .current-theme", (e) => {
if (e.shiftKey) {
if (!Config.customTheme) {
if (firebase.auth().currentUser !== null) {
if (Auth.currentUser !== null) {
if (DB.getSnapshot().customThemes.length < 1) {
Notifications.add("No custom themes!", 0);
UpdateConfig.setCustomTheme(false);

View file

@ -4,6 +4,7 @@ import Config from "../config";
import * as Misc from "../utils/misc";
import * as Notifications from "./notifications";
import { format } from "date-fns";
import { Auth } from "../firebase";
const currentLeaderboard = "time_15";
@ -282,7 +283,7 @@ async function update(): Promise<void> {
Ape.leaderboards.get("english", "time", "60", 0),
];
if (firebase.auth().currentUser) {
if (Auth.currentUser) {
leaderboardRequests.push(
Ape.leaderboards.getRank("english", "time", "15"),
Ape.leaderboards.getRank("english", "time", "60")
@ -382,7 +383,7 @@ async function requestNew(lb: LbKey, skip: number): Promise<void> {
export function show(): void {
if ($("#leaderboardsWrapper").hasClass("hidden")) {
if (firebase.auth().currentUser) {
if (Auth.currentUser) {
$("#leaderboardsWrapper #leaderboards .rightTableJumpToMe").removeClass(
"disabled"
);

View file

@ -5,6 +5,7 @@ import * as Last10Average from "../elements/last-10-average";
import Config from "../config";
import * as TestWords from "../test/test-words";
import * as ConfigEvent from "../observables/config-event";
import { Auth } from "../firebase";
ConfigEvent.subscribe((eventKey) => {
if (
@ -112,7 +113,7 @@ export async function update(): Promise<void> {
if (Config.showAvg) {
const val = Last10Average.get();
if (firebase.auth().currentUser && val > 0) {
if (Auth.currentUser && val > 0) {
$(".pageTest #testModesNotice").append(
`<div class="text-button" commands="commandsShowAvg"><i class="fas fa-tachometer-alt"></i>avg: ${val}wpm</div>`
);

View file

@ -0,0 +1,21 @@
// Import the functions you need from the SDKs you need
import { FirebaseApp, initializeApp } from "firebase/app";
import { getAuth, Auth as AuthType } from "firebase/auth";
import { firebaseConfig } from "./constants/firebase-config"; // eslint-disable-line require-path-exists/exists
import { Analytics as AnalyticsType, getAnalytics } from "firebase/analytics";
// Initialize Firebase
let app: FirebaseApp;
export let Auth: AuthType;
export let Analytics: AnalyticsType;
try {
app = initializeApp(firebaseConfig);
Auth = getAuth(app);
Analytics = getAnalytics(app);
} catch (e) {
$("body").text(
"Failed to initialize Firebase. Are you sure you have the correct config in the firebase-config.ts file?"
);
}

View file

@ -1,6 +1,7 @@
// this file should be concatenated at the top of the legacy js files
import "../styles/index.scss";
import "./firebase";
// @ts-ignore
import Chart from "chart.js";

View file

@ -1,3 +1,2 @@
declare let firebase: any; // typeof import("firebase").default;
declare let grecaptcha: ReCaptchaV2.ReCaptcha;
declare let html2canvas: typeof import("html2canvas").default;

View file

@ -13,6 +13,7 @@ import * as ConfigEvent from "../observables/config-event";
import * as ActivePage from "../states/active-page";
import * as ApeKeysPopup from "../popups/ape-keys-popup";
import Page from "./page";
import { Auth } from "../firebase";
type SettingsGroups = {
[key: string]: SettingsGroup;
@ -556,7 +557,7 @@ export function hideAccountSection(): void {
export function updateDiscordSection(): void {
//no code and no discord
if (firebase.auth().currentUser == null) {
if (Auth.currentUser == null) {
$(".pageSettings .section.discordIntegration").addClass("hidden");
} else {
if (DB.getSnapshot() == null) return;
@ -583,15 +584,13 @@ export function updateAuthSections(): void {
$(".pageSettings .section.passwordAuthSettings .button").addClass("hidden");
$(".pageSettings .section.googleAuthSettings .button").addClass("hidden");
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (!user) return;
const passwordProvider = user.providerData.find(
//@ts-ignore todo remove then firebase is initialised in code rather than with a script tag
(provider) => provider.providerId === "password"
);
const googleProvider = user.providerData.find(
//@ts-ignore
(provider) => provider.providerId === "google.com"
);
@ -636,7 +635,7 @@ function setActiveFunboxButton(): void {
}
function refreshTagsSettingsSection(): void {
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
if (Auth.currentUser !== null && DB.getSnapshot() !== null) {
const tagsEl = $(".pageSettings .section.tags .tagsList").empty();
DB.getSnapshot().tags?.forEach((tag) => {
// let tagPbString = "No PB found";
@ -671,7 +670,7 @@ function refreshTagsSettingsSection(): void {
}
function refreshPresetsSettingsSection(): void {
if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) {
if (Auth.currentUser !== null && DB.getSnapshot() !== null) {
const presetsEl = $(".pageSettings .section.presets .presetsList").empty();
DB.getSnapshot().presets?.forEach((preset: MonkeyTypes.Preset) => {
presetsEl.append(`

View file

@ -14,6 +14,7 @@ import {
import { debounce } from "../utils/debounce";
import { splitByAndKeep } from "../utils/strings";
import QuotesController from "../controllers/quotes-controller";
import { Auth } from "../firebase";
export let selectedId = 1;
@ -89,7 +90,7 @@ function buildQuoteSearchResult(
lengthDesc = "thicc";
}
const isNotAuthed = !firebase.auth().currentUser;
const isNotAuthed = !Auth.currentUser;
return `
<div class="searchResult" id="${quote.id}">
@ -160,7 +161,7 @@ export async function show(clearText = true): Promise<void> {
const quoteSearchInputValue = $("#quoteSearchPopup input").val() as string;
if (!firebase.auth().currentUser) {
if (!Auth.currentUser) {
$("#quoteSearchPopup #gotoSubmitQuoteButton").addClass("hidden");
} else {
$("#quoteSearchPopup #gotoSubmitQuoteButton").removeClass("hidden");

View file

@ -1,4 +1,3 @@
import type FirebaseTypes from "firebase";
import Ape from "../ape";
import * as AccountController from "../controllers/account-controller";
import * as DB from "../db";
@ -11,6 +10,14 @@ import * as ThemePicker from "../settings/theme-picker";
import * as CustomText from "../test/custom-text";
import * as CustomTextPopup from "../popups/custom-text-popup";
import * as SavedTextsPopup from "./saved-texts-popup";
import { FirebaseError } from "firebase/app";
import { Auth } from "../firebase";
import {
EmailAuthProvider,
reauthenticateWithCredential,
reauthenticateWithPopup,
updatePassword,
} from "firebase/auth";
type Input = {
placeholder?: string;
@ -275,21 +282,22 @@ list["updateEmail"] = new SimplePopup(
"Update",
async (_thisPopup, password, email, emailConfirm) => {
try {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (email !== emailConfirm) {
Notifications.add("Emails don't match", 0);
return;
}
if (user.providerData[0].providerId === "password") {
const credential = firebase.auth.EmailAuthProvider.credential(
user.email,
const credential = EmailAuthProvider.credential(
user.email as string,
password
);
await user.reauthenticateWithCredential(credential);
await reauthenticateWithCredential(user, credential);
}
Loader.show();
const response = await Ape.users.updateEmail(email, user.email);
const response = await Ape.users.updateEmail(email, user.email as string);
Loader.hide();
if (response.status !== 200) {
@ -304,7 +312,7 @@ list["updateEmail"] = new SimplePopup(
window.location.reload();
}, 1000);
} catch (e) {
const typedError = e as FirebaseTypes.FirebaseError;
const typedError = e as FirebaseError;
if (typedError.code === "auth/wrong-password") {
Notifications.add("Incorrect password", -1);
} else {
@ -313,7 +321,8 @@ list["updateEmail"] = new SimplePopup(
}
},
(thisPopup) => {
const user: FirebaseTypes.User = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (!user.providerData.find((p) => p?.providerId === "password")) {
thisPopup.inputs = [];
thisPopup.buttonText = "";
@ -345,15 +354,16 @@ list["updateName"] = new SimplePopup(
"Update",
async (_thisPopup, pass, newName) => {
try {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "password") {
const credential = firebase.auth.EmailAuthProvider.credential(
user.email,
const credential = EmailAuthProvider.credential(
user.email as string,
pass
);
await user.reauthenticateWithCredential(credential);
await reauthenticateWithCredential(user, credential);
} else if (user.providerData[0].providerId === "google.com") {
await user.reauthenticateWithPopup(AccountController.gmailProvider);
await reauthenticateWithPopup(user, AccountController.gmailProvider);
}
Loader.show();
@ -379,7 +389,7 @@ list["updateName"] = new SimplePopup(
DB.getSnapshot().name = newName;
$("#menu .icon-button.account .text").text(newName);
} catch (e) {
const typedError = e as FirebaseTypes.FirebaseError;
const typedError = e as FirebaseError;
if (typedError.code === "auth/wrong-password") {
Notifications.add("Incorrect password", -1);
} else {
@ -389,7 +399,8 @@ list["updateName"] = new SimplePopup(
Loader.hide();
},
(thisPopup) => {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "google.com") {
thisPopup.inputs[0].hidden = true;
thisPopup.buttonText = "Reauthenticate to update";
@ -425,9 +436,10 @@ list["updatePassword"] = new SimplePopup(
"Update",
async (_thisPopup, previousPass, newPass, newPassConfirm) => {
try {
const user = firebase.auth().currentUser;
const credential = firebase.auth.EmailAuthProvider.credential(
user.email,
const user = Auth.currentUser;
if (user === null) return;
const credential = EmailAuthProvider.credential(
user.email as string,
previousPass
);
if (newPass !== newPassConfirm) {
@ -435,15 +447,15 @@ list["updatePassword"] = new SimplePopup(
return;
}
Loader.show();
await user.reauthenticateWithCredential(credential);
await user.updatePassword(newPass);
await reauthenticateWithCredential(user, credential);
await updatePassword(user, newPass);
Loader.hide();
Notifications.add("Password updated", 1);
setTimeout(() => {
window.location.reload();
}, 1000);
} catch (e) {
const typedError = e as FirebaseTypes.FirebaseError;
const typedError = e as FirebaseError;
Loader.hide();
if (typedError.code === "auth/wrong-password") {
Notifications.add("Incorrect password", -1);
@ -453,7 +465,8 @@ list["updatePassword"] = new SimplePopup(
}
},
(thisPopup) => {
const user: FirebaseTypes.User = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (!user.providerData.find((p) => p?.providerId === "password")) {
thisPopup.inputs = [];
thisPopup.buttonText = "";
@ -505,9 +518,6 @@ list["addPasswordAuth"] = new SimplePopup(
}
await AccountController.addPasswordAuth(email, pass);
setTimeout(() => {
window.location.reload();
}, 1000);
},
() => {
//
@ -533,15 +543,16 @@ list["deleteAccount"] = new SimplePopup(
async (_thisPopup, password: string) => {
//
try {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "password") {
const credential = firebase.auth.EmailAuthProvider.credential(
user.email,
const credential = EmailAuthProvider.credential(
user.email as string,
password
);
await user.reauthenticateWithCredential(credential);
await reauthenticateWithCredential(user, credential);
} else if (user.providerData[0].providerId === "google.com") {
await user.reauthenticateWithPopup(AccountController.gmailProvider);
await reauthenticateWithPopup(user, AccountController.gmailProvider);
}
Loader.show();
Notifications.add("Deleting stats...", 0);
@ -568,7 +579,7 @@ list["deleteAccount"] = new SimplePopup(
}
Notifications.add("Deleting login information...", 0);
await firebase.auth().currentUser.delete();
await Auth.currentUser?.delete();
Notifications.add("Goodbye", 1, 5);
@ -576,7 +587,7 @@ list["deleteAccount"] = new SimplePopup(
location.reload();
}, 3000);
} catch (e) {
const typedError = e as FirebaseTypes.FirebaseError;
const typedError = e as FirebaseError;
Loader.hide();
if (typedError.code === "auth/wrong-password") {
Notifications.add("Incorrect password", -1);
@ -586,7 +597,8 @@ list["deleteAccount"] = new SimplePopup(
}
},
(thisPopup) => {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "google.com") {
thisPopup.inputs = [];
thisPopup.buttonText = "Reauthenticate to delete";
@ -677,15 +689,16 @@ list["resetPersonalBests"] = new SimplePopup(
"Reset",
async (_thisPopup, password: string) => {
try {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "password") {
const credential = firebase.auth.EmailAuthProvider.credential(
user.email,
const credential = EmailAuthProvider.credential(
user.email as string,
password
);
await user.reauthenticateWithCredential(credential);
await reauthenticateWithCredential(user, credential);
} else if (user.providerData[0].providerId === "google.com") {
await user.reauthenticateWithPopup(AccountController.gmailProvider);
await reauthenticateWithPopup(user, AccountController.gmailProvider);
}
Loader.show();
const response = await Ape.users.deletePersonalBests();
@ -712,7 +725,8 @@ list["resetPersonalBests"] = new SimplePopup(
}
},
(thisPopup) => {
const user = firebase.auth().currentUser;
const user = Auth.currentUser;
if (user === null) return;
if (user.providerData[0].providerId === "google.com") {
thisPopup.inputs = [];
thisPopup.buttonText = "Reauthenticate to reset";

View file

@ -8,6 +8,7 @@ import * as CustomThemePopup from "../popups/custom-theme-popup";
import * as Loader from "../elements/loader";
import * as DB from "../db";
import * as ConfigEvent from "../observables/config-event";
import { Auth } from "../firebase";
export function updateActiveButton(): void {
let activeThemeName = Config.theme;
@ -109,7 +110,7 @@ export async function refreshButtons(): Promise<void> {
).empty();
const addButton = $(".pageSettings .section.themes .addCustomThemeButton");
if (firebase.auth().currentUser === null) {
if (Auth.currentUser === null) {
$(
".pageSettings .section.themes .customThemeEdit .saveCustomThemeButton"
).text("save");
@ -425,7 +426,7 @@ $("#shareCustomThemeButton").on("click", () => {
$(".pageSettings .saveCustomThemeButton").on("click", async () => {
saveCustomThemeColors();
if (firebase.auth().currentUser) {
if (Auth.currentUser) {
const newCustomTheme = {
name: "custom",
colors: Config.customThemeColors,

View file

@ -12,6 +12,7 @@ import * as QuoteRatePopup from "../popups/quote-rate-popup";
import * as GlarsesMode from "../states/glarses-mode";
import * as TestInput from "./test-input";
import * as Notifications from "../elements/notifications";
import { Auth } from "../firebase";
let result: MonkeyTypes.Result<MonkeyTypes.Mode>;
let maxChartVal: number;
@ -591,7 +592,7 @@ export function update(
$("#words").removeClass("blurred");
$("#wordsInput").blur();
$("#result .stats .time .bottom .afk").text("");
if (firebase.auth().currentUser != null) {
if (Auth.currentUser != null) {
$("#result .loginTip").addClass("hidden");
} else {
$("#result .loginTip").removeClass("hidden");
@ -646,7 +647,7 @@ export function update(
$("#middle #result .stats").removeClass("hidden");
$("#middle #result .chart").removeClass("hidden");
// $("#middle #result #resultWordsHistory").removeClass("hidden");
if (firebase.auth().currentUser == null) {
if (Auth.currentUser == null) {
$("#middle #result .loginTip").removeClass("hidden");
}
$("#middle #result #showWordHistoryButton").removeClass("hidden");

View file

@ -50,6 +50,8 @@ import * as TimerEvent from "../observables/timer-event";
import * as Last10Average from "../elements/last-10-average";
import * as Monkey from "./monkey";
import NodeObjectHash from "node-object-hash";
import * as AnalyticsController from "../controllers/analytics-controller";
import { Auth } from "../firebase";
const objecthash = NodeObjectHash().hash;
@ -241,14 +243,11 @@ export function startTest(): boolean {
if (!UpdateConfig.dbConfigLoaded) {
UpdateConfig.setChangedBeforeDb(true);
}
try {
if (firebase.auth().currentUser != null) {
firebase.analytics().logEvent("testStarted");
} else {
firebase.analytics().logEvent("testStartedNoLogin");
}
} catch (e) {
console.log("Analytics unavailable");
if (Auth.currentUser !== null) {
AnalyticsController.log("testStarted");
} else {
AnalyticsController.log("testStartedNoLogin");
}
TestActive.set(true);
Replay.startReplayRecording();
@ -894,7 +893,7 @@ export async function init(): Promise<void> {
`No ${Config.language.replace(/_\d*k$/g, "")} quotes found`,
0
);
if (firebase.auth().currentUser) {
if (Auth.currentUser) {
QuoteSubmitPopup.show(false);
}
UpdateConfig.setMode("words");
@ -1141,11 +1140,7 @@ export async function retrySavingResult(): Promise<void> {
started: TestStats.restartCount + 1,
});
try {
firebase.analytics().logEvent("testCompleted", completedEvent);
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("testCompleted");
if (response.data.isPb) {
//new pb
@ -1437,14 +1432,10 @@ export async function finish(difficultyFailed = false): Promise<void> {
Result.updateTodayTracker();
}
if (firebase.auth().currentUser == null) {
if (Auth.currentUser == null) {
$(".pageTest #result #rateQuoteButton").addClass("hidden");
$(".pageTest #result #reportQuoteButton").addClass("hidden");
try {
firebase.analytics().logEvent("testCompletedNoLogin", completedEvent);
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("testCompletedNoLogin");
if (!dontSave) notSignedInLastResult = completedEvent;
dontSave = true;
} else {
@ -1474,11 +1465,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
}
if (dontSave) {
try {
firebase.analytics().logEvent("testCompletedInvalid", completedEvent);
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("testCompletedInvalid");
return;
}
@ -1492,7 +1479,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
TestStats.resetIncomplete();
}
completedEvent.uid = firebase.auth().currentUser.uid;
completedEvent.uid = Auth.currentUser?.uid as string;
Result.updateRateQuote(TestWords.randomQuote);
Result.updateGraphPBLine();
@ -1542,11 +1529,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
started: TestStats.restartCount + 1,
});
try {
firebase.analytics().logEvent("testCompleted", completedEvent);
} catch (e) {
console.log("Analytics unavailable");
}
AnalyticsController.log("testCompleted");
if (response.data.isPb) {
//new pb

View file

@ -12,6 +12,7 @@ import * as Misc from "../utils/misc";
import * as SlowTimer from "../states/slow-timer";
import * as ConfigEvent from "../observables/config-event";
import { format } from "date-fns";
import { Auth } from "../firebase";
ConfigEvent.subscribe((eventKey, eventValue) => {
if (eventValue === undefined || typeof eventValue !== "boolean") return;
@ -212,7 +213,7 @@ export async function screenshot(): Promise<void> {
$(".pageTest .ssWatermark").text("monkeytype.com");
$(".pageTest .buttons").removeClass("hidden");
if (revealReplay) $("#resultReplay").removeClass("hidden");
if (firebase.auth().currentUser == null) {
if (Auth.currentUser == null) {
$(".pageTest .loginTip").removeClass("hidden");
}
}
@ -227,7 +228,7 @@ export async function screenshot(): Promise<void> {
$(".pageTest .ssWatermark").text(
format(dateNow, "dd MMM yyyy HH:mm") + " | monkeytype.com "
);
if (firebase.auth().currentUser != null) {
if (Auth.currentUser != null) {
$(".pageTest .ssWatermark").text(
DB.getSnapshot().name +
" | " +

View file

@ -27,24 +27,12 @@ export function updateKeytips(): void {
}
}
//checking if the project is the development site
/*
if (firebase.app().options.projectId === "monkey-type-dev-67af4") {
$("#top .logo .bottom").text("monkey-dev");
$("head title").text("Monkey Dev");
$("body").append(
`<div class="devIndicator tr">DEV</div><div class="devIndicator bl">DEV</div>`
);
}
*/
if (window.location.hostname === "localhost") {
window.onerror = function (error): void {
Notifications.add(error.toString(), -1);
};
$("#top .logo .top").text("localhost");
$("head title").text($("head title").text() + " (localhost)");
//firebase.functions().useFunctionsEmulator("http://localhost:5001");
$("body").append(
`<div class="devIndicator tl">local</div><div class="devIndicator br">local</div>`
);

View file

@ -1,9 +1,10 @@
import * as Loader from "../elements/loader";
import { format } from "date-fns";
import { Auth } from "../firebase";
export function getuid(): void {
console.error("Only share this uid with Miodec and nobody else!");
console.log(firebase.auth().currentUser.uid);
console.log(Auth.currentUser?.uid);
console.error("Only share this uid with Miodec and nobody else!");
}

View file

@ -4961,18 +4961,6 @@
gtag("config", "UA-165993088-1");
</script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="/__/firebase/8.4.2/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="/__/firebase/8.4.2/firebase-analytics.js"></script>
<script src="/__/firebase/8.4.2/firebase-auth.js"></script>
<!-- <script src="/__/firebase/8.4.2/firebase-firestore.js"></script> -->
<!-- <script src="/__/firebase/8.4.2/firebase-functions.js"></script> -->
<!-- Initialize Firebase -->
<script src="/__/firebase/init.js"></script>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/jquery.color.min.js"></script>
<script src="js/easing.min.js"></script>

View file

@ -10,7 +10,6 @@
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
"types": [
"jquery",
"firebase",
"select2"
] /* Specify type package names to be included without being referenced in a source file. */,
"allowUmdGlobalAccess": true /* Allow accessing UMD globals from modules. */,

View file

@ -20,7 +20,7 @@ const PRODUCTION_CONFIGURATION = {
loader: "string-replace-loader",
options: {
search: /^export const CLIENT_VERSION =.*/,
replace(_match, _p1, _offset, _string) {
replace() {
const date = new Date();
const versionPrefix = pad(
@ -40,6 +40,17 @@ const PRODUCTION_CONFIGURATION = {
flags: "g",
},
},
{
test: /firebase\.ts$/,
loader: "string-replace-loader",
options: {
search: /\.\/constants\/firebase-config/,
replace() {
return "./constants/firebase-config-live";
},
flags: "g",
},
},
{
test: /\.m?js$/,
exclude: /(node_modules)/,

View file

@ -5,7 +5,6 @@
"node": true
},
"globals": {
"firebase": "readonly",
"$": "readonly",
"jQuery": "readonly",
"html2canvas": "readonly",