Skip to content

Commit

Permalink
feat(backend): create services & regexes endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Fraccs committed Dec 12, 2023
1 parent c19ed71 commit ec2b481
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 1 deletion.
3 changes: 3 additions & 0 deletions web/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "./utils/logs"

import { Database } from "./database/db"
import logger from "./middlewares/logger"
import regexesRoute from "./routes/regexes"
import servicesRoute from "./routes/services"

// Instantiate redis connection
Expand All @@ -19,8 +20,10 @@ Database

const api = express()

api.use(express.json())
api.use(logger)

api.use("/api/regexes", regexesRoute)
api.use("/api/services", servicesRoute)

api.listen(process.env.API_PORT, () => {
Expand Down
68 changes: 68 additions & 0 deletions web/backend/src/routes/regexes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Router } from "express"
import { z } from "zod"
import { Database } from "../database/db"
import { CerberoServiceCreate } from "../types/service"

const regexesRoute = Router()

regexesRoute.get("/:nfq", async (req, res) => {
const redis = Database.getInstance()
const { nfq } = req.params

if(!parseInt(nfq)) {
return res.status(400).json({
error: "The provided nfq id is not a number"
})
}

const activeRegexes = await redis.sMembers(`regexes:${nfq}:active`)
const inactiveRegexes = await redis.sMembers(`regexes:${nfq}:inactive`)

return res.status(201).json({
regexes: {
active: activeRegexes,
inactive: inactiveRegexes
}
})
})

regexesRoute.post("/:nfq", async (req, res) => {
const redis = Database.getInstance()
const { nfq } = req.params

const bodySchema = z.object({
regexes: z.array(z.string())
})

let typeValidatedBody: Required<Pick<CerberoServiceCreate, "regexes">>

try {
typeValidatedBody = bodySchema.parse(req.body)
}
catch(e) {
return res.status(400).json({
error: e
})
}

if(!parseInt(nfq)) {
return res.status(400).json({
error: "The provided nfq id is not a number"
})
}

// Regexes are considered active by default
await redis.sAdd(`regexes:${nfq}:active`, typeValidatedBody.regexes)

const activeRegexes = await redis.sMembers(`regexes:${nfq}:active`)
const inactiveRegexes = await redis.sMembers(`regexes:${nfq}:inactive`)

return res.status(201).json({
regexes: {
active: activeRegexes,
inactive: inactiveRegexes
}
})
})

export default regexesRoute
80 changes: 79 additions & 1 deletion web/backend/src/routes/services.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Router } from "express"
import { z } from "zod"
import { Database } from "../database/db"
import type { CerberoServiceCreate } from "../types/service"

const servicesRoute = Router()

// TODO: convert nfq and port to numbers (since redis returns everything as a string)

servicesRoute.get("/", async (req, res) => {
const redis = Database.getInstance()

Expand All @@ -12,10 +16,84 @@ servicesRoute.get("/", async (req, res) => {
for(const serviceKey of servicesKeys) {
const service = await redis.hGetAll(serviceKey)

services.push({ ...service, name: serviceKey.split(":")[1] })
services.push(service)
}

return res.json(services)
})

servicesRoute.post("/", async (req, res) => {
const redis = Database.getInstance()

const bodySchema = z.object({
name: z.string(),
nfq: z.number(),
port: z.number(),
protocol: z.literal("tcp").or(z.literal("udp")),
regexes: z.array(z.string()).optional()
})

let typeValidatedBody: CerberoServiceCreate

try {
typeValidatedBody = bodySchema.parse(req.body)
}
catch(e) {
return res.status(400).json({
error: e
})
}

// The service was created with default regexes
if(typeValidatedBody.regexes && typeValidatedBody.regexes.length > 0) {
await redis.sAdd(`regexes:${typeValidatedBody.nfq}:active`, typeValidatedBody.regexes)
}

const newService = {
name: typeValidatedBody.name,
nfq: typeValidatedBody.nfq,
port: typeValidatedBody.port,
protocol: typeValidatedBody.protocol
}

await redis.hSet(`services:${typeValidatedBody.nfq}`, newService)

return res.status(201).json({
...newService,
regexes: {
active: typeValidatedBody.regexes,
inactive: []
}
})
})

servicesRoute.get("/:nfq", async (req, res) => {
const redis = Database.getInstance()
const { nfq } = req.params

if(!parseInt(nfq)) {
return res.status(400).json({
error: "The provided nfq id is not a number"
})
}

const service = await redis.hGetAll(`services:${nfq}`)
const activeRegexes = await redis.sMembers(`regexes:${nfq}:active`)
const inactiveRegexes = await redis.sMembers(`regexes:${nfq}:inactive`)

if(Object.entries(service).length === 0) {
return res.status(404).json({
error: "Service not found"
})
}

return res.json({
...service,
regexes: {
active: activeRegexes,
inactive: inactiveRegexes
}
})
})

export default servicesRoute
4 changes: 4 additions & 0 deletions web/backend/src/types/regex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type CerberoRegexes = {
active: string[]
inactive: string[]
}
13 changes: 13 additions & 0 deletions web/backend/src/types/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { CerberoRegexes } from "./regex"

export type CerberoService = {
name: string
nfq: number
port: number
protocol: "tcp" | "udp"
regexes?: CerberoRegexes[]
}

export type CerberoServiceCreate = Omit<CerberoService, "regexes"> & {
regexes?: string[]
}

0 comments on commit ec2b481

Please sign in to comment.