mirror of
https://github.com/ThisIsBenny/wishlist-app.git
synced 2025-04-19 15:27:41 +00:00
#3 protect endpoints via API-Key
Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de>
This commit is contained in:
parent
b7c1caebd7
commit
bb5099d7d4
9 changed files with 67 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VITE_API_BASEURL=http://localhost:5000/api
|
VITE_API_BASEURL=http://localhost:5000/api
|
||||||
DATABASE_URL="file:../data/data.db"
|
DATABASE_URL="file:../data/data.db"
|
||||||
|
API_KEY=TOP_SECRET
|
||||||
|
|
|
@ -3,6 +3,8 @@ version: '3.7'
|
||||||
services:
|
services:
|
||||||
wishlist:
|
wishlist:
|
||||||
image: thisisbenny/wishlist-app:latest
|
image: thisisbenny/wishlist-app:latest
|
||||||
|
environment:
|
||||||
|
- API_KEY=TOP_SECRET
|
||||||
ports:
|
ports:
|
||||||
- '5000:5000'
|
- '5000:5000'
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# @name createWishlistFirst
|
# @name createWishlistFirst
|
||||||
POST {{BASE_URL}}/wishlist
|
POST {{BASE_URL}}/wishlist
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: API-Key TOP_SECRET
|
||||||
|
|
||||||
{
|
{
|
||||||
"title": "Junior",
|
"title": "Junior",
|
||||||
|
|
36
src/api/config/auth.ts
Normal file
36
src/api/config/auth.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'
|
||||||
|
import { notAuthorized } from './errors'
|
||||||
|
|
||||||
|
const error = notAuthorized('Unauthorized')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init: async (app: FastifyInstance) => {
|
||||||
|
if (!process.env.API_KEY) {
|
||||||
|
throw new Error('ENV API_KEY is not set!')
|
||||||
|
}
|
||||||
|
app.addHook(
|
||||||
|
'onRequest',
|
||||||
|
(request: FastifyRequest, reply: FastifyReply, done) => {
|
||||||
|
//@ts-expect-error: custom attribute
|
||||||
|
if (!reply.context.config.protected) {
|
||||||
|
return done()
|
||||||
|
}
|
||||||
|
if (!request.headers.authorization) {
|
||||||
|
return done(error)
|
||||||
|
}
|
||||||
|
const authHeader = request.headers.authorization.split(' ')
|
||||||
|
request.log.debug(authHeader)
|
||||||
|
if (
|
||||||
|
authHeader[0] &&
|
||||||
|
authHeader[0].trim().toLowerCase() === 'api-key' &&
|
||||||
|
authHeader[1]
|
||||||
|
) {
|
||||||
|
if (authHeader[1] === process.env.API_KEY) {
|
||||||
|
return done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ export const defaultErrorHandler = (
|
||||||
)
|
)
|
||||||
} else if (errorIs(error, 'P2025')) {
|
} else if (errorIs(error, 'P2025')) {
|
||||||
reply.callNotFound()
|
reply.callNotFound()
|
||||||
|
} else if (error instanceof httpError) {
|
||||||
|
reply.send(error)
|
||||||
} else {
|
} else {
|
||||||
request.log.error(error)
|
request.log.error(error)
|
||||||
const e = new httpError('unexpected error', 500, '500')
|
const e = new httpError('unexpected error', 500, '500')
|
||||||
|
@ -47,10 +49,13 @@ class httpError extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notFoundError = () => {
|
export const notFoundError = () => {
|
||||||
return new httpError('Not Found', 404, '404')
|
return new httpError('Not Found', 404, '404')
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniqueKeyError = (msg: string, code = '4001') => {
|
export const uniqueKeyError = (msg: string, code = '4001') => {
|
||||||
return new httpError(msg, 422, code)
|
return new httpError(msg, 422, code)
|
||||||
}
|
}
|
||||||
|
export const notAuthorized = (msg: string, code = '401') => {
|
||||||
|
return new httpError(msg, 401, code)
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Fastify, { FastifyContextConfig } from 'fastify'
|
||||||
import compress from 'fastify-compress'
|
import compress from 'fastify-compress'
|
||||||
import cors from 'fastify-cors'
|
import cors from 'fastify-cors'
|
||||||
import { fastify as defaultConfig } from './'
|
import { fastify as defaultConfig } from './'
|
||||||
|
import auth from './auth'
|
||||||
|
|
||||||
export default async (opts: FastifyContextConfig = {}) => {
|
export default async (opts: FastifyContextConfig = {}) => {
|
||||||
const app = Fastify({
|
const app = Fastify({
|
||||||
|
@ -23,6 +24,7 @@ export default async (opts: FastifyContextConfig = {}) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await app.register(compress)
|
await app.register(compress)
|
||||||
|
await auth.init(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@ interface createItemRequest extends FastifyRequest {
|
||||||
export const createList = <RouteOptions>{
|
export const createList = <RouteOptions>{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/',
|
url: '/',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: wishlistRequestSchema,
|
body: wishlistRequestSchema,
|
||||||
response: {
|
response: {
|
||||||
|
@ -33,6 +36,9 @@ export const createList = <RouteOptions>{
|
||||||
export const createItem = <RouteOptions>{
|
export const createItem = <RouteOptions>{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/:wishlistId/item',
|
url: '/:wishlistId/item',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: wishlistItemRequestSchema,
|
body: wishlistItemRequestSchema,
|
||||||
params: {
|
params: {
|
||||||
|
|
|
@ -17,6 +17,9 @@ interface deleteItemRequest extends FastifyRequest {
|
||||||
export const deleteList = <RouteOptions>{
|
export const deleteList = <RouteOptions>{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: '/:wishlistId',
|
url: '/:wishlistId',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
params: {
|
params: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -34,6 +37,9 @@ export const deleteList = <RouteOptions>{
|
||||||
export const deleteItem = <RouteOptions>{
|
export const deleteItem = <RouteOptions>{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: '/:wishlistId/item/:itemId',
|
url: '/:wishlistId/item/:itemId',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
params: {
|
params: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
|
|
@ -24,6 +24,9 @@ interface updateItemRequest extends FastifyRequest {
|
||||||
export const updateList = <RouteOptions>{
|
export const updateList = <RouteOptions>{
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: '/:wishlistId',
|
url: '/:wishlistId',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: wishlistRequestSchema,
|
body: wishlistRequestSchema,
|
||||||
params: {
|
params: {
|
||||||
|
@ -49,6 +52,9 @@ export const updateList = <RouteOptions>{
|
||||||
export const updateItem = <RouteOptions>{
|
export const updateItem = <RouteOptions>{
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: '/:wishlistId/item/:itemId',
|
url: '/:wishlistId/item/:itemId',
|
||||||
|
config: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
body: wishlistItemRequestSchema,
|
body: wishlistItemRequestSchema,
|
||||||
params: {
|
params: {
|
||||||
|
|
Loading…
Add table
Reference in a new issue