mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 21:11:30 +08:00 
			
		
		
		
	Merge pull request #1955 from TriliumNext/feature/db_session_store
In-database session store
This commit is contained in:
		
						commit
						56d4d7c20f
					
				| @ -104,7 +104,6 @@ | ||||
|     "sanitize-html": "2.17.0", | ||||
|     "sax": "1.4.1", | ||||
|     "serve-favicon": "2.5.0", | ||||
|     "session-file-store": "1.5.0", | ||||
|     "stream-throttle": "0.1.3", | ||||
|     "strip-bom": "5.0.0", | ||||
|     "striptags": "3.2.0", | ||||
|  | ||||
| @ -4,7 +4,6 @@ import favicon from "serve-favicon"; | ||||
| import cookieParser from "cookie-parser"; | ||||
| import helmet from "helmet"; | ||||
| import compression from "compression"; | ||||
| import sessionParser from "./routes/session_parser.js"; | ||||
| import config from "./services/config.js"; | ||||
| import utils, { getResourceDir } from "./services/utils.js"; | ||||
| import assets from "./routes/assets.js"; | ||||
| @ -111,6 +110,8 @@ export default async function buildApp() { | ||||
|     app.use(`/manifest.webmanifest`, express.static(path.join(publicAssetsDir, "manifest.webmanifest"))); | ||||
|     app.use(`/robots.txt`, express.static(path.join(publicAssetsDir, "robots.txt"))); | ||||
|     app.use(`/icon.png`, express.static(path.join(publicAssetsDir, "icon.png"))); | ||||
| 
 | ||||
|     const sessionParser = (await import("./routes/session_parser.js")).default; | ||||
|     app.use(sessionParser); | ||||
|     app.use(favicon(path.join(assetsDir, "icon.ico"))); | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,5 @@ | ||||
| CREATE TABLE IF NOT EXISTS sessions ( | ||||
|     id TEXT PRIMARY KEY, | ||||
|     data TEXT, | ||||
|     expires INTEGER | ||||
| ); | ||||
| @ -187,3 +187,9 @@ CREATE TABLE IF NOT EXISTS "embedding_providers" ( | ||||
|     "dateModified" TEXT NOT NULL, | ||||
|     "utcDateModified" TEXT NOT NULL | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE IF NOT EXISTS sessions ( | ||||
|     id TEXT PRIMARY KEY, | ||||
|     data TEXT, | ||||
|     expires INTEGER | ||||
| ); | ||||
|  | ||||
| @ -1,10 +1,55 @@ | ||||
| import session from "express-session"; | ||||
| import sessionFileStore from "session-file-store"; | ||||
| import sql from "../services/sql.js"; | ||||
| import session, { Store } from "express-session"; | ||||
| import sessionSecret from "../services/session_secret.js"; | ||||
| import dataDir from "../services/data_dir.js"; | ||||
| import config from "../services/config.js"; | ||||
| import log from "../services/log.js"; | ||||
| 
 | ||||
| const FileStore = sessionFileStore(session); | ||||
| class SQLiteSessionStore extends Store { | ||||
| 
 | ||||
|     get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void { | ||||
|         try { | ||||
|             const data = sql.getValue<string>(/*sql*/`SELECT data FROM sessions WHERE id = ?`, sid); | ||||
|             let session = null; | ||||
|             if (data) { | ||||
|                 session = JSON.parse(data); | ||||
|             } | ||||
|             return callback(null, session); | ||||
|         } catch (e: unknown) { | ||||
|             log.error(e); | ||||
|             return callback(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     set(id: string, session: session.SessionData, callback?: (err?: any) => void): void { | ||||
|         try { | ||||
|             const expires = session.cookie?.expires | ||||
|                 ? new Date(session.cookie.expires).getTime() | ||||
|                 : Date.now() + 3600000; // fallback to 1 hour
 | ||||
|             const data = JSON.stringify(session); | ||||
| 
 | ||||
|             sql.upsert("sessions", "id", { | ||||
|                 id, | ||||
|                 expires, | ||||
|                 data | ||||
|             }); | ||||
|             callback?.(); | ||||
|         } catch (e) { | ||||
|             log.error(e); | ||||
|             return callback?.(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     destroy(sid: string, callback?: (err?: any) => void): void { | ||||
|         try { | ||||
|             sql.execute(/*sql*/`DELETE FROM sessions WHERE id = ?`, sid); | ||||
|             callback?.(); | ||||
|         } catch (e) { | ||||
|             log.error(e); | ||||
|             callback?.(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| const sessionParser = session({ | ||||
|     secret: sessionSecret, | ||||
| @ -16,10 +61,14 @@ const sessionParser = session({ | ||||
|         maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds
 | ||||
|     }, | ||||
|     name: "trilium.sid", | ||||
|     store: new FileStore({ | ||||
|         ttl: config.Session.cookieMaxAge, | ||||
|         path: `${dataDir.TRILIUM_DATA_DIR}/sessions` | ||||
|     }) | ||||
|     store: new SQLiteSessionStore() | ||||
| }); | ||||
| 
 | ||||
| setInterval(() => { | ||||
|     // Clean up expired sesions.
 | ||||
|     const now = Date.now(); | ||||
|     const result = sql.execute(/*sql*/`DELETE FROM sessions WHERE expires < ?`, now); | ||||
|     console.log("Cleaning up expired sessions: ", result.changes); | ||||
| }, 60 * 60 * 1000); | ||||
| 
 | ||||
| export default sessionParser; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import build from "./build.js"; | ||||
| import packageJson from "../../package.json" with { type: "json" }; | ||||
| import dataDir from "./data_dir.js"; | ||||
| 
 | ||||
| const APP_DB_VERSION = 230; | ||||
| const APP_DB_VERSION = 231; | ||||
| const SYNC_VERSION = 35; | ||||
| const CLIPPER_PROTOCOL_VERSION = "1.0"; | ||||
| 
 | ||||
|  | ||||
| @ -69,7 +69,7 @@ function info(message: string | Error) { | ||||
|     log(message); | ||||
| } | ||||
| 
 | ||||
| function error(message: string | Error) { | ||||
| function error(message: string | Error | unknown) { | ||||
|     log(`ERROR: ${message}`); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,4 @@ | ||||
| #!/usr/bin/env node | ||||
| 
 | ||||
| import sessionParser from "./routes/session_parser.js"; | ||||
| import fs from "fs"; | ||||
| import http from "http"; | ||||
| import https from "https"; | ||||
| @ -79,6 +77,7 @@ async function startTrilium() { | ||||
| 
 | ||||
|     const httpServer = startHttpServer(app); | ||||
| 
 | ||||
|     const sessionParser = (await import("./routes/session_parser.js")).default; | ||||
|     ws.init(httpServer, sessionParser as any); // TODO: Not sure why session parser is incompatible.
 | ||||
| 
 | ||||
|     if (utils.isElectron) { | ||||
|  | ||||
| @ -20,6 +20,7 @@ | ||||
| 
 | ||||
| *   [Inconsistent Find and Replace Behavior in Large Code Notes](https://github.com/TriliumNext/Notes/issues/1826) by @SiriusXT | ||||
| *   [Incorrect import of multiple inline math](https://github.com/TriliumNext/Notes/pull/1906) by @SiriusXT | ||||
| *   [Random EPERM: operation not permitted on Windows](https://github.com/TriliumNext/Notes/issues/249) | ||||
| 
 | ||||
| ## ✨ Improvements | ||||
| 
 | ||||
| @ -40,7 +41,8 @@ | ||||
| *   [Added support for opening and activating a note in a new tab using Ctrl+Shift+click on notes in the launcher pane, note tree, or note images](https://github.com/TriliumNext/Notes/pull/1854) by @SiriusXT | ||||
| *   [Style and footnote improvements](https://github.com/TriliumNext/Notes/pull/1913) by @SiriusXT | ||||
| *   Backend log: disable some editor features in order to increase performance for large logs (syntax highlighting, folding, etc.). | ||||
| *   [Collapsible table of contents](https://github.com/TriliumNext/Notes/pull/1954) by @SriiusXT | ||||
| *   [Collapsible table of contents](https://github.com/TriliumNext/Notes/pull/1954) by @SiriusXT | ||||
| *   Sessions (logins) are no longer stored as files in the data directory, but as entries in the database. This improves the session reliability on Windows platforms. | ||||
| 
 | ||||
| ## 📖 Documentation | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										66
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										66
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -755,9 +755,6 @@ importers: | ||||
|       serve-favicon: | ||||
|         specifier: 2.5.0 | ||||
|         version: 2.5.0 | ||||
|       session-file-store: | ||||
|         specifier: 1.5.0 | ||||
|         version: 1.5.0 | ||||
|       stream-throttle: | ||||
|         specifier: 0.1.3 | ||||
|         version: 0.1.3 | ||||
| @ -6089,9 +6086,6 @@ packages: | ||||
|   asap@2.0.6: | ||||
|     resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} | ||||
| 
 | ||||
|   asn1.js@5.4.1: | ||||
|     resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} | ||||
| 
 | ||||
|   assertion-error@2.0.1: | ||||
|     resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} | ||||
|     engines: {node: '>=12'} | ||||
| @ -6221,9 +6215,6 @@ packages: | ||||
|     peerDependencies: | ||||
|       '@babel/core': ^7.0.0 | ||||
| 
 | ||||
|   bagpipe@0.3.5: | ||||
|     resolution: {integrity: sha512-42sAlmPDKes1nLm/aly+0VdaopSU9br+jkRELedhQxI5uXHgtk47I83Mpmf4zoNTRMASdLFtUkimlu/Z9zQ8+g==} | ||||
| 
 | ||||
|   balanced-match@1.0.2: | ||||
|     resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} | ||||
| 
 | ||||
| @ -6320,9 +6311,6 @@ packages: | ||||
|   bmp-ts@1.0.9: | ||||
|     resolution: {integrity: sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==} | ||||
| 
 | ||||
|   bn.js@4.12.1: | ||||
|     resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} | ||||
| 
 | ||||
|   body-parser@1.20.3: | ||||
|     resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} | ||||
|     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} | ||||
| @ -9297,9 +9285,6 @@ packages: | ||||
|     resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} | ||||
|     engines: {node: '>= 0.4'} | ||||
| 
 | ||||
|   is-typedarray@1.0.0: | ||||
|     resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} | ||||
| 
 | ||||
|   is-unicode-supported@0.1.0: | ||||
|     resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} | ||||
|     engines: {node: '>=10'} | ||||
| @ -9708,10 +9693,6 @@ packages: | ||||
|   kolorist@1.8.0: | ||||
|     resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} | ||||
| 
 | ||||
|   kruptein@2.2.3: | ||||
|     resolution: {integrity: sha512-BTwprBPTzkFT9oTugxKd3WnWrX630MqUDsnmBuoa98eQs12oD4n4TeI0GbpdGcYn/73Xueg2rfnw+oK4dovnJg==} | ||||
|     engines: {node: '>6'} | ||||
| 
 | ||||
|   langium@3.3.1: | ||||
|     resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} | ||||
|     engines: {node: '>=16.0.0'} | ||||
| @ -12432,10 +12413,6 @@ packages: | ||||
|     resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} | ||||
|     engines: {node: '>= 0.8.0'} | ||||
| 
 | ||||
|   session-file-store@1.5.0: | ||||
|     resolution: {integrity: sha512-60IZaJNzyu2tIeHutkYE8RiXVx3KRvacOxfLr2Mj92SIsRIroDsH0IlUUR6fJAjoTW4RQISbaOApa2IZpIwFdQ==} | ||||
|     engines: {node: '>= 6'} | ||||
| 
 | ||||
|   set-blocking@2.0.0: | ||||
|     resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} | ||||
| 
 | ||||
| @ -13375,9 +13352,6 @@ packages: | ||||
|   typed-assert@1.0.9: | ||||
|     resolution: {integrity: sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==} | ||||
| 
 | ||||
|   typedarray-to-buffer@3.1.5: | ||||
|     resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} | ||||
| 
 | ||||
|   typedarray@0.0.6: | ||||
|     resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} | ||||
| 
 | ||||
| @ -14073,9 +14047,6 @@ packages: | ||||
|   wrappy@1.0.2: | ||||
|     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} | ||||
| 
 | ||||
|   write-file-atomic@3.0.3: | ||||
|     resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} | ||||
| 
 | ||||
|   write-file-atomic@4.0.2: | ||||
|     resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} | ||||
|     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} | ||||
| @ -20726,13 +20697,6 @@ snapshots: | ||||
| 
 | ||||
|   asap@2.0.6: {} | ||||
| 
 | ||||
|   asn1.js@5.4.1: | ||||
|     dependencies: | ||||
|       bn.js: 4.12.1 | ||||
|       inherits: 2.0.4 | ||||
|       minimalistic-assert: 1.0.1 | ||||
|       safer-buffer: 2.1.2 | ||||
| 
 | ||||
|   assertion-error@2.0.1: {} | ||||
| 
 | ||||
|   ast-types@0.13.4: | ||||
| @ -20900,8 +20864,6 @@ snapshots: | ||||
|       babel-plugin-jest-hoist: 29.6.3 | ||||
|       babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.10) | ||||
| 
 | ||||
|   bagpipe@0.3.5: {} | ||||
| 
 | ||||
|   balanced-match@1.0.2: {} | ||||
| 
 | ||||
|   balanced-match@2.0.0: {} | ||||
| @ -20988,8 +20950,6 @@ snapshots: | ||||
| 
 | ||||
|   bmp-ts@1.0.9: {} | ||||
| 
 | ||||
|   bn.js@4.12.1: {} | ||||
| 
 | ||||
|   body-parser@1.20.3: | ||||
|     dependencies: | ||||
|       bytes: 3.1.2 | ||||
| @ -24569,8 +24529,6 @@ snapshots: | ||||
|     dependencies: | ||||
|       which-typed-array: 1.1.19 | ||||
| 
 | ||||
|   is-typedarray@1.0.0: {} | ||||
| 
 | ||||
|   is-unicode-supported@0.1.0: {} | ||||
| 
 | ||||
|   is-url@1.2.4: {} | ||||
| @ -25207,10 +25165,6 @@ snapshots: | ||||
| 
 | ||||
|   kolorist@1.8.0: {} | ||||
| 
 | ||||
|   kruptein@2.2.3: | ||||
|     dependencies: | ||||
|       asn1.js: 5.4.1 | ||||
| 
 | ||||
|   langium@3.3.1: | ||||
|     dependencies: | ||||
|       chevrotain: 11.0.3 | ||||
| @ -28268,15 +28222,6 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
| 
 | ||||
|   session-file-store@1.5.0: | ||||
|     dependencies: | ||||
|       bagpipe: 0.3.5 | ||||
|       fs-extra: 8.1.0 | ||||
|       kruptein: 2.2.3 | ||||
|       object-assign: 4.1.1 | ||||
|       retry: 0.12.0 | ||||
|       write-file-atomic: 3.0.3 | ||||
| 
 | ||||
|   set-blocking@2.0.0: {} | ||||
| 
 | ||||
|   set-function-length@1.2.2: | ||||
| @ -29481,10 +29426,6 @@ snapshots: | ||||
| 
 | ||||
|   typed-assert@1.0.9: {} | ||||
| 
 | ||||
|   typedarray-to-buffer@3.1.5: | ||||
|     dependencies: | ||||
|       is-typedarray: 1.0.0 | ||||
| 
 | ||||
|   typedarray@0.0.6: {} | ||||
| 
 | ||||
|   typescript-eslint@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3): | ||||
| @ -30336,13 +30277,6 @@ snapshots: | ||||
| 
 | ||||
|   wrappy@1.0.2: {} | ||||
| 
 | ||||
|   write-file-atomic@3.0.3: | ||||
|     dependencies: | ||||
|       imurmurhash: 0.1.4 | ||||
|       is-typedarray: 1.0.0 | ||||
|       signal-exit: 3.0.7 | ||||
|       typedarray-to-buffer: 3.1.5 | ||||
| 
 | ||||
|   write-file-atomic@4.0.2: | ||||
|     dependencies: | ||||
|       imurmurhash: 0.1.4 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran