diff --git a/functions/index.js b/functions/index.js index 4c84e2480..257eee7c4 100644 --- a/functions/index.js +++ b/functions/index.js @@ -13,6 +13,7 @@ admin.initializeApp({ }); const db = admin.firestore(); +const fetch = require("node-fetch"); async function getAllNames() { // return admin @@ -474,6 +475,55 @@ exports.getPatreons = functions.https.onRequest(async (request, response) => { } }); +exports.verifyUser = functions.https.onRequest(async (request, response) => { + response.set("Access-Control-Allow-Origin", "*"); + response.set("Access-Control-Allow-Headers", "*"); + response.set("Access-Control-Allow-Credentials", "true"); + if (request.method === "OPTIONS") { + // Send response to OPTIONS requests + response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); + response.set("Access-Control-Allow-Headers", "Authorization,Content-Type"); + response.set("Access-Control-Max-Age", "3600"); + response.status(204).send(""); + return; + } + request = request.body.data; + if (request.uid == undefined) { + response.status(200).send({ data: { status: -1, message: "Need to provide uid" } }); + return; + } + try { + return fetch("https://discord.com/api/users/@me", { + headers: { + authorization: `${request.tokenType} ${request.accessToken}`, + }, + }) + .then((res) => res.json()) + .then(async (res2) => { + let did = res2.id; + await db.collection('users').doc(request.uid).update({ + discordId: did + }) + await db.collection("bot-commands").add({ + command: "verify", + arguments: [did,request.uid], + executed: false, + requestTimestamp: Date.now(), + }); + response.status(200).send({ data: { status: 1, message: "Verified", did: did } }); + return; + }) + .catch((e) => { + console.error('Something went wrong when trying to verify user ' + e.message); + response.status(200).send({ data: { status: -1, message: e.message } }); + return; + }); + } catch (e) { + response.status(200).send({ data: { status: -1, message: e } }); + return; + } +}); + async function incrementTestCounter(uid, userData) { try { if (userData.completedTests === undefined) { @@ -1434,143 +1484,138 @@ class Leaderboard { } } -exports.generatePairingCode = functions - .runWith({ - timeoutSeconds: 100, - memory: "2GB", - }) - .https.onRequest((request, response) => { - response.set("Access-Control-Allow-Origin", "*"); - if (request.method === "OPTIONS") { - // Send response to OPTIONS requests - response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); - response.set( - "Access-Control-Allow-Headers", - "Authorization,Content-Type" - ); - response.set("Access-Control-Max-Age", "3600"); - response.status(204).send(""); - return; - } - request = request.body.data; - try { - if (request === null) { - console.error( - `error while trying to generate discord pairing code - no input` - ); - response.status(200).send({ data: { status: -999 } }); - return; - } +// exports.generatePairingCode = functions +// .runWith({ +// timeoutSeconds: 100, +// memory: "2GB", +// }) +// .https.onRequest((request, response) => { +// response.set("Access-Control-Allow-Origin", "*"); +// if (request.method === "OPTIONS") { +// // Send response to OPTIONS requests +// response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); +// response.set( +// "Access-Control-Allow-Headers", +// "Authorization,Content-Type" +// ); +// response.set("Access-Control-Max-Age", "3600"); +// response.status(204).send(""); +// return; +// } +// request = request.body.data; +// try { +// if (request === null) { +// console.error( +// `error while trying to generate discord pairing code - no input` +// ); +// response.status(200).send({ data: { status: -999 } }); +// return; +// } - return db - .collection("users") - .doc(request.uid) - .get() - .then(async (userDoc) => { - userDocData = userDoc.data(); - if ( - userDocData.discordPairingCode !== undefined && - userDocData.discordPairingCode !== null - ) { - console.log( - `user ${request.uid} already has code ${userDocData.discordPairingCode}` - ); - response.status(200).send({ - data: { - status: -999, - pairingCode: userDocData.discordPairingCode, - }, - }); - } else { - let stepSize = 1000; - let existingCodes = []; - let query = await db - .collection(`users`) - .where("discordPairingCode", ">", "") - .limit(stepSize) - .get(); - let lastDoc; - while (query.docs.length > 0) { - lastDoc = query.docs[query.docs.length - 1]; - query.docs.forEach((doc) => { - let docData = doc.data(); - if ( - docData.discordPairingCode !== undefined && - docData.discordPairingCode !== null - ) { - existingCodes.push(docData.discordPairingCode); - } - }); - query = await db - .collection(`users`) - .where("discordPairingCode", ">", "") - .limit(stepSize) - .startAfter(lastDoc) - .get(); - } +// return db +// .collection("users") +// .doc(request.uid) +// .get() +// .then(async (userDoc) => { +// userDocData = userDoc.data(); +// if ( +// userDocData.discordPairingCode !== undefined && +// userDocData.discordPairingCode !== null +// ) { +// console.log( +// `user ${request.uid} already has code ${userDocData.discordPairingCode}` +// ); +// response.status(200).send({ +// data: { +// status: -999, +// pairingCode: userDocData.discordPairingCode, +// }, +// }); +// } else { +// let stepSize = 1000; +// let existingCodes = []; +// let query = await db +// .collection(`users`) +// .where("discordPairingCode", ">", "") +// .limit(stepSize) +// .get(); +// let lastDoc; +// while (query.docs.length > 0) { +// lastDoc = query.docs[query.docs.length - 1]; +// query.docs.forEach((doc) => { +// let docData = doc.data(); +// if ( +// docData.discordPairingCode !== undefined && +// docData.discordPairingCode !== null +// ) { +// existingCodes.push(docData.discordPairingCode); +// } +// }); +// query = await db +// .collection(`users`) +// .where("discordPairingCode", ">", "") +// .limit(stepSize) +// .startAfter(lastDoc) +// .get(); +// } - let randomCode = generate(9); +// let randomCode = generate(9); - while (existingCodes.includes(randomCode)) { - randomCode = generate(9); - } +// while (existingCodes.includes(randomCode)) { +// randomCode = generate(9); +// } - return db - .collection("users") - .doc(request.uid) - .update( - { - discordPairingCode: randomCode, - }, - { merge: true } - ) - .then((res) => { - console.log(`generated ${randomCode} for user ${request.uid}`); - response.status(200).send({ - data: { - status: 1, - pairingCode: randomCode, - }, - }); - return; - }) - .catch((e) => { - console.error( - `error while trying to set discord pairing code ${randomCode} for user ${request.uid} - ${e}` - ); - response.status(200).send({ - data: { - status: -999, - }, - }); - return; - }); - } - }); - } catch (e) { - console.error( - `error while trying to generate discord pairing code for user ${request.uid} - ${e}` - ); - response.status(200).send({ - data: { - status: -999, - }, - }); - return; - } - }); +// return db +// .collection("users") +// .doc(request.uid) +// .update( +// { +// discordPairingCode: randomCode, +// }, +// { merge: true } +// ) +// .then((res) => { +// console.log(`generated ${randomCode} for user ${request.uid}`); +// response.status(200).send({ +// data: { +// status: 1, +// pairingCode: randomCode, +// }, +// }); +// return; +// }) +// .catch((e) => { +// console.error( +// `error while trying to set discord pairing code ${randomCode} for user ${request.uid} - ${e}` +// ); +// response.status(200).send({ +// data: { +// status: -999, +// }, +// }); +// return; +// }); +// } +// }); +// } catch (e) { +// console.error( +// `error while trying to generate discord pairing code for user ${request.uid} - ${e}` +// ); +// response.status(200).send({ +// data: { +// status: -999, +// }, +// }); +// return; +// } +// }); - - exports.unlinkDiscord = functions.https.onRequest((request, response) => { response.set("Access-Control-Allow-Origin", "*"); if (request.method === "OPTIONS") { // Send response to OPTIONS requests response.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); - response.set( - "Access-Control-Allow-Headers", - "Authorization,Content-Type" - ); + response.set("Access-Control-Allow-Headers", "Authorization,Content-Type"); response.set("Access-Control-Max-Age", "3600"); response.status(204).send(""); return; @@ -1578,40 +1623,46 @@ exports.unlinkDiscord = functions.https.onRequest((request, response) => { request = request.body.data; try { if (request === null || request.uid === undefined) { - response.status(200).send({ data: { status: -999, message: "Empty request" } }); + response + .status(200) + .send({ data: { status: -999, message: "Empty request" } }); return; } - return db.collection(`users`).doc(request.uid).update({ - discordId: null - }).then(f => { - response.status(200).send({ - data: { - status: 1, - message: "Unlinked" - }, + return db + .collection(`users`) + .doc(request.uid) + .update({ + discordId: null, + }) + .then((f) => { + response.status(200).send({ + data: { + status: 1, + message: "Unlinked", + }, + }); + return; + }) + .catch((e) => { + response.status(200).send({ + data: { + status: -999, + message: e.message, + }, + }); + return; }); - return; - }).catch(e => { - response.status(200).send({ - data: { - status: -999, - message: e.message - }, - }); - return; - }) } catch (e) { response.status(200).send({ data: { status: -999, - message: e + message: e, }, }); return; } }); - async function checkLeaderboards( resultObj, type, diff --git a/package-lock.json b/package-lock.json index 61d6a1d7f..e35d726c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -611,7 +611,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "requires": { - "lodash": ">=4.17.19" + "lodash": "^4.17.14" } }, "async-each": { @@ -1773,7 +1773,7 @@ "jsonschema": "^1.0.2", "jsonwebtoken": "^8.2.1", "leven": "^3.1.0", - "lodash": ">=4.17.19", + "lodash": "^4.17.14", "marked": "^0.7.0", "marked-terminal": "^3.3.0", "minimatch": "^3.0.4", @@ -2272,7 +2272,7 @@ "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": ">=4.17.19", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", @@ -2429,6 +2429,17 @@ "requires": { "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + } } }, "isstream": { @@ -2979,7 +2990,7 @@ "requires": { "async": "^1.3.0", "flat-arguments": "^1.0.0", - "lodash": ">=4.17.19", + "lodash": "^4.17.5", "minimist": "^1.1.0" }, "dependencies": { @@ -3014,13 +3025,9 @@ } }, "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { "version": "0.9.1", @@ -3712,7 +3719,7 @@ "home-dir": "^1.0.0", "is-url": "^1.2.2", "join-path": "^1.1.1", - "lodash": ">=4.17.19", + "lodash": "^4.17.4", "mime-types": "^2.1.16", "minimatch": "^3.0.4", "morgan": "^1.8.2", @@ -3958,7 +3965,7 @@ "resolved": "https://registry.npmjs.org/toxic/-/toxic-1.0.1.tgz", "integrity": "sha512-WI3rIGdcaKULYg7KVoB0zcjikqvcYYvcuT6D89bFPz2rVR0Rl0PK6x8/X62rtdLtBKIE985NzVf/auTtGegIIg==", "requires": { - "lodash": ">=4.17.19" + "lodash": "^4.17.10" } }, "traverse": { @@ -4233,7 +4240,7 @@ "requires": { "http-parser-js": ">=0.4.0 <0.4.11", "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.4" + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { diff --git a/public/index.html b/public/index.html index eda2996d1..e392498b2 100644 --- a/public/index.html +++ b/public/index.html @@ -1454,17 +1454,11 @@ When you connect your monkey-type account to your Discord account, you will be automatically assigned a new role every time you achieve a new personal best in a 60 second test. -
-
- Generate pairing code -
+ + Verify with Discord +
-
diff --git a/public/js/account.js b/public/js/account.js index 3172b37f0..c5fa4b78d 100644 --- a/public/js/account.js +++ b/public/js/account.js @@ -252,6 +252,17 @@ firebase.auth().onAuthStateChanged(function (user) { // showNotification('Signed in', 1000); $(".pageLogin .preloader").addClass("hidden"); $("#menu .icon-button.account .text").text(displayName); + if (verifyUserWhenLoggedIn !== null) { + showNotification('Verifying', 1000); + verifyUserWhenLoggedIn.uid = user.uid; + verifyUser(verifyUserWhenLoggedIn).then(data => { + showNotification(data.data.message, 3000); + if (data.data.status === 1) { + dbSnapshot.discordId = data.data.did; + updateDiscordSettingsSection() + } + }) + } } }); diff --git a/public/js/script.js b/public/js/script.js index 48a5ceca3..d9e3146f8 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -41,6 +41,7 @@ let caretAnimating = true; let lastSecondNotRound = false; let paceCaret = null; let missedWords = []; +let verifyUserWhenLoggedIn = null; let themeColors = { bg: "#323437", @@ -207,6 +208,8 @@ const generatePairingCode = firebase .httpsCallable("generatePairingCode"); const saveLbMemory = firebase.functions().httpsCallable("saveLbMemory"); const unlinkDiscord = firebase.functions().httpsCallable("unlinkDiscord"); +const verifyUser = firebase.functions().httpsCallable("verifyUser"); + function refreshThemeColorObject() { @@ -4872,7 +4875,18 @@ $(document).ready(() => { setCustomThemeInputs(); applyCustomThemeColors(); } - if (window.location.pathname === "/account") { + if (window.location.pathname === "/verify") { + const fragment = new URLSearchParams(window.location.hash.slice(1)); + if (fragment.has("access_token")) { + const accessToken = fragment.get("access_token"); + const tokenType = fragment.get("token_type"); + verifyUserWhenLoggedIn = { + accessToken: accessToken, + tokenType: tokenType + } + history.replaceState("/", null, "/"); + } + }else if (window.location.pathname === "/account") { history.replaceState("/", null, "/"); } else if (window.location.pathname !== "/") { let page = window.location.pathname.replace("/", ""); diff --git a/public/js/settings.js b/public/js/settings.js index b02a60616..f4d574332 100644 --- a/public/js/settings.js +++ b/public/js/settings.js @@ -611,48 +611,20 @@ function updateDiscordSettingsSection() { $(".pageSettings .section.discordIntegration").removeClass("hidden"); if ( - dbSnapshot.pairingCode == undefined && dbSnapshot.discordId == undefined ) { //show button - $(".pageSettings .section.discordIntegration .howto").addClass("hidden"); $(".pageSettings .section.discordIntegration .buttons").removeClass( "hidden" ); $(".pageSettings .section.discordIntegration .info").addClass("hidden"); - $(".pageSettings .section.discordIntegration .code").addClass("hidden"); - } else if ( - dbSnapshot.pairingCode != undefined && - dbSnapshot.discordId == undefined - ) { - //show code - $(".pageSettings .section.discordIntegration .code .bottom").text( - dbSnapshot.pairingCode - ); - $(".pageSettings .section.discordIntegration .howtocode").text( - dbSnapshot.pairingCode - ); - $(".pageSettings .section.discordIntegration .howto").removeClass( - "hidden" - ); - $(".pageSettings .section.discordIntegration .buttons").addClass( - "hidden" - ); - $(".pageSettings .section.discordIntegration .info").addClass("hidden"); - $(".pageSettings .section.discordIntegration .code").removeClass( - "hidden" - ); - } else if ( - dbSnapshot.discordId != undefined - ) { - $(".pageSettings .section.discordIntegration .howto").addClass("hidden"); + } else{ $(".pageSettings .section.discordIntegration .buttons").addClass( "hidden" ); $(".pageSettings .section.discordIntegration .info").removeClass( "hidden" ); - $(".pageSettings .section.discordIntegration .code").addClass("hidden"); } } }