From e51eba54d6a02aed4c5d54b970c51f3287742d83 Mon Sep 17 00:00:00 2001 From: Embbnux Ji Date: Mon, 22 Jul 2024 15:55:05 +0800 Subject: [PATCH] misc: do not save user name in DB (#97) * misc: do not save user name in DB * chore: add maintain job --- src/app/bot/actions.js | 2 + src/app/handlers/interactiveMessages.js | 14 ++-- src/app/index.js | 2 + src/app/models/trello-user.js | 4 +- src/app/routes/authorization.js | 16 +++-- src/app/routes/bot-setup.js | 8 ++- src/app/routes/maintain.js | 45 +++++++++++++ src/app/routes/webhooks.js | 4 ++ test/bot-setup.test.js | 19 +++++- test/maintain.test.js | 86 +++++++++++++++++++++++++ 10 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 src/app/routes/maintain.js create mode 100644 test/maintain.test.js diff --git a/src/app/bot/actions.js b/src/app/bot/actions.js index 46f2f16..e1fa1a0 100644 --- a/src/app/bot/actions.js +++ b/src/app/bot/actions.js @@ -109,6 +109,8 @@ async function handleUnauthorize({ }); await trello.revokeToken(); trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); await bot.sendMessage(group.id, { text: `Hi ![:Person](${user.id}), you have unauthorized Trello successfully.`, diff --git a/src/app/handlers/interactiveMessages.js b/src/app/handlers/interactiveMessages.js index a3a05c0..b66a336 100644 --- a/src/app/handlers/interactiveMessages.js +++ b/src/app/handlers/interactiveMessages.js @@ -68,14 +68,14 @@ async function notificationInteractiveMessagesHandler(req, res) { } if (trelloUser) { trelloUser.writeable_token = body.data.token; - trelloUser.username = trelloUserInfo.username; - trelloUser.fullName = trelloUserInfo.fullName; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); } else { trelloUser = await TrelloUser.create({ id: trelloUserInfo.id, - username: trelloUserInfo.username, - fullName: trelloUserInfo.fullName, + username: '', + fullName: '', writeable_token: token, }); } @@ -129,6 +129,8 @@ async function notificationInteractiveMessagesHandler(req, res) { if (e.response) { if (e.response.status === 401) { trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); await sendAuthorizeRequestCard(trelloWebhook.rc_webhook_id, webhookId); res.status(200); @@ -275,6 +277,8 @@ async function botInteractiveMessagesHandler(req, res) { trello.setToken(trelloUser.writeable_token); await trello.revokeToken(); trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); if (rcUser.bot_subscriptions) { await TrelloWebhook.destroy({ @@ -359,6 +363,8 @@ async function botInteractiveMessagesHandler(req, res) { e.response.config.url.indexOf('api.trello.com') > -1 ) { trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); res.status(200); res.json(getAuthDialog(botId, body)); diff --git a/src/app/index.js b/src/app/index.js index 5579cdf..9f54614 100644 --- a/src/app/index.js +++ b/src/app/index.js @@ -8,6 +8,7 @@ const authorizationRoute = require('./routes/authorization'); const webhooksRoute = require('./routes/webhooks'); const notificationRoute = require('./routes/notification'); const botSetupRoute = require('./routes/bot-setup'); +const maintainRoute = require('./routes/maintain'); const { botHandler } = require('./bot/handler'); const { botConfig } = require('./bot/config'); @@ -77,6 +78,7 @@ app.post('/trello/bot-revoke', refererChecker, authorizationRoute.botRevokeToken extendBotApp(app, [], botHandler, botConfig); app.get('/trello/bot-oauth-callback/:botToken', authorizationRoute.botOauthCallback); app.post('/trello/bot-oauth-callback', refererChecker, authorizationRoute.botSaveToken); +app.get('/maintain/remove-user-name', maintainRoute.removeUserName); app.use(function (err, req, res, next) { errorLogger(err); diff --git a/src/app/models/trello-user.js b/src/app/models/trello-user.js index 2226bf3..f14d6ac 100644 --- a/src/app/models/trello-user.js +++ b/src/app/models/trello-user.js @@ -8,10 +8,10 @@ exports.TrelloUser = sequelize.define('trello-users', { primaryKey: true, }, username: { - type: Sequelize.STRING + type: Sequelize.STRING // no need, will be cleaned up in DB }, fullName: { - type: Sequelize.STRING + type: Sequelize.STRING // no need, will be cleaned up in DB }, token: { type: Sequelize.STRING diff --git a/src/app/routes/authorization.js b/src/app/routes/authorization.js index 7f79c55..42a8080 100644 --- a/src/app/routes/authorization.js +++ b/src/app/routes/authorization.js @@ -125,12 +125,14 @@ async function botSaveToken(req, res) { let trelloUser = await TrelloUser.findByPk(trelloUserInfo.id); if (trelloUser) { trelloUser.writeable_token = trelloToken; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); } else { trelloUser = await TrelloUser.create({ id: trelloUserInfo.id, - username: trelloUserInfo.username, - fullName: trelloUserInfo.fullName, + username: '', + fullName: '', writeable_token: trelloToken, }); } @@ -202,12 +204,14 @@ async function saveToken(req, res) { let trelloUser = await TrelloUser.findByPk(userInfo.id); if (trelloUser) { trelloUser.token = token; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); } else { trelloUser = await TrelloUser.create({ id: userInfo.id, - username: userInfo.username, - fullName: userInfo.fullName, + username: '', + fullName: '', token, }); } @@ -253,6 +257,8 @@ async function revokeToken(req, res) { }); await trello.revokeToken(); trelloUser.token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); } res.status(200); @@ -303,6 +309,8 @@ async function botRevokeToken(req, res) { trello.setToken(trelloUser.writeable_token); await trello.revokeToken(); trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); if (rcUser.bot_subscriptions && rcUser.bot_subscriptions.length > 0) { await TrelloWebhook.destroy({ diff --git a/src/app/routes/bot-setup.js b/src/app/routes/bot-setup.js index 501c28f..cbd35cc 100644 --- a/src/app/routes/bot-setup.js +++ b/src/app/routes/bot-setup.js @@ -93,7 +93,7 @@ async function info(req, res) { if (trelloUser) { botInfo.trelloAuthorized = !!trelloUser.writeable_token; botInfo.trelloUser = { - fullName: trelloUser.fullName, + fullName: '', }; if (trelloUser.writeable_token) { const trello = new Trello({ @@ -102,6 +102,8 @@ async function info(req, res) { token: trelloUser.writeable_token, }); botInfo.boards = await trello.getBoards(); + const trelloUserInfo = await trello.getUserInfo(); + botInfo.trelloUser.fullName = trelloUserInfo.fullName; } } } @@ -114,6 +116,8 @@ async function info(req, res) { trelloUser ) { trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); botInfo.trelloAuthorized = false; res.status(200); @@ -243,6 +247,8 @@ async function saveSubscription(req, res) { trelloUser ) { trelloUser.writeable_token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); res.status(401); res.send('Trello authorization required'); diff --git a/src/app/routes/maintain.js b/src/app/routes/maintain.js new file mode 100644 index 0000000..896294c --- /dev/null +++ b/src/app/routes/maintain.js @@ -0,0 +1,45 @@ +const { TrelloUser } = require('../models/trello-user'); +const { errorLogger } = require('../lib/logger'); + +async function removeUserName(req, res) { + if (!process.env.MAINTAIN_TOKEN) { + res.status(404); + res.send('Not found'); + return; + } + if (req.query.maintain_token !== process.env.MAINTAIN_TOKEN) { + res.status(403); + res.send('Forbidden'); + return; + } + let lastKey = req.query.last_key; + try { + const trelloUsers = await TrelloUser.findAll({ + limit: 50, + lastKey: lastKey ? { id: lastKey } : undefined, + }); + if (trelloUsers.lastKey) { + lastKey = trelloUsers.lastKey.id; + } else { + lastKey = ''; + } + for (const trelloUser of trelloUsers) { + if (!!trelloUser.username || !!trelloUser.fullName) { + await TrelloUser.update({ + username: '', + fullName: '', + }, { where: { id: trelloUser.id } }); + } + } + res.status(200); + res.json({ + lastKey, + }); + } catch (e) { + errorLogger(e); + res.status(500); + res.send('Internal error'); + } +} + +exports.removeUserName = removeUserName; \ No newline at end of file diff --git a/src/app/routes/webhooks.js b/src/app/routes/webhooks.js index 0c684e5..0712659 100644 --- a/src/app/routes/webhooks.js +++ b/src/app/routes/webhooks.js @@ -84,6 +84,8 @@ async function webhookInfo(req, res) { if (e.response && e.response.status === 401) { if (trelloUser) { trelloUser.token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); } res.status(401); @@ -187,6 +189,8 @@ async function createWebhook(req, res) { } catch (e) { if (e.response && e.response.status === 401) { trelloUser.token = ''; + trelloUser.username = ''; + trelloUser.fullName = ''; await trelloUser.save(); res.status(401); res.send('Unauthorized'); diff --git a/test/bot-setup.test.js b/test/bot-setup.test.js index 568984c..8f20a90 100644 --- a/test/bot-setup.test.js +++ b/test/bot-setup.test.js @@ -183,6 +183,11 @@ describe('Bot Setup', () => { "id": "5b689b3228998cf3f01c629e", }, ]); + const trelloUserScope = nock('https://api.trello.com') + .get(uri => uri.includes(`/1/members/me?`)) + .reply(200, { + fullName: 'test_user', + }); const res = await request(server) .get('/bot-info') .set('Referer', process.env.RINGCENTRAL_CHATBOT_SERVER) @@ -190,7 +195,9 @@ describe('Bot Setup', () => { expect(res.status).toEqual(200); expect(res.body.trelloAuthorized).toEqual(true); expect(res.body.boards.length).toEqual(2); + expect(res.body.trelloUser.fullName).toEqual('test_user'); trelloBoardScope.done(); + trelloUserScope.done(); await rcUserRecord.destroy(); await trelloUserRecord.destroy(); }); @@ -232,6 +239,11 @@ describe('Bot Setup', () => { "id": "5b689b3228998cf3f01c629e", }, ]); + const trelloUserScope = nock('https://api.trello.com') + .get(uri => uri.includes(`/1/members/me?`)) + .reply(200, { + fullName: 'test_user', + }); const res = await request(server) .get('/bot-info') .set('Referer', process.env.RINGCENTRAL_CHATBOT_SERVER) @@ -242,6 +254,7 @@ describe('Bot Setup', () => { expect(res.body.subscriptions.length).toEqual(1); expect(res.body.subscriptions[0].id).toEqual('test_2'); trelloBoardScope.done(); + trelloUserScope.done(); await rcUserRecord.destroy(); await trelloUserRecord.destroy(); }); @@ -276,7 +289,7 @@ describe('Bot Setup', () => { await trelloUserRecord.destroy(); }); - it('should get 500 when require trello 500', async () => { + it('should get 500 when request trello 500', async () => { const rcUserId = 'test_rc_user_id_123'; const trelloUserId = 'trello-user-123'; const trelloUserRecord = await TrelloUser.create({ @@ -890,10 +903,10 @@ describe('Bot Setup', () => { expect(res.status).toEqual(401); const newTrelloUserRecord = await TrelloUser.findByPk(trelloUserId); expect(newTrelloUserRecord.writeable_token).toEqual(''); + trelloLabelsScope.done(); await rcUserRecord.destroy(); await trelloUserRecord.destroy(); await trelloWebhookRecord.destroy(); - trelloLabelsScope.done(); }); it('should return 500 when fetch trello labels 500 at create subscription', async () => { @@ -1405,9 +1418,9 @@ describe('Bot Setup', () => { expect(newRcUserRecord.bot_subscriptions.length).toEqual(0); const newTrelloWebhookRecord = await TrelloWebhook.findByPk(subscriptionId); expect(!!newTrelloWebhookRecord).toEqual(false); + trelloDeleteWebhooksScope.done(); await rcUserRecord.destroy(); await trelloUserRecord.destroy(); - trelloDeleteWebhooksScope.done(); }); }); }); diff --git a/test/maintain.test.js b/test/maintain.test.js new file mode 100644 index 0000000..9ecab1a --- /dev/null +++ b/test/maintain.test.js @@ -0,0 +1,86 @@ +const request = require('supertest'); +const { server } = require('../src/server'); +const { TrelloUser } = require('../src/app/models/trello-user'); + +describe('Maintain', () => { + it('should return 404 when no MAINTAIN_TOKEN env', async () => { + const res = await request(server).get('/maintain/remove-user-name'); + expect(res.status).toEqual(404); + }); + + it('should return 403 when maintain_token is invalid', async () => { + process.env.MAINTAIN_TOKEN = 'valid'; + const res = await request(server).get('/maintain/remove-user-name?maintain_token=invalid'); + expect(res.status).toEqual(403); + delete process.env.MAINTAIN_TOKEN; + }); + + it('should return 200 when maintain_token is valid', async () => { + await TrelloUser.create({ + id: '111', + username: 'test', + fullName: 'test', + writeable_token: 'test111', + }); + await TrelloUser.create({ + id: '222', + username: '', + fullName: '', + writeable_token: 'test222', + }); + await TrelloUser.create({ + id: '333', + username: '333name', + fullName: '333name', + writeable_token: 'test333', + }); + process.env.MAINTAIN_TOKEN = 'valid'; + const res = await request(server).get(`/maintain/remove-user-name?maintain_token=${process.env.MAINTAIN_TOKEN}`); + expect(res.status).toEqual(200); + expect(res.body.lastKey).toEqual(''); + const user1 = await TrelloUser.findByPk('111'); + expect(user1.username).toEqual(''); + expect(user1.fullName).toEqual(''); + expect(user1.writeable_token).toEqual('test111'); + const user2 = await TrelloUser.findByPk('222'); + expect(user2.username).toEqual(''); + expect(user2.fullName).toEqual(''); + expect(user2.writeable_token).toEqual('test222'); + const user3 = await TrelloUser.findByPk('333'); + expect(user3.username).toEqual(''); + expect(user3.fullName).toEqual(''); + expect(user3.writeable_token).toEqual('test333'); + delete process.env.MAINTAIN_TOKEN; + await TrelloUser.destroy({ where: { id: '111' } }); + await TrelloUser.destroy({ where: { id: '222' } }); + await TrelloUser.destroy({ where: { id: '333' } }); + }); + + it('should return 200 when maintain_token is valid', async () => { + await TrelloUser.create({ + id: '111', + username: 'test', + fullName: 'test', + writeable_token: 'test111', + }); + await TrelloUser.create({ + id: '222', + username: '', + fullName: '', + writeable_token: 'test222', + }); + await TrelloUser.create({ + id: '333', + username: '333name', + fullName: '333name', + writeable_token: 'test333', + }); + process.env.MAINTAIN_TOKEN = 'valid'; + const res = await request(server).get(`/maintain/remove-user-name?maintain_token=${process.env.MAINTAIN_TOKEN}&last_key=111`); + expect(res.status).toEqual(200); + delete process.env.MAINTAIN_TOKEN; + await TrelloUser.destroy({ where: { id: '111' } }); + await TrelloUser.destroy({ where: { id: '222' } }); + await TrelloUser.destroy({ where: { id: '333' } }); + }); +});