Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
4.7 KiB

import assert from 'assert';
import session, {
SessionData,
Store as BaseSessionStore,
} from 'express-session';
import {
dbQuery,
dbWrite,
getLocalHostUUID,
timestamp,
} from './lib/accessModule';
import { getSessionSecret } from './lib/getSessionSecret';
import { stdout, stdoutVar, uuidgen } from './lib/shell';
const DEFAULT_COOKIE_ORIGINAL_MAX_AGE = 1000 * 60 * 60;
export class SessionStore extends BaseSessionStore {
constructor(options = {}) {
super(options);
}
public destroy(
sid: string,
done?: ((err?: unknown) => void) | undefined,
): void {
stdout(`Destroy session ${sid}`);
try {
const { write_code: wcode }: { write_code: number } = dbWrite(
`DELETE FROM sessions WHERE session_uuid = '${sid}';`,
).stdout;
assert(wcode === 0, `Delete session ${sid} failed with code ${wcode}`);
} catch (writeError) {
return done?.call(null, writeError);
}
return done?.call(null);
}
public get(
sid: string,
done: (err: unknown, session?: SessionData | null | undefined) => void,
): void {
stdout(`Get session ${sid}`);
let rows: [
sessionUuid: string,
userUuid: string,
sessionModifiedDate: string,
][];
try {
rows = dbQuery(
`SELECT
s.session_uuid,
u.user_uuid,
s.modified_date
FROM sessions AS s
JOIN users AS u
ON s.session_user_uuid = u.user_uuid
WHERE s.session_uuid = '${sid}';`,
).stdout;
} catch (queryError) {
return done(queryError);
}
if (!rows.length) {
return done(null);
}
const {
0: [, userUuid, sessionModifiedDate],
} = rows;
const cookieMaxAge =
SessionStore.calculateCookieMaxAge(sessionModifiedDate);
const data: SessionData = {
cookie: {
maxAge: cookieMaxAge,
originalMaxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE,
},
passport: {
user: userUuid,
},
};
return done(null, data);
}
public set(
sid: string,
session: SessionData,
done?: ((err?: unknown) => void) | undefined,
): void {
stdout(`Set session ${sid}; session=${JSON.stringify(session, null, 2)}`);
const {
passport: { user: userUuid },
} = session;
try {
const localHostUuid = getLocalHostUUID();
const modifiedDate = timestamp();
const { write_code: wcode }: { write_code: number } = dbWrite(
`INSERT INTO
sessions (
session_uuid,
session_host_uuid,
session_user_uuid,
session_salt,
modified_date
)
VALUES
(
'${sid}',
'${localHostUuid}',
'${userUuid}',
'',
'${modifiedDate}'
)
ON CONFLICT (session_uuid)
DO UPDATE SET session_host_uuid = '${localHostUuid}',
modified_date = '${modifiedDate}';`,
).stdout;
assert(
wcode === 0,
`Insert or update session ${sid} failed with code ${wcode}`,
);
} catch (error) {
return done?.call(null, error);
}
return done?.call(null);
}
public touch(
sid: string,
session: SessionData,
done?: ((err?: unknown) => void) | undefined,
): void {
stdout(
`Update modified date in session ${sid}; session=${JSON.stringify(
session,
null,
2,
)}`,
);
try {
const { write_code: wcode }: { write_code: number } = dbWrite(
`UPDATE sessions SET modified_date = '${timestamp()}' WHERE session_uuid = '${sid}';`,
).stdout;
assert(
wcode === 0,
`Update modified date for session ${sid} failed with code ${wcode}`,
);
} catch (writeError) {
return done?.call(null, writeError);
}
return done?.call(null);
}
public static calculateCookieMaxAge(
sessionModifiedDate: string,
cookieOriginalMaxAge: number = DEFAULT_COOKIE_ORIGINAL_MAX_AGE,
) {
const sessionModifiedEpoch = Date.parse(sessionModifiedDate);
const sessionDeadlineEpoch = sessionModifiedEpoch + cookieOriginalMaxAge;
const cookieMaxAge = sessionDeadlineEpoch - Date.now();
stdoutVar({ sessionModifiedDate, sessionDeadlineEpoch, cookieMaxAge });
return cookieMaxAge;
}
}
const sessionHandler = session({
cookie: { maxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE },
genid: ({ path }) => {
const sid = uuidgen('--random').trim();
stdout(`Generated session identifier ${sid}; request.path=${path}`);
return sid;
},
resave: false,
saveUninitialized: false,
secret: getSessionSecret(),
store: new SessionStore(),
});
export default sessionHandler;