From 4bac4ffe15dc0128d04d31400ac80244088e1947 Mon Sep 17 00:00:00 2001 From: Nareshkumar Rao <_accounts@nareshkumarrao.com> Date: Wed, 28 Jul 2021 14:00:28 +0200 Subject: [PATCH 1/2] implemented telegram login --- app.js | 125 ++++++++++++++++++++++++++++++---------------- package-lock.json | 41 +++++++++++++++ package.json | 1 + 3 files changed, 124 insertions(+), 43 deletions(-) diff --git a/app.js b/app.js index 0ba3c71..981b8b3 100644 --- a/app.js +++ b/app.js @@ -5,7 +5,9 @@ const bcrypt = require('bcrypt'); const QRCode = require('qrcode'); const cors = require('cors'); const { createSecureServer } = require('http2'); +const { default: axios } = require('axios'); require("dotenv-flow").config(); +const crypto = require('crypto'); var SequelizeStore = require("connect-session-sequelize")(session.Store); @@ -82,17 +84,36 @@ User.sync().then(() => { }); -function authUser(telegram, password, done) { +function authUser(telegramResponse, done) { + let dataCheckArray = []; + + for (const [key, value] of Object.entries(telegramResponse)) { + if (key == "hash") continue; + dataCheckArray.push(`${key}=${value}`); + } + dataCheckArray.sort(); + const dataCheckString = dataCheckArray.join("\n"); + + secretKey = crypto.createHash("sha256").update(process.env.TELEGRAM_TOKEN).digest(); + confirmationHash = crypto.createHmac("sha256", secretKey).update(dataCheckString).digest("hex"); + + const authorized = confirmationHash == telegramResponse.hash; + + if (!authorized) { + done({ authorized: false }); + } + User.findOne({ where: { - telegram: telegram + telegram: telegramResponse.id, } }).then(user => { if (!user) { - done(false, "User not found") + createUser(telegramResponse.id, (success) => { + done({ authorized: success }); + }) } else { - const auth = bcrypt.compareSync(password, user.hash); - done(auth, auth ? "Authorized" : "Wrong password"); + done({ authorized: true }); } }); } @@ -109,10 +130,10 @@ function refreshVerification(user, done) { function createQRCode(telegram, done) { User.findOne({ - where: { - telegram: telegram - } - }) + where: { + telegram: telegram + } + }) .then(user => { refreshVerification(user, result => { const verifyURL = `${process.env.WEBSITE_URL}/#/verify/${encodeURIComponent(result.verification)}`; @@ -140,11 +161,9 @@ function checkVerification(id, done) { }); } -function createUser(telegram, password, done) { - hash = bcrypt.hashSync(password, 10); +function createUser(telegram, done) { User.create({ - telegram: telegram, - hash: hash, + telegram: telegram }).then(user => { if (!user) { done(false, "Could not create user"); @@ -162,13 +181,18 @@ function createUser(telegram, password, done) { function addContact(telegram, withUserID, done) { User.findOne({ where: { telegram: telegram } }).then(user => { - Contact.create({ user: user.id, with: withUserID }) - .then(res => { - done(true, "Successfully added contact"); - }) - .catch(e => { - done(false, e); - }); + User.findOne({ where: { id: withUserID } }).then(withUser => { + Contact.create({ user: user.id, with: withUserID }) + .then(res => { + console.log(`Registering contact between ${user.id} and ${withUserID}`); + sendTelegramMessage(withUser.telegram, "Someone scanned your QR code. You will be notified if they are tested positive with Covid. If you are tested positive, please tell this bot /COVIDPOSITIVE"); + done(true, "Successfully added contact"); + }) + .catch(e => { + done(false, e); + }); + + }) }) } @@ -176,6 +200,32 @@ function getCookieExpiry() { return new Date(Date.now() + COOKIE_EXPIRY_DURATION); } +function setTelegramWebHook(done) { + const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/setWebhook`; + axios.post(url, { + url: `${process.env.SERVER_API_URL}/${process.env.TELEGRAM_SECRET}`, + allowed_updates: [], + drop_pending_updates: true, + }) + .then(res => { done(res) }) + .catch(err => { done(err) }); +} + +function sendTelegramMessage(telegramID, message, done) { + const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/sendMessage`; + axios.post(url, { + chat_id: telegramID, + text: message, + }) + .then((res) => { + done(res) + }) + .catch(err => { + console.error("Problem sending Telegram message."); + done(err) + }); +} + const app = express(); app.set('trust proxy', 1) app.use(session({ @@ -191,17 +241,25 @@ app.use(session({ app.use(cors({ credentials: true, origin: true, secure: true })); app.use(express.json()) +setTelegramWebHook(() => { }); +app.post(`/${process.env.TELEGRAM_SECRET}`, (req, res) => { + if (req.body.message) { + sendTelegramMessage(req.body.message.chat.id, `${req.body.message.text.toUpperCase()}`, (res) => { console.log(res) }); + } + res.send(); +}); + app.post('/login', (req, res) => { - reqTelegram = req.body.telegram.toLowerCase(); - const auth = authUser(reqTelegram, req.body.password, (success, msg) => { + telegramResponse = req.body.telegramResponse; + const auth = authUser(telegramResponse, (success, msg) => { if (success) { const verified = req.session.verified; const verifiedBy = req.session.verifiedBy; req.session.regenerate(() => { cookieExpiry = getCookieExpiry(); - req.session.user = reqTelegram; + req.session.user = telegramResponse.id; if (verified) { - addContact(reqTelegram, verifiedBy, (contactSuccess) => { + addContact(telegramResponse.id, verifiedBy, (contactSuccess) => { res.send({ authorized: success, message: msg, contactSuccess: contactSuccess }); }); } else { @@ -214,25 +272,6 @@ app.post('/login', (req, res) => { }); }); -app.post('/create', (req, res) => { - reqTelegram = req.body.telegram.toLowerCase(); - if (req.session.verified) { - createUser(reqTelegram, req.body.password, (success, msg) => { - cookieExpiry = getCookieExpiry(); - req.session.user = reqTelegram; - if (success) { - addContact(req.session.user, req.session.verifiedBy, (sucesss, msg) => { - res.send({ success: success, message: msg }); - }); - } else { - res.send({ success: success, message: msg }); - } - }); - } else { - res.status(401).send("Not verified"); - } -}) - app.get('/code', (req, res) => { if (!req.session.user) { res.status(401).send("Not logged in"); diff --git a/package-lock.json b/package-lock.json index c32cbe2..5444b11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "axios": "^0.21.1", "bcrypt": "^5.0.1", "connect-session-sequelize": "^7.1.1", "cors": "^2.8.5", @@ -202,6 +203,14 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "optional": true }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -965,6 +974,25 @@ "node": ">=6" } }, + "node_modules/follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", @@ -3431,6 +3459,14 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "optional": true }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4020,6 +4056,11 @@ "locate-path": "^3.0.0" } }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", diff --git a/package.json b/package.json index ab47dcc..5daa337 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { + "axios": "^0.21.1", "bcrypt": "^5.0.1", "connect-session-sequelize": "^7.1.1", "cors": "^2.8.5", From 9a73fb0662ddff34d2246547203c11745669a348 Mon Sep 17 00:00:00 2001 From: Nareshkumar Rao Date: Wed, 28 Jul 2021 19:52:16 +0200 Subject: [PATCH 2/2] postgres is strict about variable type --- app.js | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/app.js b/app.js index 981b8b3..228b314 100644 --- a/app.js +++ b/app.js @@ -60,13 +60,10 @@ Contact.sync(); const User = sequelize.define('User', { telegram: { - type: DataTypes.STRING, + type: DataTypes.INTEGER, allowNull: false, unique: true, }, - hash: { - type: STRING, - }, verification: { type: DataTypes.STRING, }, @@ -130,10 +127,10 @@ function refreshVerification(user, done) { function createQRCode(telegram, done) { User.findOne({ - where: { - telegram: telegram - } - }) + where: { + telegram: telegram + } + }) .then(user => { refreshVerification(user, result => { const verifyURL = `${process.env.WEBSITE_URL}/#/verify/${encodeURIComponent(result.verification)}`; @@ -185,7 +182,10 @@ function addContact(telegram, withUserID, done) { Contact.create({ user: user.id, with: withUserID }) .then(res => { console.log(`Registering contact between ${user.id} and ${withUserID}`); - sendTelegramMessage(withUser.telegram, "Someone scanned your QR code. You will be notified if they are tested positive with Covid. If you are tested positive, please tell this bot /COVIDPOSITIVE"); + sendTelegramMessage(withUser.telegram, + "Someone scanned your QR code. You will be notified if they are tested positive with Covid. If you are tested positive, please tell this bot /COVIDPOSITIVE", + () => {} + ); done(true, "Successfully added contact"); }) .catch(e => { @@ -203,10 +203,10 @@ function getCookieExpiry() { function setTelegramWebHook(done) { const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/setWebhook`; axios.post(url, { - url: `${process.env.SERVER_API_URL}/${process.env.TELEGRAM_SECRET}`, - allowed_updates: [], - drop_pending_updates: true, - }) + url: `${process.env.SERVER_API_URL}/${process.env.TELEGRAM_SECRET}`, + allowed_updates: [], + drop_pending_updates: true, + }) .then(res => { done(res) }) .catch(err => { done(err) }); } @@ -214,9 +214,9 @@ function setTelegramWebHook(done) { function sendTelegramMessage(telegramID, message, done) { const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/sendMessage`; axios.post(url, { - chat_id: telegramID, - text: message, - }) + chat_id: telegramID, + text: message, + }) .then((res) => { done(res) }) @@ -241,11 +241,8 @@ app.use(session({ app.use(cors({ credentials: true, origin: true, secure: true })); app.use(express.json()) -setTelegramWebHook(() => { }); +setTelegramWebHook(() => {}); app.post(`/${process.env.TELEGRAM_SECRET}`, (req, res) => { - if (req.body.message) { - sendTelegramMessage(req.body.message.chat.id, `${req.body.message.text.toUpperCase()}`, (res) => { console.log(res) }); - } res.send(); });