Skip to content
Open
65 changes: 65 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"cSpell.ignoreWords": [
"autogenerated",
"boop",
"braintree",
"buildkite",
"camelcase",
"caniuse",
"chartmetric",
"codecov",
"codegen",
"codeship",
"ddex",
"dedupe",
"deployers",
"destructure",
"dont",
"dropzone",
"entrypoint",
"eval",
"feature",
"ffmpeg",
"flexbox",
"flowtype",
"ftui",
"geocountry",
"githooks",
"graphdoc",
"has",
"hocs",
"kubectl",
"kubernetes",
"loadables",
"luxon",
"minitest",
"nacl",
"name",
"new",
"noopener",
"noreferrer",
"observee",
"paypal",
"pipefail",
"prebuild",
"raygun",
"recaptcha",
"repos",
"rubocop",
"scrollable",
"semibold",
"soundcloud",
"tandc",
"tcomb",
"theming",
"tipalti",
"turbolinks",
"typeof",
"unmock",
"unstyled",
"vevo",
"vydia",
"vydiadev",
"youtube"
],
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"test:watch": "yarn test --watchAll"
},
"dependencies": {
"js-nacl": "^1.3.2",
"autoprefixer": "^10.1.0",
"discord.js": "^12.5.1",
"luxon": "^1.25.0",
Expand Down
77 changes: 77 additions & 0 deletions pages/api/discord.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import naclFactory from 'js-nacl'
import type { NextApiRequest, NextApiResponse } from 'next'

export const config = {
api: {
bodyParser: false,
}
}

const PUBLIC_KEY = '516311b92a3f7ef74e8034274aedcad679216d5f19183becf4a627b06b9884d4'
const RESPONSE_TYPES = {
'PONG': 1,
'ACK_NO_SOURCE': 2,
'MESSAGE_NO_SOURCE': 3,
'MESSAGE_WITH_SOURCE': 4,
'ACK_WITH_SOURCE': 5
}

const verifySignature = (rawBody: string, headers: Object) => {
const authSig = headers['x-signature-ed25519']
const authTs = headers['x-signature-timestamp']
const authT: string = typeof(authTs) === 'string' ? authTs : authTs[0]

console.log('raw body: ', rawBody)

naclFactory.instantiate((nacl) => {
const verified = nacl.crypto_sign_verify_detached(
nacl.from_hex(authSig),
`${encodeURI(authT)}${encodeURI(rawBody)}`,
nacl.from_hex(PUBLIC_KEY)
)
console.log(verified)
return verified
})
}

export default async (req: NextApiRequest, res: NextApiResponse) => {
// console.log(`headers: ${JSON.stringify(req.headers)}`)
// console.log(`body: ${JSON.stringify(req.body)}`)

const rawBody: string = await new Promise((resolve) => {
if (!req.body) {
let buffer = ''
req.on('data', (chunk) => {
console.log(chunk)
buffer += chunk
})

req.on('end', () => {
resolve(buffer)
})
}
})
const body = JSON.parse(Buffer.from(rawBody).toString())

console.log(`raw body: ${rawBody}`)
console.log(`body: ${JSON.stringify(body)}`)
try {
verifySignature(rawBody, req.headers)
} catch {
console.error('[UNAUTHORIZED] Invalid request signature: {e}')
}

if (body['type'] == 1) {
return {'type': 1}
}

return {
'type': RESPONSE_TYPES['MESSAGE_NO_SOURCE'],
'data': {
'tts': false,
'content': 'BEEP BOOP',
'embeds': [],
'allowed_mentions': []
}
}
}
Loading