mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-30 10:36:35 +02:00
Server: Expire sessions after 12 hours
This commit is contained in:
parent
134bc91e20
commit
0ada1dfb46
46
packages/server/src/models/SessionModel.test.ts
Normal file
46
packages/server/src/models/SessionModel.test.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { createUserAndSession, beforeAllDb, afterAllTests, beforeEachDb, models } from '../utils/testing/testUtils';
|
||||
import { defaultSessionTtl } from './SessionModel';
|
||||
|
||||
describe('SessionModel', function() {
|
||||
|
||||
beforeAll(async () => {
|
||||
await beforeAllDb('SessionModel');
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await afterAllTests();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await beforeEachDb();
|
||||
});
|
||||
|
||||
test('should delete expired sessions', async function() {
|
||||
jest.useFakeTimers('modern');
|
||||
|
||||
const t0 = new Date('2020-01-01T00:00:00').getTime();
|
||||
jest.setSystemTime(t0);
|
||||
|
||||
const { user, password } = await createUserAndSession(1);
|
||||
await models().session().authenticate(user.email, password);
|
||||
|
||||
jest.setSystemTime(new Date(t0 + defaultSessionTtl + 10));
|
||||
|
||||
const lastSession = await models().session().authenticate(user.email, password);
|
||||
|
||||
expect(await models().session().count()).toBe(3);
|
||||
|
||||
await models().session().deleteExpiredSessions();
|
||||
|
||||
expect(await models().session().count()).toBe(1);
|
||||
expect((await models().session().all())[0].id).toBe(lastSession.id);
|
||||
|
||||
await models().session().authenticate(user.email, password);
|
||||
await models().session().deleteExpiredSessions();
|
||||
|
||||
expect(await models().session().count()).toBe(2);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
});
|
@ -2,6 +2,9 @@ import BaseModel from './BaseModel';
|
||||
import { User, Session, Uuid } from '../services/database/types';
|
||||
import uuidgen from '../utils/uuidgen';
|
||||
import { ErrorForbidden } from '../utils/errors';
|
||||
import { Hour } from '../utils/time';
|
||||
|
||||
export const defaultSessionTtl = 12 * Hour;
|
||||
|
||||
export default class SessionModel extends BaseModel<Session> {
|
||||
|
||||
@ -40,4 +43,9 @@ export default class SessionModel extends BaseModel<Session> {
|
||||
await query.delete();
|
||||
}
|
||||
|
||||
public async deleteExpiredSessions() {
|
||||
const cutOffTime = Date.now() - defaultSessionTtl;
|
||||
await this.db(this.tableName).where('created_time', '<', cutOffTime).delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ export enum TaskId {
|
||||
HandleOversizedAccounts = 3,
|
||||
HandleBetaUserEmails = 4,
|
||||
HandleFailedPaymentSubscriptions = 5,
|
||||
DeleteExpiredSessions = 6,
|
||||
}
|
||||
|
||||
export enum RunType {
|
||||
|
@ -5,6 +5,7 @@ import Router from './Router';
|
||||
import { AppContext, HttpMethod, RouteType } from './types';
|
||||
import { URL } from 'url';
|
||||
import { csrfCheck } from './csrf';
|
||||
import { contextSessionId } from './requestUtils';
|
||||
|
||||
const { ltrimSlashes, rtrimSlashes } = require('@joplin/lib/path-utils');
|
||||
|
||||
@ -200,7 +201,16 @@ export async function execRequest(routes: Routers, ctx: AppContext) {
|
||||
// This is a generic catch-all for all private end points - if we
|
||||
// couldn't get a valid session, we exit now. Individual end points
|
||||
// might have additional permission checks depending on the action.
|
||||
if (!isPublicRoute && !ctx.joplin.owner) throw new ErrorForbidden();
|
||||
if (!isPublicRoute && !ctx.joplin.owner) {
|
||||
if (contextSessionId(ctx, false)) {
|
||||
// If we have a session but not a user it means the session was
|
||||
// invalid or has expired, so display a special message, since this
|
||||
// is also going to be displayed on the website.
|
||||
throw new ErrorForbidden('Your session has expired. Please login again.');
|
||||
} else {
|
||||
throw new ErrorForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
await csrfCheck(ctx, isPublicRoute);
|
||||
disabledAccountCheck(match, ctx.joplin.owner);
|
||||
|
@ -29,6 +29,13 @@ export default function(env: Env, models: Models, config: Config): TaskService {
|
||||
schedule: '0 */2 30 * *',
|
||||
run: (models: Models) => models.user().handleOversizedAccounts(),
|
||||
},
|
||||
|
||||
{
|
||||
id: TaskId.DeleteExpiredSessions,
|
||||
description: 'Delete expired sessions',
|
||||
schedule: '0 */6 * * *',
|
||||
run: (models: Models) => models.session().deleteExpiredSessions(),
|
||||
},
|
||||
];
|
||||
|
||||
if (config.isJoplinCloud) {
|
||||
|
Loading…
Reference in New Issue
Block a user