Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(captcha): use Slack captcha handler token when provided #2460

Merged
merged 4 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/messaging/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export async function sendDMAsync(
} catch (error: unknown) {
logger.error("✖ couldn't send discord DM", error);
}
} else {
logger.warn("✖ couldn't send discord DM, missing configuration");
}
return;
}
Expand All @@ -122,6 +124,7 @@ export async function getDMResponseAsync(
botMessage: Discord.Message | undefined,
timeout: number
): Promise<string> {
if (!botMessage) return '';
const iterations = Math.max(Math.floor(timeout / pollInterval), 1);
let iteration = 0;
const client = await getDiscordClientAsync();
Expand Down Expand Up @@ -195,7 +198,7 @@ async function getDiscordClientAsync() {
}

async function getDMChannelAsync(client?: Discord.Client) {
if (!dmChannelInstance && userId && !!client) {
if (!dmChannelInstance && userId && client) {
const user = await new Discord.User(client, {
id: userId,
}).fetch();
Expand Down
87 changes: 62 additions & 25 deletions src/messaging/slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,35 @@ import {Print, logger} from '../logger';
import {WebClient} from '@slack/web-api';
import {config} from '../config';

const {channel, token} = config.notifications.slack;
const {pollInterval, responseTimeout, userId} = config.captchaHandler;
const web = new WebClient(token);
type ClientTypes = 'service' | 'captcha';
type ClientMap<T> = {
[clientType in ClientTypes]: T;
};

export function sendSlackMessage(link: Link, store: Store) {
if (channel && token) {
const {channel} = config.notifications.slack;
const {pollInterval, responseTimeout, userId} = config.captchaHandler;
const clients: ClientMap<WebClient | undefined> = {
service: undefined,
captcha: undefined,
};
const tokens: ClientMap<string> = {
service: config.notifications.slack.token,
captcha: config.captchaHandler.token,
};

export function sendSlackMessage(
link: Link,
store: Store,
client: WebClient = getClient()
) {
if (channel && client.token) {
logger.debug('↗ sending slack message');

(async () => {
const givenUrl = link.cartUrl ? link.cartUrl : link.url;

try {
const result = await web.chat.postMessage({
const result = await client.chat.postMessage({
channel: channel.replace('#', ''),
text: `${Print.inStock(link, store)}\n${givenUrl}`,
});
Expand All @@ -33,12 +49,15 @@ export function sendSlackMessage(link: Link, store: Store) {
}
}

export async function sendDMAsync(payload: string) {
if (userId && token) {
export async function sendDMAsync(
payload: string,
client: WebClient = getClient()
) {
if (userId && client.token) {
logger.debug('↗ sending slack DM');

try {
const dmResult = await web.conversations.open({
const dmResult = await client.conversations.open({
users: `${userId}`,
return_im: false,
});
Expand All @@ -48,8 +67,10 @@ export async function sendDMAsync(payload: string) {
return;
}

const result = await web.chat.postMessage({
channel: (dmResult as any).channel?.id.replace('#', ''),
const dmChannel = (dmResult as any).channel?.id.replace('#', '');
logger.debug(`sending DM to channel id ${dmChannel}...`);
const result = await client.chat.postMessage({
channel: dmChannel,
text: payload,
});

Expand All @@ -59,19 +80,22 @@ export async function sendDMAsync(payload: string) {
}

logger.info('✔ slack DM sent');

return {ts: (result as any).ts, channel: (result as any).channel};
return result as any;
} catch (error: unknown) {
logger.error("✖ couldn't send slack DM", error);
}
} else {
logger.warn("✖ couldn't send slack DM, missing configuration");
}
return;
}

export async function getDMResponseAsync(
dmId: any,
timeout: number
botMessage: any,
timeout: number,
client: WebClient = getClient()
): Promise<string> {
if (!botMessage || !client.token) return '';
const iterations = Math.max(Math.floor(timeout / pollInterval), 1);
let iteration = 0;
return new Promise(resolve => {
Expand All @@ -84,9 +108,9 @@ export async function getDMResponseAsync(
try {
iteration++;

const threadResult = await web.conversations.replies({
channel: dmId.channel,
ts: dmId.ts,
const threadResult = await client.conversations.replies({
channel: botMessage.channel,
ts: botMessage.ts,
});

if (!threadResult.ok) {
Expand All @@ -106,9 +130,9 @@ export async function getDMResponseAsync(
.sort((a: any, b: any) => Number(b.ts) - Number(a.ts))[0];
if (!lastUserMessage) {
if (iteration >= iterations) {
await web.chat.postMessage({
channel: dmId.channel,
thread_ts: dmId.ts,
await client.chat.postMessage({
channel: botMessage.channel,
thread_ts: botMessage.ts,
text: 'Timed out waiting for response... :crying_cat_face:',
});
logger.error('✖ no response from user');
Expand All @@ -117,8 +141,8 @@ export async function getDMResponseAsync(
} else {
response = lastUserMessage.text;

await web.reactions.add({
channel: dmId.channel,
await client.reactions.add({
channel: botMessage.channel,
name: 'white_check_mark',
timestamp: lastUserMessage.ts,
});
Expand All @@ -140,6 +164,19 @@ export async function getSlackCaptchaInputAsync(
payload: string,
timeout?: number
): Promise<string> {
const dmId = await sendDMAsync(payload);
return await getDMResponseAsync(dmId, timeout || responseTimeout);
const captchaClient = getClient('captcha');
const botMessage = await sendDMAsync(payload, captchaClient);
return await getDMResponseAsync(
botMessage,
timeout || responseTimeout,
captchaClient
);
}

function getClient(clientType: ClientTypes = 'service'): WebClient {
if (!clients[clientType]) {
const token = tokens[clientType] || tokens['service']; // attempt to fall back to service token
clients[clientType] = new WebClient(token);
}
return clients[clientType] as WebClient;
}