diff --git a/server/.env b/server/.env index c663bad..42cc3fd 100644 --- a/server/.env +++ b/server/.env @@ -6,5 +6,6 @@ ENVIRONMENT=dev PORT=8080 +CLEANUP_INTERVAL_SECONDS=60 FRONTEND_URL="http://localhost:3000" -DATABASE_URL="file:./dev.db" \ No newline at end of file +DATABASE_URL="file:./dev.db" diff --git a/server/package-lock.json b/server/package-lock.json index d570ecc..f9e7224 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "@prisma/client": "^3.15.2", + "@prisma/client": "^4.0.0", "cors": "^2.8.5", "dotenv": "^16.0.1", "express": "^4.18.1", @@ -21,7 +21,7 @@ "@types/node": "^18.0.0", "@types/sqlite3": "^3.1.8", "nodemon": "^2.0.16", - "prisma": "^3.15.2", + "prisma": "^4.0.0", "supertest": "^6.2.3", "ts-node": "^10.8.1", "typescript": "^4.7.4", @@ -128,15 +128,15 @@ } }, "node_modules/@prisma/client": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.15.2.tgz", - "integrity": "sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.0.0.tgz", + "integrity": "sha512-g1h2OGoRo7anBVQ9Cw3gsbjwPtvf7i0pkGxKeZICtwkvE5CZXW+xZF4FZdmrViYkKaAShbISL0teNpu9ecpf4g==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e" + "@prisma/engines-version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11" }, "engines": { - "node": ">=12.6" + "node": ">=14.17" }, "peerDependencies": { "prisma": "*" @@ -148,16 +148,16 @@ } }, "node_modules/@prisma/engines": { - "version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz", - "integrity": "sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==", + "version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz", + "integrity": "sha512-u/rG4lDHALolWBLr3yebZ+N2qImp3SDMcu7bHNJuRDaYvYEXy/MqfNRNEgd9GoPsXL3gofYf0VzJf2AmCG3YVw==", "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz", - "integrity": "sha512-e3k2Vd606efd1ZYy2NQKkT4C/pn31nehyLhVug6To/q8JT8FpiMrDy7zmm3KLF0L98NOQQcutaVtAPhzKhzn9w==" + "version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz", + "integrity": "sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw==" }, "node_modules/@sindresorhus/is": { "version": "0.14.0", @@ -2949,20 +2949,20 @@ } }, "node_modules/prisma": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-3.15.2.tgz", - "integrity": "sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.0.0.tgz", + "integrity": "sha512-Dtsar03XpCBkcEb2ooGWO/WcgblDTLzGhPcustbehwlFXuTMliMDRzXsfygsgYwQoZnAUKRd1rhpvBNEUziOVw==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e" + "@prisma/engines": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11" }, "bin": { "prisma": "build/index.js", "prisma2": "build/index.js" }, "engines": { - "node": ">=12.6" + "node": ">=14.17" } }, "node_modules/promise-inflight": { @@ -4157,23 +4157,23 @@ } }, "@prisma/client": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.15.2.tgz", - "integrity": "sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.0.0.tgz", + "integrity": "sha512-g1h2OGoRo7anBVQ9Cw3gsbjwPtvf7i0pkGxKeZICtwkvE5CZXW+xZF4FZdmrViYkKaAShbISL0teNpu9ecpf4g==", "requires": { - "@prisma/engines-version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e" + "@prisma/engines-version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11" } }, "@prisma/engines": { - "version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz", - "integrity": "sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==", + "version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz", + "integrity": "sha512-u/rG4lDHALolWBLr3yebZ+N2qImp3SDMcu7bHNJuRDaYvYEXy/MqfNRNEgd9GoPsXL3gofYf0VzJf2AmCG3YVw==", "devOptional": true }, "@prisma/engines-version": { - "version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz", - "integrity": "sha512-e3k2Vd606efd1ZYy2NQKkT4C/pn31nehyLhVug6To/q8JT8FpiMrDy7zmm3KLF0L98NOQQcutaVtAPhzKhzn9w==" + "version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz", + "integrity": "sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw==" }, "@sindresorhus/is": { "version": "0.14.0", @@ -6209,12 +6209,12 @@ "dev": true }, "prisma": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-3.15.2.tgz", - "integrity": "sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.0.0.tgz", + "integrity": "sha512-Dtsar03XpCBkcEb2ooGWO/WcgblDTLzGhPcustbehwlFXuTMliMDRzXsfygsgYwQoZnAUKRd1rhpvBNEUziOVw==", "devOptional": true, "requires": { - "@prisma/engines": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e" + "@prisma/engines": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11" } }, "promise-inflight": { diff --git a/server/package.json b/server/package.json index ecdfa47..da61934 100644 --- a/server/package.json +++ b/server/package.json @@ -11,7 +11,7 @@ "author": "Maxime Cannoodt (mcndt)", "license": "MIT", "dependencies": { - "@prisma/client": "^3.15.2", + "@prisma/client": "^4.0.0", "cors": "^2.8.5", "dotenv": "^16.0.1", "express": "^4.18.1", @@ -23,7 +23,7 @@ "@types/node": "^18.0.0", "@types/sqlite3": "^3.1.8", "nodemon": "^2.0.16", - "prisma": "^3.15.2", + "prisma": "^4.0.0", "supertest": "^6.2.3", "ts-node": "^10.8.1", "typescript": "^4.7.4", diff --git a/server/prisma/dev.db b/server/prisma/dev.db index e5cad23..8844e8a 100644 Binary files a/server/prisma/dev.db and b/server/prisma/dev.db differ diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 78d38ce..6b26a4c 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -13,6 +13,7 @@ datasource db { model EncryptedNote { id String @id @default(cuid()) insert_time DateTime @default(now()) + expire_time DateTime @default(now()) ciphertext String hmac String } diff --git a/server/server.ts b/server/server.ts index ca3618f..dced1ef 100644 --- a/server/server.ts +++ b/server/server.ts @@ -2,11 +2,15 @@ import "dotenv/config"; import express, { Express, Request, Response } from "express"; import cors from "cors"; import { PrismaClient, EncryptedNote } from "@prisma/client"; +import { addDays } from "./util"; +// Initialize middleware clients const prisma = new PrismaClient(); const app: Express = express(); +app.use(express.json()); +// Allow CORS in dev mode. if (process.env.ENVIRONMENT == "dev") { app.use( cors({ @@ -15,8 +19,6 @@ if (process.env.ENVIRONMENT == "dev") { ); } -app.use(express.json()); - // start the Express server app.listen(process.env.PORT, () => { console.log(`server started at http://localhost:${process.env.PORT}`); @@ -25,7 +27,9 @@ app.listen(process.env.PORT, () => { // Post new encrypted note app.post("/note/", async (req: Request<{}, {}, EncryptedNote>, res) => { const note = req.body; - const savedNote = await prisma.encryptedNote.create({ data: note }); + const savedNote = await prisma.encryptedNote.create({ + data: { ...note, expire_time: addDays(new Date(), 14) }, + }); res.json({ view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}` }); }); @@ -44,3 +48,24 @@ app.get("/note/:id", async (req, res) => { app.use((req, res, next) => { res.status(404).send(); }); + +// Clean up expired notes periodically +const interval = + Math.max(parseInt(process.env.CLEANUP_INTERVAL_SECONDS) || 1, 1) * + 1000; +setInterval(async () => { + try { + console.log("[Cleanup] Cleaning up expired notes..."); + const deleted = await prisma.encryptedNote.deleteMany({ + where: { + expire_time: { + lte: new Date(), + }, + }, + }); + console.log(`[Cleanup] Deleted ${deleted.count} expired notes.`); + } catch (err) { + console.error(`[Cleanup] Error cleaning expired notes:`); + console.error(err); + } +}, interval); diff --git a/server/util.ts b/server/util.ts new file mode 100644 index 0000000..f0d8b08 --- /dev/null +++ b/server/util.ts @@ -0,0 +1,5 @@ +export function addDays(date: Date, days: number): Date { + var result = new Date(date); + result.setDate(result.getDate() + days); + return result; +}