diff --git a/.env.example b/.env.example index 2f1884c..6611360 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,4 @@ NUXT_SESSION_PASSWORD= NUXT_WEBHOOKS_URL= NUXT_STRAVA_VERIFY_TOKEN= NUXT_HUB_PROJECT_KEY= +NUXT_HOOKDECK_KEY= diff --git a/nuxt.config.ts b/nuxt.config.ts index 8d5915e..70beb67 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -11,6 +11,7 @@ export default defineNuxtConfig({ runtimeConfig: { webhooksUrl: "", stravaVerifyToken: "", + hookdeckKey: "", openaiApiKey: "", databaseUrl: "", public: { diff --git a/server/routes/webhooks/strava/activity-create.post.ts b/server/routes/webhooks/strava/activity-create.post.ts index 0046512..60d059b 100644 --- a/server/routes/webhooks/strava/activity-create.post.ts +++ b/server/routes/webhooks/strava/activity-create.post.ts @@ -1,6 +1,8 @@ import { createActivityContent } from "~~/server/utils/create-content"; export default defineEventHandler(async (event) => { + await validateHookdeck(event); + const body = await readBody(event); const db = useDrizzle(); diff --git a/server/routes/webhooks/strava/athlete-update.post.ts b/server/routes/webhooks/strava/athlete-update.post.ts index 3cfc201..fb76fd1 100644 --- a/server/routes/webhooks/strava/athlete-update.post.ts +++ b/server/routes/webhooks/strava/athlete-update.post.ts @@ -2,6 +2,8 @@ import { get } from "radash"; import { eq } from "drizzle-orm"; export default defineEventHandler(async (event) => { + await validateHookdeck(event); + const body = await readBody(event); const db = useDrizzle(); diff --git a/server/routes/webhooks/strava/index.post.ts b/server/routes/webhooks/strava/index.post.ts index 2ff9ea1..e8f21e7 100644 --- a/server/routes/webhooks/strava/index.post.ts +++ b/server/routes/webhooks/strava/index.post.ts @@ -1,6 +1,9 @@ import { get } from "radash"; export default defineEventHandler(async (event) => { + await validateHookdeck(event); + + const config = useRuntimeConfig(); const body = await readBody(event); const aspectType = get(body, "aspect_type"); @@ -9,5 +12,8 @@ export default defineEventHandler(async (event) => { await $fetch(`/webhooks/strava/${objectType}-${aspectType}`, { method: "post", body, + headers: { + "X-Hookdeck-Key": config.hookdeckKey, + }, }); }); diff --git a/server/utils/hookdeck-validation.ts b/server/utils/hookdeck-validation.ts new file mode 100644 index 0000000..e108c46 --- /dev/null +++ b/server/utils/hookdeck-validation.ts @@ -0,0 +1,19 @@ +import type { H3Event } from "h3"; +import { isEmpty } from "radash"; + +export const validateHookdeck = async (event: H3Event) => { + const hookdeckKeyHeader = getHeader(event, "X-Hookdeck-Key"); + const config = useRuntimeConfig(); + + if (isEmpty(hookdeckKeyHeader)) { + throw createError({ + status: 401, + }); + } + + if (hookdeckKeyHeader !== config.hookdeckKey) { + throw createError({ + status: 401, + }); + } +};