From e947fed979ce01c569dec87663fae3e9827d8910 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 2 Jul 2017 22:24:51 +0200 Subject: [PATCH] Read configuration of redis from the yaml file. --- Gruntfile.js | 5 +- src/server/lib/ConfigurationAdapter.ts | 3 +- src/server/lib/Server.ts | 12 +- src/server/lib/SessionConfigurationBuilder.ts | 4 +- src/types/Configuration.ts | 10 +- ...r.test.ts => ConfigurationAdapter.test.ts} | 0 .../SessionConfigurationBuilder.test.ts | 123 ++++++++++++++++++ 7 files changed, 142 insertions(+), 15 deletions(-) rename test/server/{config_adapter.test.ts => ConfigurationAdapter.test.ts} (100%) create mode 100644 test/server/SessionConfigurationBuilder.test.ts diff --git a/Gruntfile.js b/Gruntfile.js index 775c85d38..3313edc2d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -109,7 +109,7 @@ module.exports = function (grunt) { }, client: { files: ['src/client/**/*.ts', 'test/client/**/*.ts'], - tasks: ['build'], + tasks: ['build-dev'], options: { interrupt: true, atBegin: true @@ -117,9 +117,10 @@ module.exports = function (grunt) { }, server: { files: ['src/server/**/*.ts', 'test/server/**/*.ts'], - tasks: ['build', 'run:docker-restart', 'run:make-dev-views' ], + tasks: ['build-dev', 'run:docker-restart', 'run:make-dev-views' ], options: { interrupt: true, + atBegin: true } } }, diff --git a/src/server/lib/ConfigurationAdapter.ts b/src/server/lib/ConfigurationAdapter.ts index 4779fa080..3cbca9168 100644 --- a/src/server/lib/ConfigurationAdapter.ts +++ b/src/server/lib/ConfigurationAdapter.ts @@ -1,6 +1,6 @@ import * as ObjectPath from "object-path"; -import { AppConfiguration, UserConfiguration, NotifierConfiguration, ACLConfiguration, LdapConfiguration } from "./../../types/Configuration"; +import { AppConfiguration, UserConfiguration, NotifierConfiguration, ACLConfiguration, LdapConfiguration, SessionRedisOptions } from "./../../types/Configuration"; const LDAP_URL_ENV_VARIABLE = "LDAP_URL"; @@ -32,6 +32,7 @@ function adaptFromUserConfiguration(userConfiguration: UserConfiguration): AppCo domain: ObjectPath.get(userConfiguration, "session.domain"), secret: ObjectPath.get(userConfiguration, "session.secret"), expiration: get_optional(userConfiguration, "session.expiration", 3600000), // in ms + redis: ObjectPath.get(userConfiguration, "session.redis") }, store_directory: get_optional(userConfiguration, "store_directory", undefined), logs_level: get_optional(userConfiguration, "logs_level", "info"), diff --git a/src/server/lib/Server.ts b/src/server/lib/Server.ts index 84c01d04a..c9d888a7b 100644 --- a/src/server/lib/Server.ts +++ b/src/server/lib/Server.ts @@ -21,14 +21,14 @@ import * as http from "http"; export default class Server { private httpServer: http.Server; - start(yaml_configuration: UserConfiguration, deps: GlobalDependencies): BluebirdPromise { - const config = ConfigurationAdapter.adapt(yaml_configuration); + start(yamlConfiguration: UserConfiguration, deps: GlobalDependencies): BluebirdPromise { + const config = ConfigurationAdapter.adapt(yamlConfiguration); - const view_directory = Path.resolve(__dirname, "../views"); - const public_html_directory = Path.resolve(__dirname, "../public_html"); + const viewsDirectory = Path.resolve(__dirname, "../views"); + const publicHtmlDirectory = Path.resolve(__dirname, "../public_html"); const app = Express(); - app.use(Express.static(public_html_directory)); + app.use(Express.static(publicHtmlDirectory)); app.use(BodyParser.urlencoded({ extended: false })); app.use(BodyParser.json()); @@ -37,7 +37,7 @@ export default class Server { const sessionOptions = SessionConfigurationBuilder.build(config, deps); app.use(deps.session(sessionOptions)); - app.set("views", view_directory); + app.set("views", viewsDirectory); app.set("view engine", "pug"); // by default the level of logs is info diff --git a/src/server/lib/SessionConfigurationBuilder.ts b/src/server/lib/SessionConfigurationBuilder.ts index 8d846a37b..3fa6c661d 100644 --- a/src/server/lib/SessionConfigurationBuilder.ts +++ b/src/server/lib/SessionConfigurationBuilder.ts @@ -19,7 +19,8 @@ export default class SessionConfigurationBuilder { if (configuration.session.redis) { let redisOptions; - if (configuration.session.redis.host && configuration.session.redis.port) { + if (configuration.session.redis.host + && configuration.session.redis.port) { redisOptions = { host: configuration.session.redis.host, port: configuration.session.redis.port @@ -31,7 +32,6 @@ export default class SessionConfigurationBuilder { sessionOptions.store = new RedisStore(redisOptions); } } - return sessionOptions; } } \ No newline at end of file diff --git a/src/types/Configuration.ts b/src/types/Configuration.ts index ce88fe35b..8c2c9192a 100644 --- a/src/types/Configuration.ts +++ b/src/types/Configuration.ts @@ -24,14 +24,16 @@ export interface ACLConfiguration { users: ACLUsersRules; } +export interface SessionRedisOptions { + host: string; + port: number; +} + interface SessionCookieConfiguration { secret: string; expiration?: number; domain?: string; - redis?: { - host: string; - port: number; - }; + redis?: SessionRedisOptions; } export interface GmailNotifierConfiguration { diff --git a/test/server/config_adapter.test.ts b/test/server/ConfigurationAdapter.test.ts similarity index 100% rename from test/server/config_adapter.test.ts rename to test/server/ConfigurationAdapter.test.ts diff --git a/test/server/SessionConfigurationBuilder.test.ts b/test/server/SessionConfigurationBuilder.test.ts new file mode 100644 index 000000000..53891300a --- /dev/null +++ b/test/server/SessionConfigurationBuilder.test.ts @@ -0,0 +1,123 @@ +import SessionConfigurationBuilder from "../../src/server/lib/SessionConfigurationBuilder"; +import { AppConfiguration } from "../../src/types/Configuration"; +import { GlobalDependencies } from "../../src/types/Dependencies"; +import ExpressSession = require("express-session"); +import ConnectRedis = require("connect-redis"); +import sinon = require("sinon"); +import Assert = require("assert"); + +describe.only("test session configuration builder", function () { + it("should return session options without redis options", function () { + const configuration: AppConfiguration = { + access_control: { + default: [], + users: {}, + groups: {} + }, + ldap: { + url: "ldap://ldap", + base_dn: "dc=example,dc=com", + user: "user", + password: "password" + }, + logs_level: "debug", + notifier: { + filesystem: { + filename: "/test" + } + }, + port: 8080, + session: { + domain: "example.com", + expiration: 3600, + secret: "secret" + }, + store_in_memory: true + }; + + const deps: GlobalDependencies = { + ConnectRedis: sinon.spy() as any, + ldapjs: sinon.spy() as any, + nedb: sinon.spy() as any, + nodemailer: sinon.spy() as any, + session: sinon.spy() as any, + speakeasy: sinon.spy() as any, + u2f: sinon.spy() as any, + winston: sinon.spy() as any + }; + + const options = SessionConfigurationBuilder.build(configuration, deps); + + const expectedOptions = { + secret: "secret", + resave: false, + saveUninitialized: true, + cookie: { + secure: false, + maxAge: 3600, + domain: "example.com" + } + }; + + Assert.deepEqual(expectedOptions, options); + }); + + it("should return session options with redis options", function () { + const configuration: AppConfiguration = { + access_control: { + default: [], + users: {}, + groups: {} + }, + ldap: { + url: "ldap://ldap", + base_dn: "dc=example,dc=com", + user: "user", + password: "password" + }, + logs_level: "debug", + notifier: { + filesystem: { + filename: "/test" + } + }, + port: 8080, + session: { + domain: "example.com", + expiration: 3600, + secret: "secret", + redis: { + host: "redis.example.com", + port: 6379 + } + }, + store_in_memory: true + }; + + const deps: GlobalDependencies = { + ConnectRedis: sinon.stub().returns({ RedisStore: sinon.spy() }) as any, + ldapjs: sinon.spy() as any, + nedb: sinon.spy() as any, + nodemailer: sinon.spy() as any, + session: sinon.spy() as any, + speakeasy: sinon.spy() as any, + u2f: sinon.spy() as any, + winston: sinon.spy() as any + }; + + const options = SessionConfigurationBuilder.build(configuration, deps); + + const expectedOptions: ExpressSession.SessionOptions = { + secret: "secret", + resave: false, + saveUninitialized: true, + cookie: { + secure: false, + maxAge: 3600, + domain: "example.com" + } + }; + + Assert(expectedOptions.store != undefined); + }); +}); \ No newline at end of file