Skip to content

Commit

Permalink
misc: use code for bot dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
embbnux committed Jun 26, 2024
1 parent 8a73eea commit 0cbec6c
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 61 deletions.
14 changes: 7 additions & 7 deletions src/app/handlers/interactiveMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,26 +152,26 @@ async function notificationInteractiveMessagesHandler(req, res) {
};

function getSetupDialog(botId, body) {
const botToken = generateToken({
uId: body.user.extId,
const botCode = generateToken({
_uId: body.user.extId, // make code token different as access token
bId: botId,
gId: body.data.conversationId || body.conversation.id,
}, '24h');
}, 20); // bot code 20s valid
const trackAccountId = getHashValue(body.user.accountId, process.env.ANALYTICS_SECRET_KEY);
return {
type: 'dialog',
dialog: {
title: `Trello setup for ${body.data.conversationName || 'this conversation'}`,
size: 'medium',
iconURL: DIALOG_ICON_URL,
iframeURL: `${process.env.APP_SERVER}/bot-setup?token=${botToken}&trackAccountId=${trackAccountId}`,
iframeURL: `${process.env.APP_SERVER}/bot-setup?code=${botCode}&trackAccountId=${trackAccountId}`,
}
};
}

function getAuthDialog(botId, body) {
const botToken = generateToken({
uId: body.user.extId,
const botCode = generateToken({
_uId: body.user.extId, // make code token different as access token
bId: botId,
gId: body.conversation.id,
}, '24h');
Expand All @@ -182,7 +182,7 @@ function getAuthDialog(botId, body) {
title: `Trello authorization`,
size: 'small',
iconURL: DIALOG_ICON_URL,
iframeURL: `${process.env.APP_SERVER}/bot-auth-setup?token=${botToken}&trackAccountId=${trackAccountId}`,
iframeURL: `${process.env.APP_SERVER}/bot-auth-setup?code=${botCode}&trackAccountId=${trackAccountId}`,
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ app.get('/bot-auth-setup', authorizationRoute.botAuthSetup);
app.post('/trello/bot-revoke', authorizationRoute.botRevokeToken);
extendBotApp(app, [], botHandler, botConfig);
app.get('/trello/bot-oauth-callback/:botToken', authorizationRoute.botOauthCallback);
app.post('/trello/bot-oauth-callback/:botToken', authorizationRoute.botSaveToken);
app.post('/trello/bot-oauth-callback', authorizationRoute.botSaveToken);

exports.app = app;
37 changes: 25 additions & 12 deletions src/app/routes/authorization.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,30 @@ function oauthCallback(req, res) {
};

function botOauthCallback(req, res) {
res.render('bot-oauth-callback');
res.render('bot-oauth-callback', {
authPath: `${process.env.RINGCENTRAL_CHATBOT_SERVER}/trello/bot-oauth-callback`,
botToken: encodeURIComponent(req.params.botToken),
});
}

async function botAuthSetup(req, res) {
const token = req.query.token;
const code = req.query.code;
const decodedCode = decodeToken(code);
if (!decodedCode) {
res.status(401);
res.send('Token invalid, please reopen.');
return;
}
const token = generateToken({
uId: decodedCode._uId,
bId: decodedCode.bId,
gId: decodedCode.gId,
}, '24h');
const trello = new Trello({
appKey: process.env.TRELLO_APP_KEY,
redirectUrl: `${process.env.RINGCENTRAL_CHATBOT_SERVER}/trello/bot-oauth-callback/${token}`,
name: 'RingCentral Bot',
});
const decodedToken = decodeToken(token);
if (!decodedToken) {
res.status(401);
res.send('Token invalid, please reopen.');
return;
}
let trackAccountId = undefined;
if (req.query.trackAccountId) {
// escape the value to prevent XSS
Expand All @@ -62,15 +70,20 @@ async function botAuthSetup(req, res) {
authorizationUri: trello.authorizationUrl({ scope: 'read,write' }),
authorizationRevokeUri: `${process.env.APP_SERVER}/trello/bot-revoke`,
mixpanelKey: process.env.MIXPANEL_KEY,
trackUserId: getHashValue(decodedToken.uId, process.env.ANALYTICS_SECRET_KEY),
trackUserId: getHashValue(decodedCode._uId, process.env.ANALYTICS_SECRET_KEY),
trackAccountId,
trackBotId: getHashValue(decodedToken.bId, process.env.ANALYTICS_SECRET_KEY),
trackBotId: getHashValue(decodedCode.bId, process.env.ANALYTICS_SECRET_KEY),
},
});
}

async function botSaveToken(req, res) {
const botToken = req.params.botToken;
const botToken = req.body.botToken;
if (!botToken) {
res.status(403);
res.send('Params error');
return;
}
const decodedToken = decodeToken(botToken);
if (!decodedToken) {
res.status(401);
Expand All @@ -82,7 +95,7 @@ async function botSaveToken(req, res) {
const cardId = decodedToken.cId;
const conversationId = decodedToken.gId;
const nextAction = decodedToken.next;
const trelloToken = req.query.token;
const trelloToken = req.body.trelloToken;
if (!trelloToken) {
res.status(401);
res.send('Trello token invalid.');
Expand Down
30 changes: 20 additions & 10 deletions src/app/routes/bot-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@ const Bot = require('ringcentral-chatbot-core/dist/models/Bot').default;
const { RcUser } = require('../models/rc-user');
const { TrelloUser } = require('../models/trello-user');
const { TrelloWebhook } = require('../models/trello-webhook');
const { decodeToken } = require('../lib/jwt');
const { decodeToken, generateToken } = require('../lib/jwt');
const { Trello } = require('../lib/Trello');
const { getHashValue } = require('../lib/getHashValue');

async function botSetup(req, res) {
const token = req.query.token;
const code = req.query.code;
if (!code) {
res.status(400);
res.send('Code is required.');
return;
}
const decodedCode = decodeToken(code);
if (!decodedCode) {
res.status(401);
res.send('Token invalid, please reopen');
return;
}
const token = generateToken({
uId: decodedCode._uId,
bId: decodedCode.bId,
gId: decodedCode.gId,
}, '24h');
const trello = new Trello({
appKey: process.env.TRELLO_APP_KEY,
redirectUrl: `${process.env.RINGCENTRAL_CHATBOT_SERVER}/trello/bot-oauth-callback/${token}`,
name: 'RingCentral Bot',
});
const decodedToken = decodeToken(token);
if (!decodedToken) {
res.status(401);
res.send('Token invalid, please reopen');
return;
}
let trackAccountId = undefined;
if (req.query.trackAccountId) {
// escape the value to prevent XSS
Expand All @@ -34,8 +44,8 @@ async function botSetup(req, res) {
authorizationRevokeUri: `${process.env.APP_SERVER}/trello/bot-revoke`,
subscriptionUri: `${process.env.APP_SERVER}/bot-subscription`,
mixpanelKey: process.env.MIXPANEL_KEY,
trackBotId: getHashValue(decodedToken.bId, process.env.ANALYTICS_SECRET_KEY),
trackUserId: getHashValue(decodedToken.uId, process.env.ANALYTICS_SECRET_KEY),
trackBotId: getHashValue(decodedCode.bId, process.env.ANALYTICS_SECRET_KEY),
trackUserId: getHashValue(decodedCode._uId, process.env.ANALYTICS_SECRET_KEY),
trackAccountId,
},
});
Expand Down
11 changes: 10 additions & 1 deletion src/app/views/bot-oauth-callback.pug
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ html
script.
var container = window.document.getElementById('container');
var tokenHash = window.location.hash.substr(1);
var botToken = "#{botToken}";
var parsedQuery = new URLSearchParams(tokenHash);
var authPath = "#{authPath}";
if (parsedQuery.get('error')) {
container.innerText = "Authorization error from Trello.";
} else {
fetch(window.location.pathname + '?' + tokenHash, {
fetch(authPath, {
method: 'POST',
body: JSON.stringify({
trelloToken: parsedQuery.get('token'),
botToken: botToken,
}),
headers: {
'Content-Type': 'application/json',
},
}).then(function(response) {
if (response.status === 200) {
container.innerText = "Authorized! Please close this page and go back to RingCentral conversation with this bot.";
Expand Down
56 changes: 44 additions & 12 deletions test/authorization.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ describe('Trello Authorization', () => {
const token = jwt.generateToken({
id: 'xxx',
});
const res = await request(server).get(`/bot-auth-setup?token=${token}`);
const res = await request(server).get(`/bot-auth-setup?code=${token}`);
expect(res.status).toEqual(200);
expect(res.text).toContain(token);
});

it('should response 403 when save token without token', async () => {
Expand Down Expand Up @@ -191,8 +190,15 @@ describe('Trello Authorization', () => {
});

describe('Bot Save Token', () => {
it('should response 403 when save bot token without bot token', async () => {
const res = await request(server).post('/trello/bot-oauth-callback');
expect(res.status).toEqual(403);
});

it('should response 401 when save bot token with invalid bot token', async () => {
const res = await request(server).post('/trello/bot-oauth-callback/xxx');
const res = await request(server).post('/trello/bot-oauth-callback').send({
botToken: 'xxx',
});
expect(res.status).toEqual(401);
});

Expand All @@ -203,7 +209,9 @@ describe('Trello Authorization', () => {
cId: 'cardId',
gId: 'conversationId',
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
});
expect(res.status).toEqual(401);
});

Expand All @@ -217,7 +225,10 @@ describe('Trello Authorization', () => {
const trelloUserScope = nock('https://api.trello.com')
.get(uri => uri.includes(`/1/members/me?`))
.reply(200, {});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(403);
trelloUserScope.done();
});
Expand All @@ -232,7 +243,10 @@ describe('Trello Authorization', () => {
const trelloUserScope = nock('https://api.trello.com')
.get(uri => uri.includes(`/1/members/me?`))
.reply(401, {});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(401);
trelloUserScope.done();
});
Expand All @@ -247,7 +261,10 @@ describe('Trello Authorization', () => {
const trelloUserScope = nock('https://api.trello.com')
.get(uri => uri.includes(`/1/members/me?`))
.reply(500, {});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(500);
trelloUserScope.done();
});
Expand All @@ -266,7 +283,10 @@ describe('Trello Authorization', () => {
id: trelloUserId,
fullName: 'test name',
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(404);
trelloUserScope.done();
});
Expand Down Expand Up @@ -304,7 +324,10 @@ describe('Trello Authorization', () => {
rcAuthCardPutScope.once('request', ({ headers: requestHeaders }, interceptor, reqBody) => {
requestBody = JSON.parse(reqBody);
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(200);
expect(requestBody.fallbackText).toContain('Connected with Trello successfully');
const rcUser = await RcUser.findByPk(`rcext-${rcUserId}`);
Expand Down Expand Up @@ -359,7 +382,10 @@ describe('Trello Authorization', () => {
rcAuthCardPutScope.once('request', ({ headers: requestHeaders }, interceptor, reqBody) => {
requestBody = JSON.parse(reqBody);
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(200);
expect(requestBody.fallbackText).toContain('Connected with Trello successfully');
trelloUserRecord = await TrelloUser.findByPk(trelloUserId);
Expand Down Expand Up @@ -401,7 +427,10 @@ describe('Trello Authorization', () => {
id: trelloUserId,
fullName: 'test name',
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(200);
trelloUserRecord = await TrelloUser.findByPk(trelloUserId);
expect(trelloUserRecord.writeable_token).toEqual('xxx');
Expand Down Expand Up @@ -458,7 +487,10 @@ describe('Trello Authorization', () => {
rcCardPutScope.once('request', ({ headers: requestHeaders }, interceptor, reqBody) => {
requestBody = JSON.parse(reqBody);
});
const res = await request(server).post(`/trello/bot-oauth-callback/${botToken}?token=xxx`);
const res = await request(server).post(`/trello/bot-oauth-callback`).send({
botToken,
trelloToken: 'xxx',
});
expect(res.status).toEqual(200);
expect(requestBody.fallbackText).toContain('Trello setup for **test team**');
const rcUser = await RcUser.findByPk(`rcext-${rcUserId}`);
Expand Down
Loading

0 comments on commit 0cbec6c

Please sign in to comment.