mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	test(server): ensure session info exists
This commit is contained in:
		
							parent
							
								
									2ceab66b98
								
							
						
					
					
						commit
						e003ec3b6f
					
				@ -2,14 +2,19 @@ import { beforeAll, describe, expect, it } from "vitest";
 | 
				
			|||||||
import supertest from "supertest";
 | 
					import supertest from "supertest";
 | 
				
			||||||
import type { Application } from "express";
 | 
					import type { Application } from "express";
 | 
				
			||||||
import dayjs from "dayjs";
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					import type { SQLiteSessionStore } from "./session_parser.js";
 | 
				
			||||||
 | 
					import { promisify } from "util";
 | 
				
			||||||
 | 
					import { SessionData } from "express-session";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let app: Application;
 | 
					let app: Application;
 | 
				
			||||||
 | 
					let sessionStore: SQLiteSessionStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("Login Route test", () => {
 | 
					describe("Login Route test", () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beforeAll(async () => {
 | 
					    beforeAll(async () => {
 | 
				
			||||||
        const buildApp = (await import("../app.js")).default;
 | 
					        const buildApp = (await import("../app.js")).default;
 | 
				
			||||||
        app = await buildApp();
 | 
					        app = await buildApp();
 | 
				
			||||||
 | 
					        sessionStore = (await import("./session_parser.js")).sessionStore;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("should return the login page, when using a GET request", async () => {
 | 
					    it("should return the login page, when using a GET request", async () => {
 | 
				
			||||||
@ -52,7 +57,7 @@ describe("Login Route test", () => {
 | 
				
			|||||||
        // match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
 | 
					        // match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
 | 
				
			||||||
        const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
 | 
					        const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
 | 
				
			||||||
        const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
 | 
					        const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
 | 
				
			||||||
        const actualExpiresDate = new Date(expiresCookieMatch?.groups?.date || "").toUTCString()
 | 
					        const actualExpiresDate = new Date(expiresCookieMatch?.groups?.date || "").toUTCString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        expect(actualExpiresDate).to.not.eql("Invalid Date");
 | 
					        expect(actualExpiresDate).to.not.eql("Invalid Date");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -60,6 +65,13 @@ describe("Login Route test", () => {
 | 
				
			|||||||
        // if for some reason execution is slow between calculation of expected and actual
 | 
					        // if for some reason execution is slow between calculation of expected and actual
 | 
				
			||||||
        expect(actualExpiresDate.slice(0,23)).toBe(expectedExpiresDate.slice(0,23))
 | 
					        expect(actualExpiresDate.slice(0,23)).toBe(expectedExpiresDate.slice(0,23))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check the session is stored in the database.
 | 
				
			||||||
 | 
					        const session = await getSessionFromCookie(setCookieHeader);
 | 
				
			||||||
 | 
					        expect(session!).toBeTruthy();
 | 
				
			||||||
 | 
					        expect(session!.cookie.expires).toBeTruthy();
 | 
				
			||||||
 | 
					        expect(new Date(session!.cookie.expires!).toUTCString().substring(0, 23))
 | 
				
			||||||
 | 
					            .toBe(expectedExpiresDate.substring(0, 23));
 | 
				
			||||||
 | 
					        expect(session!.loggedIn).toBe(true);
 | 
				
			||||||
    }, 10_000);
 | 
					    }, 10_000);
 | 
				
			||||||
    // use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
 | 
					    // use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
 | 
				
			||||||
    // failing CI, because for some reason it currently takes approx. 6 secs to run
 | 
					    // failing CI, because for some reason it currently takes approx. 6 secs to run
 | 
				
			||||||
@ -67,7 +79,6 @@ describe("Login Route test", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("does not set Expires, when 'Remember Me' is not ticked", async () => {
 | 
					    it("does not set Expires, when 'Remember Me' is not ticked", async () => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        const res = await supertest(app)
 | 
					        const res = await supertest(app)
 | 
				
			||||||
            .post("/login")
 | 
					            .post("/login")
 | 
				
			||||||
            .send({ password: "demo1234" })
 | 
					            .send({ password: "demo1234" })
 | 
				
			||||||
@ -76,14 +87,38 @@ describe("Login Route test", () => {
 | 
				
			|||||||
        const setCookieHeader = res.headers["set-cookie"][0];
 | 
					        const setCookieHeader = res.headers["set-cookie"][0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
 | 
					        // match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
 | 
				
			||||||
        const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
 | 
					        expect(setCookieHeader).not.toMatch(/Expires=(?<date>[\w\s,:]+)/)
 | 
				
			||||||
        const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
 | 
					 | 
				
			||||||
        expect(expiresCookieMatch).toBeNull();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check the session is stored in the database.
 | 
				
			||||||
 | 
					        const session = await getSessionFromCookie(setCookieHeader);
 | 
				
			||||||
 | 
					        expect(session!).toBeTruthy();
 | 
				
			||||||
 | 
					        expect(session!.cookie.expires).toBeUndefined();
 | 
				
			||||||
 | 
					        expect(session!.loggedIn).toBe(true);
 | 
				
			||||||
    }, 10_000);
 | 
					    }, 10_000);
 | 
				
			||||||
    // use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
 | 
					    // use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
 | 
				
			||||||
    // failing CI, because for some reason it currently takes approx. 6 secs to run
 | 
					    // failing CI, because for some reason it currently takes approx. 6 secs to run
 | 
				
			||||||
    // TODO: actually identify what is causing this and fix the flakiness
 | 
					    // TODO: actually identify what is causing this and fix the flakiness
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function getSessionFromCookie(setCookieHeader: string) {
 | 
				
			||||||
 | 
					    // Extract the session ID from the cookie.
 | 
				
			||||||
 | 
					    const sessionIdMatch = setCookieHeader.match(/trilium.sid=(?<sessionId>[^;]+)/)?.[1];
 | 
				
			||||||
 | 
					    expect(sessionIdMatch).toBeTruthy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check the session is stored in the database.
 | 
				
			||||||
 | 
					    const sessionId = decodeURIComponent(sessionIdMatch!).slice(2).split(".")[0];
 | 
				
			||||||
 | 
					    return await getSessionFromStore(sessionId);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getSessionFromStore(sessionId: string) {
 | 
				
			||||||
 | 
					    return new Promise<SessionData | null | undefined>((resolve, reject) => {
 | 
				
			||||||
 | 
					        sessionStore.get(sessionId, (err, session) => {
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                reject(err);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                resolve(session);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								apps/server/src/routes/session_parser.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								apps/server/src/routes/session_parser.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import { beforeAll, describe, expect, it } from "vitest";
 | 
				
			||||||
 | 
					import supertest from "supertest";
 | 
				
			||||||
 | 
					import type { Application } from "express";
 | 
				
			||||||
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					let app: Application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("Session parser", () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beforeAll(async () => {
 | 
				
			||||||
 | 
					        const buildApp = (await import("../app.js")).default;
 | 
				
			||||||
 | 
					        app = await buildApp();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -5,7 +5,7 @@ import config from "../services/config.js";
 | 
				
			|||||||
import log from "../services/log.js";
 | 
					import log from "../services/log.js";
 | 
				
			||||||
import type express from "express";
 | 
					import type express from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SQLiteSessionStore extends Store {
 | 
					export class SQLiteSessionStore extends Store {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void {
 | 
					    get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
@ -52,6 +52,8 @@ class SQLiteSessionStore extends Store {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const sessionStore = new SQLiteSessionStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sessionParser: express.RequestHandler = session({
 | 
					const sessionParser: express.RequestHandler = session({
 | 
				
			||||||
    secret: sessionSecret,
 | 
					    secret: sessionSecret,
 | 
				
			||||||
    resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
 | 
					    resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
 | 
				
			||||||
@ -62,7 +64,7 @@ const sessionParser: express.RequestHandler = session({
 | 
				
			|||||||
        maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds
 | 
					        maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    name: "trilium.sid",
 | 
					    name: "trilium.sid",
 | 
				
			||||||
    store: new SQLiteSessionStore()
 | 
					    store: sessionStore
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setInterval(() => {
 | 
					setInterval(() => {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user