feat: add API Key security for POST uploads

This commit is contained in:
Divlo 2022-04-08 18:46:36 +02:00
parent 7d8b88d5d2
commit ddab264c7f
No known key found for this signature in database
GPG Key ID: 8F9478F220CE65E9
11 changed files with 84 additions and 7 deletions

View File

@ -2,3 +2,4 @@ HOST='0.0.0.0'
PORT='8000'
NODE_ENV='development'
API_URL='http://localhost:8000'
API_KEY='apiKeySecret'

1
.gitignore vendored
View File

@ -35,3 +35,4 @@ npm-debug.log*
# misc
.DS_Store
/uploads

View File

@ -12,7 +12,7 @@ const parameters = Type.Object({
type Parameters = Static<typeof parameters>
export const getServiceSchema: FastifySchema = {
tags: ['uploads'] as string[],
tags: ['guilds'] as string[],
params: parameters,
response: {
200: {

View File

@ -8,15 +8,23 @@ import {
MAXIMUM_IMAGE_SIZE,
SUPPORTED_IMAGE_MIMETYPE
} from '../../../tools/configurations/index.js'
import verifyAPIKey from '../../../tools/plugins/verifyAPIKey.js'
const postServiceSchema: FastifySchema = {
description: 'Uploads guild icon',
tags: ['uploads'] as string[],
tags: ['guilds'] as string[],
security: [
{
apiKeyAuth: []
}
] as Array<{ [key: string]: [] }>,
consumes: ['multipart/form-data'] as string[],
produces: ['application/json'] as string[],
response: {
201: Type.String(),
400: fastifyErrors[400],
401: fastifyErrors[401],
403: fastifyErrors[403],
431: fastifyErrors[431],
500: fastifyErrors[500]
}
@ -26,12 +34,16 @@ export const postGuildsUploadsIconService: FastifyPluginAsync = async (
fastify
) => {
await fastify.register(fastifyMultipart)
await fastify.register(verifyAPIKey)
fastify.route({
method: 'POST',
url: '/uploads/guilds',
schema: postServiceSchema,
handler: async (request, reply) => {
if (request.apiKey == null) {
throw fastify.httpErrors.forbidden()
}
const file = await uploadFile({
fastify,
request,

View File

@ -12,7 +12,7 @@ const parameters = Type.Object({
type Parameters = Static<typeof parameters>
export const getServiceSchema: FastifySchema = {
tags: ['uploads'] as string[],
tags: ['messages'] as string[],
params: parameters,
response: {
200: {

View File

@ -5,15 +5,23 @@ import fastifyMultipart from 'fastify-multipart'
import { fastifyErrors } from '../../../models/utils.js'
import { uploadFile } from '../../../tools/utils/uploadFile.js'
import { MAXIMUM_IMAGE_SIZE } from '../../../tools/configurations/index.js'
import verifyAPIKey from '../../../tools/plugins/verifyAPIKey.js'
const postServiceSchema: FastifySchema = {
description: 'Uploads message file',
tags: ['uploads'] as string[],
tags: ['messages'] as string[],
security: [
{
apiKeyAuth: []
}
] as Array<{ [key: string]: [] }>,
consumes: ['multipart/form-data'] as string[],
produces: ['application/json'] as string[],
response: {
201: Type.String(),
400: fastifyErrors[400],
401: fastifyErrors[401],
403: fastifyErrors[403],
431: fastifyErrors[431],
500: fastifyErrors[500]
}
@ -23,12 +31,16 @@ export const postMessagesUploadsService: FastifyPluginAsync = async (
fastify
) => {
await fastify.register(fastifyMultipart)
await fastify.register(verifyAPIKey)
fastify.route({
method: 'POST',
url: '/uploads/messages',
schema: postServiceSchema,
handler: async (request, reply) => {
if (request.apiKey == null) {
throw fastify.httpErrors.forbidden()
}
const file = await uploadFile({
fastify,
request,

View File

@ -12,7 +12,7 @@ const parameters = Type.Object({
type Parameters = Static<typeof parameters>
export const getServiceSchema: FastifySchema = {
tags: ['uploads'] as string[],
tags: ['users'] as string[],
params: parameters,
response: {
200: {

View File

@ -8,15 +8,23 @@ import {
MAXIMUM_IMAGE_SIZE,
SUPPORTED_IMAGE_MIMETYPE
} from '../../../tools/configurations/index.js'
import verifyAPIKey from '../../../tools/plugins/verifyAPIKey.js'
const postServiceSchema: FastifySchema = {
description: 'Uploads user logo',
tags: ['uploads'] as string[],
tags: ['users'] as string[],
security: [
{
apiKeyAuth: []
}
] as Array<{ [key: string]: [] }>,
consumes: ['multipart/form-data'] as string[],
produces: ['application/json'] as string[],
response: {
201: Type.String(),
400: fastifyErrors[400],
401: fastifyErrors[401],
403: fastifyErrors[403],
431: fastifyErrors[431],
500: fastifyErrors[500]
}
@ -26,12 +34,16 @@ export const postUsersUploadsLogoService: FastifyPluginAsync = async (
fastify
) => {
await fastify.register(fastifyMultipart)
await fastify.register(verifyAPIKey)
fastify.route({
method: 'POST',
url: '/uploads/users',
schema: postServiceSchema,
handler: async (request, reply) => {
if (request.apiKey == null) {
throw fastify.httpErrors.forbidden()
}
const file = await uploadFile({
fastify,
request,

View File

@ -7,6 +7,7 @@ dotenv.config()
export const PORT = parseInt(process.env.PORT ?? '8000', 10)
export const HOST = process.env.HOST ?? '0.0.0.0'
export const API_URL = process.env.API_URL ?? `http://${HOST}:${PORT}`
export const API_KEY = process.env.API_KEY ?? 'apiKeySecret'
export const SRC_URL = new URL('../../', import.meta.url)
export const ROOT_URL = new URL('../', SRC_URL)

View File

@ -14,7 +14,16 @@ export const swaggerOptions: FastifyDynamicSwaggerOptions = {
description: packageJSON.description,
version: packageJSON.version
},
tags: [{ name: 'guilds' }, { name: 'messages' }, { name: 'users' }]
tags: [{ name: 'guilds' }, { name: 'messages' }, { name: 'users' }],
components: {
securitySchemes: {
apiKeyAuth: {
type: 'apiKey',
name: 'X-API-KEY',
in: 'header'
}
}
}
},
exposeRoute: true,
staticCSP: true,

View File

@ -0,0 +1,29 @@
import fastifyPlugin from 'fastify-plugin'
import httpErrors from 'http-errors'
import { API_KEY } from '../configurations/index.js'
const { Unauthorized, Forbidden } = httpErrors
declare module 'fastify' {
export interface FastifyRequest {
apiKey?: string
}
}
export default fastifyPlugin(
async (fastify) => {
await fastify.decorateRequest('apiKey', null)
await fastify.addHook('onRequest', async (request) => {
const apiKey = request.headers['x-api-key']
if (apiKey == null || typeof apiKey !== 'string') {
throw new Unauthorized()
}
if (apiKey !== API_KEY) {
throw new Forbidden()
}
request.apiKey = apiKey
})
},
{ fastify: '3.x' }
)