gitpod/components/server/src/session-handler.ts
Gero Posmyk-Leinemann 7abe78c917 [dev] Upgrade to node.js v16 and all major TS libs
This commit includes the following commits:
 - @iqqbot update dev image to nodejs v16lts
 - @iqqbot update dev-environment-image to use nodejs v16
 - @iqqbot update component to nodejs v16 lts
 - [licensor] Adjust to v16
 - [ts] Bump @types/node to ^16.11.0 accordingly
 - @aledbf Update typescript dependencies
 - @aledbf Update typescript configuration
 - @aledbf / @geropl Update typescript code
 - [server] Fix express/passport types
 - [db] typeorm upgrade 0.1.20 -> 0.2.22: fix compile and runtime issues
 - [db] typeorm upgrade 0.2.22 -> 0.2.38: fix compile and runtime issues
 - [dev] Upgrade amqplib and smaller libs
 - [dev] Upgrade uuid
 - [dev] Update probot
 - [dev] Final yarn.lock
2021-11-02 13:59:10 +01:00

104 lines
4.1 KiB
TypeScript

/**
* Copyright (c) 2020 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/
import * as express from 'express';
import * as session from 'express-session';
import { SessionOptions } from 'express-session';
import { v4 as uuidv4 } from 'uuid';
import { injectable, inject , postConstruct } from 'inversify';
import * as mysqlstore from 'express-mysql-session';
const MySQLStore = mysqlstore(session);
import { log } from '@gitpod/gitpod-protocol/lib/util/logging';
import { Config as DBConfig } from '@gitpod/gitpod-db/lib/config';
import { Config } from './config';
@injectable()
export class SessionHandlerProvider {
@inject(Config) protected readonly config: Config;
@inject(DBConfig) protected readonly dbConfig: DBConfig;
public sessionHandler: express.RequestHandler
@postConstruct()
public init() {
const options: SessionOptions = {} as SessionOptions
options.cookie = this.getCookieOptions(this.config);
options.genid = function (req: any) {
return uuidv4() // use UUIDs for session IDs
},
options.name = SessionHandlerProvider.getCookieName(this.config);
// options.proxy = true // TODO SSL Proxy
options.resave = true // TODO Check with store! See docu
options.rolling = true // default, new cookie and maxAge
options.secret = this.config.session.secret;
options.saveUninitialized = false // Do not save new cookie without content (uninitialized)
options.store = this.createStore();
this.sessionHandler = session(options);
}
protected getCookieOptions(config: Config): express.CookieOptions {
const hostName = config.hostUrl.url.host;
let domain = hostName;
if (config.devBranch) {
// Use cookie for base domain to allow cookies being sent via ingress proxy in preview environments
//
// Otherwise, clients (in this case Chrome) may ignore (as in: save it, but don't send it on consequent requests) the 'Set-Cookie:...' send with a redirect (302, to github oauth)
// For details, see:
// - RFC draft sameSite: http://httpwg.org/http-extensions/draft-ietf-httpbis-cookie-same-site.html
// - https://bugs.chromium.org/p/chromium/issues/detail?id=150066
// - google: chromium not sending cookies set with redirect
const hostParts = hostName.split('.');
const baseDomain = hostParts.slice(hostParts.length - 2).join('.');
domain = `.${baseDomain}`;
}
if (this.config.insecureNoDomain) {
domain = hostName.split(":")[0];
}
return {
path: "/", // default
httpOnly: true, // default
secure: false, // default, TODO SSL! Config proxy
maxAge: config.session.maxAgeMs, // configured in Helm chart, defaults to 3 days.
sameSite: "lax", // default: true. "Lax" needed for OAuth.
domain: `${domain}`
};
}
static getCookieName(config: Config) {
return config.hostUrl.toString()
.replace(/https?/, '')
.replace(/[\W_]+/g, "_");
}
public clearSessionCookie(res: express.Response, config: Config): void {
// http://expressjs.com/en/api.html#res.clearCookie
const name = SessionHandlerProvider.getCookieName(config);
const options = { ...this.getCookieOptions(config) };
delete options.expires;
delete options.maxAge;
res.clearCookie(name, options);
}
protected createStore(): any | undefined {
const options = {
...(this.dbConfig.dbConfig as any),
user: this.dbConfig.dbConfig.username,
database: 'gitpod-sessions',
createDatabaseTable: true
};
return new MySQLStore(options, undefined, (err) => {
if (err) {
log.debug('MySQL session store error: ', err);
}
});
}
}