feat(nostr): added nostrEvent validation
This commit is contained in:
parent
2c5037a491
commit
ce9306271d
src
models
routes
utils
@ -1,10 +1,12 @@
|
|||||||
|
import { ObjectId } from 'mongodb'
|
||||||
export class NostrEvent {
|
export class NostrEvent {
|
||||||
constructor(
|
constructor(
|
||||||
public nostrId: string, // nostr unique identifier
|
public nostrId: string, // nostr unique identifier
|
||||||
public pubkey: string, // public key of the event creator
|
public pubkey: string, // public key of the event creator
|
||||||
public created_at: number, // timestamp
|
public created_at: number, // timestamp
|
||||||
public kind: number, // event type, e.g., review, article, comment
|
public kind: number, // event type, e.g., review, article, comment
|
||||||
public tags: [string][], // array of keywords or hashtags
|
public tags: string[][], // array of keywords or hashtags
|
||||||
public content: string // text content of the event
|
public content: string, // text content of the event
|
||||||
|
public id?: ObjectId
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
import express, { Request, Response } from 'express'
|
import express, { Request, Response } from 'express'
|
||||||
import { collections } from '../services/database.service'
|
import { collections } from '../services/database.service'
|
||||||
import { NostrEvent } from '../models'
|
import { NostrEvent } from '../models'
|
||||||
|
import {
|
||||||
|
nostrEventValidation,
|
||||||
|
handleReqError,
|
||||||
|
handleReqSuccess
|
||||||
|
} from '../utils'
|
||||||
|
import { Event } from 'nostr-tools'
|
||||||
|
import Joi from 'joi'
|
||||||
|
|
||||||
// Global Config
|
// Global Config
|
||||||
export const nostrRouter = express.Router()
|
export const nostrRouter = express.Router()
|
||||||
@ -26,23 +33,39 @@ nostrRouter.get('/', async (_req: Request, res: Response) => {
|
|||||||
// POST
|
// POST
|
||||||
nostrRouter.post('/', async (req: Request, res: Response) => {
|
nostrRouter.post('/', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const nostrEvent = req.body as NostrEvent
|
const {
|
||||||
|
error,
|
||||||
|
value: event
|
||||||
|
}: { error: Joi.ValidationError | undefined; value: Event } =
|
||||||
|
nostrEventValidation(req.body)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error.details[0].message
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, pubkey, created_at, kind, tags, content } = event
|
||||||
|
|
||||||
|
const events = await collections.nostrEvents
|
||||||
|
?.find({ nostrId: id })
|
||||||
|
.toArray()
|
||||||
|
|
||||||
|
if (events?.length) {
|
||||||
|
throw new Error('nostr event with provided "id" exists')
|
||||||
|
}
|
||||||
|
|
||||||
|
const nostrEvent: NostrEvent = {
|
||||||
|
nostrId: id,
|
||||||
|
pubkey,
|
||||||
|
created_at,
|
||||||
|
kind,
|
||||||
|
tags,
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
const result = await collections.nostrEvents?.insertOne(nostrEvent)
|
const result = await collections.nostrEvents?.insertOne(nostrEvent)
|
||||||
|
|
||||||
if (result) {
|
handleReqSuccess(res, result, 'nostrEvent')
|
||||||
res
|
|
||||||
.status(201)
|
|
||||||
.send(
|
|
||||||
`Successfully created a new nostrEvent with id ${result.insertedId}`
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
res.status(500).send('Failed to create a new nostrEvent.')
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(error)
|
handleReqError(res, error)
|
||||||
|
|
||||||
if (error instanceof Error) {
|
|
||||||
res.status(400).send(error.message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import express, { Request, Response } from 'express'
|
import express, { Request, Response } from 'express'
|
||||||
import { collections } from '../services/database.service'
|
import { collections } from '../services/database.service'
|
||||||
import { User } from '../models'
|
import { User } from '../models'
|
||||||
import { userValidation } from '../utils'
|
import { userValidation, handleReqError, handleReqSuccess } from '../utils'
|
||||||
import Joi from 'joi'
|
import Joi from 'joi'
|
||||||
|
|
||||||
// Global Config
|
// Global Config
|
||||||
@ -59,20 +59,8 @@ usersRouter.post('/', async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const result = await collections.users?.insertOne(newUser)
|
const result = await collections.users?.insertOne(newUser)
|
||||||
|
|
||||||
if (result) {
|
handleReqSuccess(res, result, 'user')
|
||||||
res
|
|
||||||
.status(201)
|
|
||||||
.send(`Successfully created a new user with id ${result.insertedId}`)
|
|
||||||
} else {
|
|
||||||
res.status(500).send('Failed to create a new user.')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
handleReqError(res, error)
|
||||||
|
|
||||||
if (error instanceof Error) {
|
|
||||||
res.status(400).send(error.message)
|
|
||||||
} else if (typeof error === 'string') {
|
|
||||||
res.status(400).send(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from './validation'
|
export * from './validation'
|
||||||
export * from './nostr'
|
export * from './nostr'
|
||||||
|
export * from './route'
|
||||||
|
28
src/utils/route.ts
Normal file
28
src/utils/route.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Response } from 'express'
|
||||||
|
import { InsertOneResult } from 'mongodb'
|
||||||
|
|
||||||
|
export const handleReqError = (res: Response, error: unknown) => {
|
||||||
|
console.error(error)
|
||||||
|
|
||||||
|
if (error instanceof Error) {
|
||||||
|
res.status(400).send(error.message)
|
||||||
|
} else if (typeof error === 'string') {
|
||||||
|
res.status(400).send(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleReqSuccess = (
|
||||||
|
res: Response,
|
||||||
|
result: InsertOneResult<Document> | undefined,
|
||||||
|
itemName: string
|
||||||
|
) => {
|
||||||
|
if (result) {
|
||||||
|
res
|
||||||
|
.status(201)
|
||||||
|
.send(
|
||||||
|
`Successfully created a new ${itemName} with id ${result.insertedId}`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
res.status(500).send(`Failed to create a new ${itemName}.`)
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export * from './user'
|
export * from './user'
|
||||||
|
export * from './nostr'
|
||||||
|
24
src/utils/validation/nostr.ts
Normal file
24
src/utils/validation/nostr.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import Joi from 'joi'
|
||||||
|
import { npubToHex, validateHex } from '../nostr'
|
||||||
|
|
||||||
|
export const nostrEventValidation = (data: unknown): Joi.ValidationResult =>
|
||||||
|
Joi.object({
|
||||||
|
id: Joi.string().required(),
|
||||||
|
kind: Joi.number().required(),
|
||||||
|
content: Joi.string().required(),
|
||||||
|
tags: Joi.array().items(Joi.array().items(Joi.string())),
|
||||||
|
created_at: Joi.number().required(),
|
||||||
|
pubkey: Joi.string()
|
||||||
|
.custom((value, helper) => {
|
||||||
|
const hex = npubToHex(value as string)
|
||||||
|
|
||||||
|
if (!hex || !validateHex(hex)) {
|
||||||
|
return helper.message({
|
||||||
|
custom: Joi.expression('"pubkey" contains an invalid value')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
.required()
|
||||||
|
}).validate(data)
|
@ -16,11 +16,11 @@ const npubValidation = (value: unknown, helper: Joi.CustomHelpers<unknown>) => {
|
|||||||
|
|
||||||
export const userValidation = (data: unknown): Joi.ValidationResult =>
|
export const userValidation = (data: unknown): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
name: Joi.string().not('').required(),
|
name: Joi.string().required(),
|
||||||
npub: Joi.alternatives()
|
npub: Joi.alternatives()
|
||||||
.try(
|
.try(
|
||||||
Joi.array().items(Joi.string().custom(npubValidation)),
|
Joi.array().items(Joi.string().custom(npubValidation)),
|
||||||
Joi.string().not('').custom(npubValidation)
|
Joi.string().custom(npubValidation)
|
||||||
)
|
)
|
||||||
.required(),
|
.required(),
|
||||||
role: Joi.string()
|
role: Joi.string()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user