validate POST body form
This commit is contained in:
parent
1d824d5f07
commit
276ac5cfe0
42
server/package-lock.json
generated
42
server/package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.0.0",
|
"@prisma/client": "^4.0.0",
|
||||||
"body-parser": "^1.20.0",
|
"body-parser": "^1.20.0",
|
||||||
|
"class-validator": "^0.13.2",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"express-rate-limit": "^6.4.0",
|
"express-rate-limit": "^6.4.0",
|
||||||
@ -930,6 +931,15 @@
|
|||||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/class-validator": {
|
||||||
|
"version": "0.13.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
|
||||||
|
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"libphonenumber-js": "^1.9.43",
|
||||||
|
"validator": "^13.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clean-stack": {
|
"node_modules/clean-stack": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||||
@ -2935,6 +2945,11 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/libphonenumber-js": {
|
||||||
|
"version": "1.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.7.tgz",
|
||||||
|
"integrity": "sha512-jZXLCCWMe1b/HXkjiLeYt2JsytZMcqH26jLFIdzFDFF0xvSUWrYKyvPlyPG+XJzEyKUFbcZxLdWGMwQsWaHDxQ=="
|
||||||
|
},
|
||||||
"node_modules/load-json-file": {
|
"node_modules/load-json-file": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||||
@ -5260,6 +5275,14 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/validator": {
|
||||||
|
"version": "13.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
|
||||||
|
"integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@ -6265,6 +6288,15 @@
|
|||||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"class-validator": {
|
||||||
|
"version": "0.13.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
|
||||||
|
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
|
||||||
|
"requires": {
|
||||||
|
"libphonenumber-js": "^1.9.43",
|
||||||
|
"validator": "^13.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"clean-stack": {
|
"clean-stack": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||||
@ -7685,6 +7717,11 @@
|
|||||||
"package-json": "^6.3.0"
|
"package-json": "^6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"libphonenumber-js": {
|
||||||
|
"version": "1.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.7.tgz",
|
||||||
|
"integrity": "sha512-jZXLCCWMe1b/HXkjiLeYt2JsytZMcqH26jLFIdzFDFF0xvSUWrYKyvPlyPG+XJzEyKUFbcZxLdWGMwQsWaHDxQ=="
|
||||||
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||||
@ -9417,6 +9454,11 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"validator": {
|
||||||
|
"version": "13.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
|
||||||
|
"integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw=="
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.0.0",
|
"@prisma/client": "^4.0.0",
|
||||||
"body-parser": "^1.20.0",
|
"body-parser": "^1.20.0",
|
||||||
|
"class-validator": "^0.13.2",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"express-rate-limit": "^6.4.0",
|
"express-rate-limit": "^6.4.0",
|
||||||
|
@ -3,9 +3,10 @@ import request from "supertest";
|
|||||||
import { describe, it, expect } from "vitest";
|
import { describe, it, expect } from "vitest";
|
||||||
import prisma from "./client";
|
import prisma from "./client";
|
||||||
|
|
||||||
|
// const testNote with base64 ciphertext and hmac
|
||||||
const testNote = {
|
const testNote = {
|
||||||
ciphertext: "sample_ciphertext",
|
ciphertext: Buffer.from("sample_ciphertext").toString("base64"),
|
||||||
hmac: "sample_hmac",
|
hmac: Buffer.from("sample_hmac").toString("base64"),
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("GET /api/note", () => {
|
describe("GET /api/note", () => {
|
||||||
@ -78,6 +79,11 @@ describe("POST /api/note", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Returns a bad request on invalid POST body", async () => {
|
||||||
|
const res = await request(app).post("/api/note").send({});
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
});
|
||||||
|
|
||||||
it("returns a valid view_url on correct POST body", async () => {
|
it("returns a valid view_url on correct POST body", async () => {
|
||||||
// Make post request
|
// Make post request
|
||||||
let res = await request(app).post("/api/note").send(testNote);
|
let res = await request(app).post("/api/note").send(testNote);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import express, { Express, Request } from "express";
|
import express, { Express, Request, Response } from "express";
|
||||||
import { EncryptedNote } from "@prisma/client";
|
import { EncryptedNote } from "@prisma/client";
|
||||||
import { addDays } from "./util";
|
import { addDays } from "./util";
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
@ -8,6 +8,8 @@ import pinoHttp from "pino-http";
|
|||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import prisma from "./client";
|
import prisma from "./client";
|
||||||
import bodyParser from "body-parser";
|
import bodyParser from "body-parser";
|
||||||
|
import { NotePostRequest } from "./model/NotePostRequest";
|
||||||
|
import { validateOrReject } from "class-validator";
|
||||||
|
|
||||||
// Initialize middleware clients
|
// Initialize middleware clients
|
||||||
const app: Express = express();
|
const app: Express = express();
|
||||||
@ -48,7 +50,7 @@ const getLimiter = rateLimit({
|
|||||||
app.use(bodyParser.json({ limit: "400k" }));
|
app.use(bodyParser.json({ limit: "400k" }));
|
||||||
|
|
||||||
// Get encrypted note
|
// Get encrypted note
|
||||||
app.get("/api/note/:id", getLimiter, (req, res, next) => {
|
app.get("/api/note/:id", getLimiter, (req: Request, res: Response, next) => {
|
||||||
prisma.encryptedNote
|
prisma.encryptedNote
|
||||||
.findUnique({
|
.findUnique({
|
||||||
where: { id: req.params.id },
|
where: { id: req.params.id },
|
||||||
@ -63,14 +65,19 @@ app.get("/api/note/:id", getLimiter, (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Post new encrypted note
|
// Post new encrypted note
|
||||||
app.post(
|
app.post("/api/note/", postLimiter, (req: Request, res: Response, next) => {
|
||||||
"/api/note/",
|
const notePostRequest = new NotePostRequest();
|
||||||
postLimiter,
|
Object.assign(notePostRequest, req.body);
|
||||||
(req: Request<{}, {}, EncryptedNote>, res, next) => {
|
validateOrReject(notePostRequest).catch((err) => {
|
||||||
const note = req.body;
|
res.status(400).send(err.message);
|
||||||
|
});
|
||||||
|
const note = notePostRequest as EncryptedNote;
|
||||||
prisma.encryptedNote
|
prisma.encryptedNote
|
||||||
.create({
|
.create({
|
||||||
data: { ...note, expire_time: addDays(new Date(), 30) },
|
data: {
|
||||||
|
...note,
|
||||||
|
expire_time: addDays(new Date(), 30),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then((savedNote) => {
|
.then((savedNote) => {
|
||||||
res.json({
|
res.json({
|
||||||
@ -79,8 +86,7 @@ app.post(
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// For testing purposes
|
// For testing purposes
|
||||||
app.get("/api/test", (req, res, next) => {
|
app.get("/api/test", (req, res, next) => {
|
||||||
|
12
server/src/model/NotePostRequest.ts
Normal file
12
server/src/model/NotePostRequest.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IsBase64 } from "class-validator";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request body for creating a note
|
||||||
|
*/
|
||||||
|
export class NotePostRequest {
|
||||||
|
@IsBase64()
|
||||||
|
ciphertext: string | undefined;
|
||||||
|
|
||||||
|
@IsBase64()
|
||||||
|
hmac: string | undefined;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"lib": ["esnext"],
|
"lib": ["esnext"],
|
||||||
|
Loading…
Reference in New Issue
Block a user