mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-04-24 19:39:11 +00:00
fix interactions, apparently cfw doesn't speak Buffer
This commit is contained in:
parent
7007cfea9d
commit
544ef1b2f0
5 changed files with 56 additions and 20 deletions
|
@ -10,10 +10,15 @@ export const helloWorld: InteractionHandler = (
|
||||||
interaction: InteractionRequest,
|
interaction: InteractionRequest,
|
||||||
context: Context
|
context: Context
|
||||||
): InteractionResponse => {
|
): InteractionResponse => {
|
||||||
|
console.log({ interaction });
|
||||||
return {
|
return {
|
||||||
type: InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE,
|
type: InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE,
|
||||||
data: {
|
data: {
|
||||||
content: `Hey there, ${interaction.member?.nick || interaction.user?.username}`,
|
content: `Hey there, ${
|
||||||
|
interaction.member?.nick ||
|
||||||
|
interaction.member?.user?.username ||
|
||||||
|
interaction.user?.username
|
||||||
|
}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,27 +13,50 @@ export const verifyRequest = async (
|
||||||
request: Request,
|
request: Request,
|
||||||
interaction: InteractionRequest
|
interaction: InteractionRequest
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
const timestamp = request.headers.get('x-signature-timestamp');
|
try {
|
||||||
const signature = request.headers.get('x-signature-ed25519');
|
const timestamp = request.headers.get('x-signature-timestamp');
|
||||||
|
const signature = request.headers.get('x-signature-ed25519');
|
||||||
|
|
||||||
if (!timestamp || !signature) {
|
if (!timestamp || !signature) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = await crypto.subtle.importKey(
|
||||||
|
'raw',
|
||||||
|
bufferizeHex(config.publicKey),
|
||||||
|
{ name: 'NODE-ED25519', namedCurve: 'NODE-ED25519', public: true } as any,
|
||||||
|
false,
|
||||||
|
['verify']
|
||||||
|
);
|
||||||
|
|
||||||
|
const verified = await crypto.subtle.verify(
|
||||||
|
'NODE-ED25519',
|
||||||
|
key,
|
||||||
|
bufferizeHex(signature),
|
||||||
|
bufferizeString(timestamp + JSON.stringify(interaction))
|
||||||
|
);
|
||||||
|
|
||||||
|
return verified;
|
||||||
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const key = await crypto.subtle.importKey(
|
// Cloudflare Workers + SubtleCrypto has no idea what a Buffer.from() is.
|
||||||
'raw',
|
// What the fuck?
|
||||||
Buffer.from(config.publicKey, 'hex'),
|
const bufferizeHex = (input: string) => {
|
||||||
{ name: 'NODE-ED25519', namedCurve: 'NODE-ED25519', public: true } as any,
|
const buffer = new Uint8Array(input.length / 2);
|
||||||
false,
|
|
||||||
['verify']
|
|
||||||
);
|
|
||||||
|
|
||||||
return crypto.subtle.verify(
|
for (let i = 0; i < input.length; i += 2) {
|
||||||
'NODE-ED25519',
|
buffer[i / 2] = parseInt(input.substring(i, i + 2), 16);
|
||||||
key,
|
}
|
||||||
Buffer.from(signature, 'hex'),
|
|
||||||
Buffer.from(timestamp + JSON.stringify(interaction))
|
return buffer;
|
||||||
);
|
};
|
||||||
|
|
||||||
|
const bufferizeString = (input: string) => {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
return encoder.encode(input);
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InteractionHandler = ((
|
export type InteractionHandler = ((
|
||||||
|
@ -59,7 +82,7 @@ export const runAsync = async (
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
type: InteractionCallbackType.DEFERRED_UPDATE_MESSAGE,
|
type: InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
|
||||||
data: {
|
data: {
|
||||||
flags: handler.ephemeral ? InteractionFlags.EPHEMERAL : 0,
|
flags: handler.ephemeral ? InteractionFlags.EPHEMERAL : 0,
|
||||||
...response.data,
|
...response.data,
|
||||||
|
@ -82,7 +105,7 @@ export const runAsync = async (
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
type: InteractionCallbackType.DEFERRED_UPDATE_MESSAGE,
|
type: InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE,
|
||||||
data: {
|
data: {
|
||||||
content: "I'm sorry, I'm having trouble processing this request.",
|
content: "I'm sorry, I'm having trouble processing this request.",
|
||||||
flags: InteractionFlags.EPHEMERAL,
|
flags: InteractionFlags.EPHEMERAL,
|
||||||
|
|
|
@ -30,14 +30,17 @@ export const handleInteraction: RoleypolyHandler = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await verifyRequest(context.config, request, interaction))) {
|
if (!(await verifyRequest(context.config, request, interaction))) {
|
||||||
|
console.warn('interactions: invalid signature');
|
||||||
return new Response('invalid request signature', { status: 401 });
|
return new Response('invalid request signature', { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interaction.type !== InteractionType.APPLICATION_COMMAND) {
|
if (interaction.type !== InteractionType.APPLICATION_COMMAND) {
|
||||||
if (interaction.type === InteractionType.PING) {
|
if (interaction.type === InteractionType.PING) {
|
||||||
|
console.info('interactions: ping');
|
||||||
return json({ type: InteractionCallbackType.PONG });
|
return json({ type: InteractionCallbackType.PONG });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.warn('interactions: not application command');
|
||||||
return json({ err: 'not implemented' }, { status: 400 });
|
return json({ err: 'not implemented' }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const corsHeaders = {
|
||||||
'Access-Control-Max-Age': '86400',
|
'Access-Control-Max-Age': '86400',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const noContent = () => new Response(null, { status: 204 });
|
export const noContent = () => new Response(null, { status: 204, headers: corsHeaders });
|
||||||
export const seeOther = (url: string) =>
|
export const seeOther = (url: string) =>
|
||||||
new Response(
|
new Response(
|
||||||
`<!doctype html>If you are not redirected soon, <a href="${url}">click here.</a>`,
|
`<!doctype html>If you are not redirected soon, <a href="${url}">click here.</a>`,
|
||||||
|
|
5
terraform/interactions.tf
Normal file
5
terraform/interactions.tf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
resource "discord-interactions_guild_command" "hello-world" {
|
||||||
|
name = "hello-world"
|
||||||
|
description = "Says hello!"
|
||||||
|
guild_id = "386659935687147521"
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue