From 57278a73069bd8e7fefbfefcd5a10789f93fff37 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sat, 20 May 2017 09:49:05 +0200 Subject: [PATCH] Move notifiers to typescript --- package.json | 3 + src/lib/Configuration.ts | 20 +++--- src/lib/ConfigurationAdapter.ts | 42 +++++++++++ src/lib/Dependencies.ts | 22 ++++++ src/lib/GlobalDependencies.ts | 11 --- src/lib/Identity.ts | 6 ++ src/lib/Server.ts | 16 ++--- src/lib/config_adapter.ts | 40 ----------- src/lib/notifier.js | 24 ------- src/lib/notifiers/FileSystemNotifier.ts | 25 +++++++ src/lib/notifiers/GMailNotifier.ts | 44 ++++++++++++ src/lib/notifiers/INotifier.ts | 7 ++ src/lib/notifiers/NotifierFactory.ts | 22 ++++++ src/lib/notifiers/filesystem.js | 16 ----- src/lib/notifiers/gmail.js | 33 --------- test/unitary/Server.test.ts | 4 +- test/unitary/config_adapter.test.ts | 29 ++++---- test/unitary/data_persistence.test.ts | 6 +- test/unitary/mocks/nodemailer.ts | 7 ++ .../notifiers/FileSystemNotifier.test.ts | 42 +++++++++++ test/unitary/notifiers/GMailNotifier.test.ts | 39 +++++++++++ .../unitary/notifiers/NotifierFactory.test.ts | 39 +++++++++++ test/unitary/notifiers/test_fs.js | 37 ---------- test/unitary/notifiers/test_gmail.js | 36 ---------- test/unitary/notifiers/test_notifier.js | 35 ---------- test/unitary/server_config.test.ts | 10 +-- test/unitary/test_server_config.ts | 69 +++++++++++++++++++ 27 files changed, 411 insertions(+), 273 deletions(-) create mode 100644 src/lib/ConfigurationAdapter.ts create mode 100644 src/lib/Dependencies.ts delete mode 100644 src/lib/GlobalDependencies.ts create mode 100644 src/lib/Identity.ts delete mode 100644 src/lib/config_adapter.ts delete mode 100644 src/lib/notifier.js create mode 100644 src/lib/notifiers/FileSystemNotifier.ts create mode 100644 src/lib/notifiers/GMailNotifier.ts create mode 100644 src/lib/notifiers/INotifier.ts create mode 100644 src/lib/notifiers/NotifierFactory.ts delete mode 100644 src/lib/notifiers/filesystem.js delete mode 100644 src/lib/notifiers/gmail.js create mode 100644 test/unitary/mocks/nodemailer.ts create mode 100644 test/unitary/notifiers/FileSystemNotifier.test.ts create mode 100644 test/unitary/notifiers/GMailNotifier.test.ts create mode 100644 test/unitary/notifiers/NotifierFactory.test.ts delete mode 100644 test/unitary/notifiers/test_fs.js delete mode 100644 test/unitary/notifiers/test_gmail.js delete mode 100644 test/unitary/notifiers/test_notifier.js create mode 100644 test/unitary/test_server_config.ts diff --git a/package.json b/package.json index a5078e69..09cc9f23 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@types/assert": "0.0.31", "@types/bluebird": "^3.5.3", "@types/body-parser": "^1.16.3", + "@types/ejs": "^2.3.33", "@types/express": "^4.0.35", "@types/express-session": "0.0.32", "@types/ldapjs": "^1.0.0", @@ -56,6 +57,7 @@ "@types/nedb": "^1.8.3", "@types/nodemailer": "^1.3.32", "@types/object-path": "^0.9.28", + "@types/proxyquire": "^1.3.27", "@types/request": "0.0.43", "@types/sinon": "^2.2.1", "@types/speakeasy": "^2.0.1", @@ -67,6 +69,7 @@ "grunt-run": "^0.6.0", "mocha": "^3.2.0", "mockdate": "^2.0.1", + "proxyquire": "^1.8.0", "request": "^2.79.0", "should": "^11.1.1", "sinon": "^1.17.6", diff --git a/src/lib/Configuration.ts b/src/lib/Configuration.ts index 2ed31f56..d077f42e 100644 --- a/src/lib/Configuration.ts +++ b/src/lib/Configuration.ts @@ -30,14 +30,18 @@ interface SessionCookieConfiguration { domain?: string; } -interface GMailNotifier { - user: string; - pass: string; +export interface GmailNotifierConfiguration { + username: string; + password: string; } -type NotifierType = string; -export interface NotifiersConfiguration { - gmail: GMailNotifier; +export interface FileSystemNotifierConfiguration { + filename: string; +} + +export interface NotifierConfiguration { + gmail?: GmailNotifierConfiguration; + filesystem?: FileSystemNotifierConfiguration; } export interface UserConfiguration { @@ -46,7 +50,7 @@ export interface UserConfiguration { ldap: LdapConfiguration; session: SessionCookieConfiguration; store_directory?: string; - notifier: NotifiersConfiguration; + notifier: NotifierConfiguration; access_control?: ACLConfiguration; } @@ -57,6 +61,6 @@ export interface AppConfiguration { session: SessionCookieConfiguration; store_in_memory?: boolean; store_directory?: string; - notifier: NotifiersConfiguration; + notifier: NotifierConfiguration; access_control?: ACLConfiguration; } diff --git a/src/lib/ConfigurationAdapter.ts b/src/lib/ConfigurationAdapter.ts new file mode 100644 index 00000000..2742d135 --- /dev/null +++ b/src/lib/ConfigurationAdapter.ts @@ -0,0 +1,42 @@ + +import * as ObjectPath from "object-path"; +import { AppConfiguration, UserConfiguration, NotifierConfiguration, ACLConfiguration, LdapConfiguration } from "./Configuration"; + + +function get_optional(config: object, path: string, default_value: T): T { + let entry = default_value; + if (ObjectPath.has(config, path)) { + entry = ObjectPath.get(config, path); + } + return entry; +} + +function ensure_key_existence(config: object, path: string): void { + if (!ObjectPath.has(config, path)) { + throw new Error(`Configuration error: key '${path}' is missing in configuration file`); + } +} + +export default class ConfigurationAdapter { + static adapt(yaml_config: UserConfiguration): AppConfiguration { + ensure_key_existence(yaml_config, "ldap"); + ensure_key_existence(yaml_config, "session.secret"); + + const port = ObjectPath.get(yaml_config, "port", 8080); + + return { + port: port, + ldap: ObjectPath.get(yaml_config, "ldap"), + session: { + domain: ObjectPath.get(yaml_config, "session.domain"), + secret: ObjectPath.get(yaml_config, "session.secret"), + expiration: get_optional(yaml_config, "session.expiration", 3600000), // in ms + }, + store_directory: get_optional(yaml_config, "store_directory", undefined), + logs_level: get_optional(yaml_config, "logs_level", "info"), + notifier: ObjectPath.get(yaml_config, "notifier"), + access_control: ObjectPath.get(yaml_config, "access_control") + }; + } +} + diff --git a/src/lib/Dependencies.ts b/src/lib/Dependencies.ts new file mode 100644 index 00000000..0cfa344f --- /dev/null +++ b/src/lib/Dependencies.ts @@ -0,0 +1,22 @@ +import * as winston from "winston"; +import nodemailer = require("nodemailer"); + +export interface Nodemailer { + createTransport: (options?: any, defaults?: Object) => nodemailer.Transporter; +} + +export interface GlobalDependencies { + u2f: object; + nodemailer: Nodemailer; + ldapjs: object; + session: any; + winston: winston.Winston; + speakeasy: object; + nedb: any; +} + +export type NodemailerDependencies = Nodemailer; + +export interface NotifierDependencies { + nodemailer: Nodemailer; +} \ No newline at end of file diff --git a/src/lib/GlobalDependencies.ts b/src/lib/GlobalDependencies.ts deleted file mode 100644 index 4b71f273..00000000 --- a/src/lib/GlobalDependencies.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as winston from "winston"; - -export interface GlobalDependencies { - u2f: object; - nodemailer: any; - ldapjs: object; - session: any; - winston: winston.Winston; - speakeasy: object; - nedb: any; -} \ No newline at end of file diff --git a/src/lib/Identity.ts b/src/lib/Identity.ts new file mode 100644 index 00000000..e985984e --- /dev/null +++ b/src/lib/Identity.ts @@ -0,0 +1,6 @@ + + +export interface Identity { + userid: string; + email: string; +} \ No newline at end of file diff --git a/src/lib/Server.ts b/src/lib/Server.ts index 8df410f6..360e90c6 100644 --- a/src/lib/Server.ts +++ b/src/lib/Server.ts @@ -1,16 +1,16 @@ import { UserConfiguration } from "./Configuration"; -import { GlobalDependencies } from "./GlobalDependencies"; +import { GlobalDependencies } from "./Dependencies"; +import { AuthenticationRegulator } from "./AuthenticationRegulator"; +import UserDataStore from "./UserDataStore"; +import ConfigurationAdapter from "./ConfigurationAdapter"; +import { NotifierFactory } from "./notifiers/NotifierFactory"; + import * as Express from "express"; import * as BodyParser from "body-parser"; import * as Path from "path"; -import { AuthenticationRegulator } from "./AuthenticationRegulator"; -import UserDataStore from "./UserDataStore"; import * as http from "http"; -import config_adapter = require("./config_adapter"); - -const Notifier = require("./notifier"); const setup_endpoints = require("./setup_endpoints"); const Ldap = require("./ldap"); const AccessControl = require("./access_control"); @@ -19,7 +19,7 @@ export default class Server { private httpServer: http.Server; start(yaml_configuration: UserConfiguration, deps: GlobalDependencies): Promise { - const config = config_adapter(yaml_configuration); + const config = ConfigurationAdapter.adapt(yaml_configuration); const view_directory = Path.resolve(__dirname, "../views"); const public_html_directory = Path.resolve(__dirname, "../public_html"); @@ -54,7 +54,7 @@ export default class Server { const five_minutes = 5 * 60; const data_store = new UserDataStore(datastore_options); const regulator = new AuthenticationRegulator(data_store, five_minutes); - const notifier = new Notifier(config.notifier, deps); + const notifier = NotifierFactory.build(config.notifier, deps); const ldap = new Ldap(deps, config.ldap); const access_control = AccessControl(deps.winston, config.access_control); diff --git a/src/lib/config_adapter.ts b/src/lib/config_adapter.ts deleted file mode 100644 index 5503f1c8..00000000 --- a/src/lib/config_adapter.ts +++ /dev/null @@ -1,40 +0,0 @@ - -import * as ObjectPath from "object-path"; -import { AppConfiguration, UserConfiguration, NotifiersConfiguration, ACLConfiguration, LdapConfiguration } from "./Configuration"; - - -function get_optional(config: object, path: string, default_value: T): T { - let entry = default_value; - if (ObjectPath.has(config, path)) { - entry = ObjectPath.get(config, path); - } - return entry; -} - -function ensure_key_existence(config: object, path: string): void { - if (!ObjectPath.has(config, path)) { - throw new Error(`Configuration error: key '${path}' is missing in configuration file`); - } -} - -export = function(yaml_config: UserConfiguration): AppConfiguration { - ensure_key_existence(yaml_config, "ldap"); - ensure_key_existence(yaml_config, "session.secret"); - - const port = ObjectPath.get(yaml_config, "port", 8080); - - return { - port: port, - ldap: ObjectPath.get(yaml_config, "ldap"), - session: { - domain: ObjectPath.get(yaml_config, "session.domain"), - secret: ObjectPath.get(yaml_config, "session.secret"), - expiration: get_optional(yaml_config, "session.expiration", 3600000), // in ms - }, - store_directory: get_optional(yaml_config, "store_directory", undefined), - logs_level: get_optional(yaml_config, "logs_level", "info"), - notifier: ObjectPath.get(yaml_config, "notifier"), - access_control: ObjectPath.get(yaml_config, "access_control") - }; -}; - diff --git a/src/lib/notifier.js b/src/lib/notifier.js deleted file mode 100644 index 84ba6060..00000000 --- a/src/lib/notifier.js +++ /dev/null @@ -1,24 +0,0 @@ - -module.exports = Notifier; - -var GmailNotifier = require('./notifiers/gmail.js'); -var FSNotifier = require('./notifiers/filesystem.js'); - -function notifier_factory(options, deps) { - if('gmail' in options) { - return new GmailNotifier(options.gmail, deps); - } - else if('filesystem' in options) { - return new FSNotifier(options.filesystem); - } -} - -function Notifier(options, deps) { - this._notifier = notifier_factory(options, deps); -} - -Notifier.prototype.notify = function(identity, subject, link) { - return this._notifier.notify(identity, subject, link); -} - - diff --git a/src/lib/notifiers/FileSystemNotifier.ts b/src/lib/notifiers/FileSystemNotifier.ts new file mode 100644 index 00000000..10b62f8c --- /dev/null +++ b/src/lib/notifiers/FileSystemNotifier.ts @@ -0,0 +1,25 @@ + +import * as BluebirdPromise from "bluebird"; +import * as util from "util"; +import * as fs from "fs"; +import { INotifier } from "./INotifier"; +import { Identity } from "../Identity"; + +import { FileSystemNotifierConfiguration } from "../Configuration"; + +export class FileSystemNotifier extends INotifier { + private filename: string; + + constructor(options: FileSystemNotifierConfiguration) { + super(); + this.filename = options.filename; + } + + notify(identity: Identity, subject: string, link: string): BluebirdPromise { + const content = util.format("User: %s\nSubject: %s\nLink: %s", identity.userid, + subject, link); + const writeFilePromised = BluebirdPromise.promisify(fs.writeFile); + return writeFilePromised(this.filename, content); + } +} + diff --git a/src/lib/notifiers/GMailNotifier.ts b/src/lib/notifiers/GMailNotifier.ts new file mode 100644 index 00000000..030cd85d --- /dev/null +++ b/src/lib/notifiers/GMailNotifier.ts @@ -0,0 +1,44 @@ + +import * as Promise from "bluebird"; +import * as fs from "fs"; +import * as ejs from "ejs"; +import nodemailer = require("nodemailer"); + +import { NodemailerDependencies } from "../Dependencies"; +import { Identity } from "../Identity"; +import { INotifier } from "../notifiers/INotifier"; +import { GmailNotifierConfiguration } from "../Configuration"; + +const email_template = fs.readFileSync(__dirname + "/../../resources/email-template.ejs", "UTF-8"); + +export class GMailNotifier extends INotifier { + private transporter: any; + + constructor(options: GmailNotifierConfiguration, deps: NodemailerDependencies) { + super(); + const transporter = deps.createTransport({ + service: "gmail", + auth: { + user: options.username, + pass: options.password + } + }); + this.transporter = Promise.promisifyAll(transporter); + } + + notify(identity: Identity, subject: string, link: string): Promise { + const d = { + url: link, + button_title: "Continue", + title: subject + }; + + const mailOptions = { + from: "auth-server@open-intent.io", + to: identity.email, + subject: subject, + html: ejs.render(email_template, d) + }; + return this.transporter.sendMailAsync(mailOptions); + } +} diff --git a/src/lib/notifiers/INotifier.ts b/src/lib/notifiers/INotifier.ts new file mode 100644 index 00000000..84e94b3d --- /dev/null +++ b/src/lib/notifiers/INotifier.ts @@ -0,0 +1,7 @@ + +import * as BluebirdPromise from "bluebird"; +import { Identity } from "../Identity"; + +export abstract class INotifier { + abstract notify(identity: Identity, subject: string, link: string): BluebirdPromise; +} \ No newline at end of file diff --git a/src/lib/notifiers/NotifierFactory.ts b/src/lib/notifiers/NotifierFactory.ts new file mode 100644 index 00000000..fe166c72 --- /dev/null +++ b/src/lib/notifiers/NotifierFactory.ts @@ -0,0 +1,22 @@ + +import { NotifierConfiguration } from "..//Configuration"; +import { NotifierDependencies } from "../Dependencies"; +import { INotifier } from "./INotifier"; + +import { GMailNotifier } from "./GMailNotifier"; +import { FileSystemNotifier } from "./FileSystemNotifier"; + +export class NotifierFactory { + static build(options: NotifierConfiguration, deps: NotifierDependencies): INotifier { + if ("gmail" in options) { + return new GMailNotifier(options.gmail, deps.nodemailer); + } + else if ("filesystem" in options) { + return new FileSystemNotifier(options.filesystem); + } + } +} + + + + diff --git a/src/lib/notifiers/filesystem.js b/src/lib/notifiers/filesystem.js deleted file mode 100644 index a4a295ce..00000000 --- a/src/lib/notifiers/filesystem.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = FSNotifier; - -var Promise = require('bluebird'); -var fs = Promise.promisifyAll(require('fs')); -var util = require('util'); - -function FSNotifier(options) { - this._filename = options.filename; -} - -FSNotifier.prototype.notify = function(identity, subject, link) { - var content = util.format('User: %s\nSubject: %s\nLink: %s', identity.userid, - subject, link); - return fs.writeFileAsync(this._filename, content); -} - diff --git a/src/lib/notifiers/gmail.js b/src/lib/notifiers/gmail.js deleted file mode 100644 index 5007d858..00000000 --- a/src/lib/notifiers/gmail.js +++ /dev/null @@ -1,33 +0,0 @@ -module.exports = GmailNotifier; - -var Promise = require('bluebird'); -var fs = require('fs'); -var ejs = require('ejs'); - -var email_template = fs.readFileSync(__dirname + '/../../resources/email-template.ejs', 'UTF-8'); - -function GmailNotifier(options, deps) { - var transporter = deps.nodemailer.createTransport({ - service: 'gmail', - auth: { - user: options.username, - pass: options.password - } - }); - this.transporter = Promise.promisifyAll(transporter); -} - -GmailNotifier.prototype.notify = function(identity, subject, link) { - var d = {}; - d.url = link; - d.button_title = 'Continue'; - d.title = subject; - - var mailOptions = {}; - mailOptions.from = 'auth-server@open-intent.io'; - mailOptions.to = identity.email; - mailOptions.subject = subject; - mailOptions.html = ejs.render(email_template, d); - return this.transporter.sendMailAsync(mailOptions); -} - diff --git a/test/unitary/Server.test.ts b/test/unitary/Server.test.ts index cd9d0630..bc930f3b 100644 --- a/test/unitary/Server.test.ts +++ b/test/unitary/Server.test.ts @@ -44,8 +44,8 @@ describe("test the server", function () { store_in_memory: true, notifier: { gmail: { - user: "user@example.com", - pass: "password" + username: "user@example.com", + password: "password" } } }; diff --git a/test/unitary/config_adapter.test.ts b/test/unitary/config_adapter.test.ts index 6f55ac2b..0c8a651e 100644 --- a/test/unitary/config_adapter.test.ts +++ b/test/unitary/config_adapter.test.ts @@ -1,7 +1,6 @@ import * as Assert from "assert"; import { UserConfiguration } from "../../src/lib/Configuration"; -import config_adapter = require("../../src/lib/config_adapter"); - +import ConfigurationAdapter from "../../src/lib/ConfigurationAdapter"; describe("test config adapter", function() { function build_yaml_config(): UserConfiguration { @@ -22,8 +21,8 @@ describe("test config adapter", function() { logs_level: "debug", notifier: { gmail: { - user: "user", - pass: "password" + username: "user", + password: "password" } } }; @@ -33,14 +32,14 @@ describe("test config adapter", function() { it("should read the port from the yaml file", function() { const yaml_config = build_yaml_config(); yaml_config.port = 7070; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.equal(config.port, 7070); }); it("should default the port to 8080 if not provided", function() { const yaml_config = build_yaml_config(); delete yaml_config.port; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.equal(config.port, 8080); }); @@ -55,7 +54,7 @@ describe("test config adapter", function() { password: "pass" }; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.equal(config.ldap.url, "http://ldap"); Assert.equal(config.ldap.additional_user_dn, "ou=users"); @@ -71,7 +70,7 @@ describe("test config adapter", function() { secret: "secret", expiration: 3600 }; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.equal(config.session.domain, "example.com"); Assert.equal(config.session.secret, "secret"); Assert.equal(config.session.expiration, 3600); @@ -80,7 +79,7 @@ describe("test config adapter", function() { it("should get the log level", function() { const yaml_config = build_yaml_config(); yaml_config.logs_level = "debug"; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.equal(config.logs_level, "debug"); }); @@ -88,15 +87,15 @@ describe("test config adapter", function() { const yaml_config = build_yaml_config(); yaml_config.notifier = { gmail: { - user: "user", - pass: "pass" + username: "user", + password: "pass" } }; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.deepEqual(config.notifier, { gmail: { - user: "user", - pass: "pass" + username: "user", + password: "pass" } }); }); @@ -108,7 +107,7 @@ describe("test config adapter", function() { users: {}, groups: {} }; - const config = config_adapter(yaml_config); + const config = ConfigurationAdapter.adapt(yaml_config); Assert.deepEqual(config.access_control, { default: [], users: {}, diff --git a/test/unitary/data_persistence.test.ts b/test/unitary/data_persistence.test.ts index 4f2154f5..494bb0a7 100644 --- a/test/unitary/data_persistence.test.ts +++ b/test/unitary/data_persistence.test.ts @@ -4,7 +4,7 @@ import * as request from "request"; import Server from "../../src/lib/Server"; import { UserConfiguration } from "../../src/lib/Configuration"; -import { GlobalDependencies } from "../../src/lib/GlobalDependencies"; +import { GlobalDependencies } from "../../src/lib/Dependencies"; import * as tmp from "tmp"; @@ -77,8 +77,8 @@ describe("test data persistence", function () { store_directory: tmpDir.name, notifier: { gmail: { - user: "user@example.com", - pass: "password" + username: "user@example.com", + password: "password" } } }; diff --git a/test/unitary/mocks/nodemailer.ts b/test/unitary/mocks/nodemailer.ts new file mode 100644 index 00000000..1e42d13e --- /dev/null +++ b/test/unitary/mocks/nodemailer.ts @@ -0,0 +1,7 @@ + +import sinon = require("sinon"); +import { Nodemailer } from "../../../src/lib/Dependencies"; + +export = { + createTransport: sinon.stub() +}; diff --git a/test/unitary/notifiers/FileSystemNotifier.test.ts b/test/unitary/notifiers/FileSystemNotifier.test.ts new file mode 100644 index 00000000..b5197157 --- /dev/null +++ b/test/unitary/notifiers/FileSystemNotifier.test.ts @@ -0,0 +1,42 @@ + +import * as sinon from "sinon"; +import * as assert from "assert"; +import { FileSystemNotifier } from "../../../src/lib/notifiers/FileSystemNotifier"; +import * as tmp from "tmp"; +import * as fs from "fs"; + +const NOTIFICATIONS_DIRECTORY = "notifications"; + +describe("test FS notifier", function() { + let tmpDir: tmp.SynchrounousResult; + before(function() { + tmpDir = tmp.dirSync({ unsafeCleanup: true }); + }); + + after(function() { + tmpDir.removeCallback(); + }); + + it("should write the notification in a file", function() { + const options = { + filename: tmpDir.name + "/" + NOTIFICATIONS_DIRECTORY + }; + + const sender = new FileSystemNotifier(options); + const subject = "subject"; + + const identity = { + userid: "user", + email: "user@example.com" + }; + + const url = "http://test.com"; + + return sender.notify(identity, subject, url) + .then(function() { + const content = fs.readFileSync(options.filename, "UTF-8"); + assert(content.length > 0); + return Promise.resolve(); + }); + }); +}); diff --git a/test/unitary/notifiers/GMailNotifier.test.ts b/test/unitary/notifiers/GMailNotifier.test.ts new file mode 100644 index 00000000..3e6f6ce4 --- /dev/null +++ b/test/unitary/notifiers/GMailNotifier.test.ts @@ -0,0 +1,39 @@ +import * as sinon from "sinon"; +import * as assert from "assert"; + +import nodemailerMock = require("../mocks/nodemailer"); +import GMailNotifier = require("../../../src/lib/notifiers/GMailNotifier"); + + +describe("test gmail notifier", function () { + it("should send an email", function () { + const transporter = { + sendMail: sinon.stub().yields() + }; + nodemailerMock.createTransport.returns(transporter); + + const options = { + username: "user_gmail", + password: "pass_gmail" + }; + + const sender = new GMailNotifier.GMailNotifier(options, nodemailerMock); + const subject = "subject"; + + const identity = { + userid: "user", + email: "user@example.com" + }; + + const url = "http://test.com"; + + return sender.notify(identity, subject, url) + .then(function () { + assert.equal(nodemailerMock.createTransport.getCall(0).args[0].auth.user, "user_gmail"); + assert.equal(nodemailerMock.createTransport.getCall(0).args[0].auth.pass, "pass_gmail"); + assert.equal(transporter.sendMail.getCall(0).args[0].to, "user@example.com"); + assert.equal(transporter.sendMail.getCall(0).args[0].subject, "subject"); + return Promise.resolve(); + }); + }); +}); diff --git a/test/unitary/notifiers/NotifierFactory.test.ts b/test/unitary/notifiers/NotifierFactory.test.ts new file mode 100644 index 00000000..25600b0c --- /dev/null +++ b/test/unitary/notifiers/NotifierFactory.test.ts @@ -0,0 +1,39 @@ + +import * as sinon from "sinon"; +import * as BluebirdPromise from "bluebird"; +import * as assert from "assert"; + +import NodemailerMock = require("../mocks/nodemailer"); + +import { NotifierFactory } from "../../../src/lib/notifiers/NotifierFactory"; +import { GMailNotifier } from "../../../src/lib/notifiers/GMailNotifier"; +import { FileSystemNotifier } from "../../../src/lib/notifiers/FileSystemNotifier"; + +import { NotifierDependencies } from "../../../src/lib/Dependencies"; + + +describe("test notifier", function() { + const deps: NotifierDependencies = { + nodemailer: NodemailerMock + }; + + it("should build a Gmail Notifier", function() { + const options = { + gmail: { + username: "abc", + password: "password" + } + }; + assert(NotifierFactory.build(options, deps) instanceof GMailNotifier); + }); + + it("should build a FS Notifier", function() { + const options = { + filesystem: { + filename: "abc" + } + }; + + assert(NotifierFactory.build(options, deps) instanceof FileSystemNotifier); + }); +}); diff --git a/test/unitary/notifiers/test_fs.js b/test/unitary/notifiers/test_fs.js deleted file mode 100644 index 60b16b8e..00000000 --- a/test/unitary/notifiers/test_fs.js +++ /dev/null @@ -1,37 +0,0 @@ -var sinon = require('sinon'); -var assert = require('assert'); -var FSNotifier = require('../../../src/lib/notifiers/filesystem'); -var tmp = require('tmp'); -var fs = require('fs'); - -describe('test FS notifier', function() { - var tmpDir; - before(function() { - tmpDir = tmp.dirSync({ unsafeCleanup: true }); - }); - - after(function() { - tmpDir.removeCallback(); - }); - - it('should write the notification in a file', function() { - var options = {}; - options.filename = tmpDir.name + '/notification'; - - var sender = new FSNotifier(options); - var subject = 'subject'; - - var identity = {}; - identity.userid = 'user'; - identity.email = 'user@example.com'; - - var url = 'http://test.com'; - - return sender.notify(identity, subject, url) - .then(function() { - var content = fs.readFileSync(options.filename, 'UTF-8'); - assert(content.length > 0); - return Promise.resolve(); - }); - }); -}); diff --git a/test/unitary/notifiers/test_gmail.js b/test/unitary/notifiers/test_gmail.js deleted file mode 100644 index bc65967a..00000000 --- a/test/unitary/notifiers/test_gmail.js +++ /dev/null @@ -1,36 +0,0 @@ -var sinon = require('sinon'); -var assert = require('assert'); -var GmailNotifier = require('../../../src/lib/notifiers/gmail'); - -describe('test gmail notifier', function() { - it('should send an email', function() { - var nodemailer = {}; - var transporter = {}; - nodemailer.createTransport = sinon.stub().returns(transporter); - transporter.sendMail = sinon.stub().yields(); - var options = {}; - options.username = 'user_gmail'; - options.password = 'pass_gmail'; - - var deps = {}; - deps.nodemailer = nodemailer; - - var sender = new GmailNotifier(options, deps); - var subject = 'subject'; - - var identity = {}; - identity.userid = 'user'; - identity.email = 'user@example.com'; - - var url = 'http://test.com'; - - return sender.notify(identity, subject, url) - .then(function() { - assert.equal(nodemailer.createTransport.getCall(0).args[0].auth.user, 'user_gmail'); - assert.equal(nodemailer.createTransport.getCall(0).args[0].auth.pass, 'pass_gmail'); - assert.equal(transporter.sendMail.getCall(0).args[0].to, 'user@example.com'); - assert.equal(transporter.sendMail.getCall(0).args[0].subject, 'subject'); - return Promise.resolve(); - }); - }); -}); diff --git a/test/unitary/notifiers/test_notifier.js b/test/unitary/notifiers/test_notifier.js deleted file mode 100644 index efa4413d..00000000 --- a/test/unitary/notifiers/test_notifier.js +++ /dev/null @@ -1,35 +0,0 @@ - -var sinon = require('sinon'); -var Promise = require('bluebird'); -var assert = require('assert'); - -var Notifier = require('../../../src/lib/notifier'); -var GmailNotifier = require('../../../src/lib/notifiers/gmail'); -var FSNotifier = require('../../../src/lib/notifiers/filesystem'); - -describe('test notifier', function() { - it('should build a Gmail Notifier', function() { - var deps = {}; - deps.nodemailer = {}; - deps.nodemailer.createTransport = sinon.stub().returns({}); - - var options = {}; - options.gmail = {}; - options.gmail.user = 'abc'; - options.gmail.pass = 'abcd'; - - var notifier = new Notifier(options, deps); - assert(notifier._notifier instanceof GmailNotifier); - }); - - it('should build a FS Notifier', function() { - var deps = {}; - - var options = {}; - options.filesystem = {}; - options.filesystem.filename = 'abc'; - - var notifier = new Notifier(options, deps); - assert(notifier._notifier instanceof FSNotifier); - }); -}); diff --git a/test/unitary/server_config.test.ts b/test/unitary/server_config.test.ts index 6e4bf17f..c03072ce 100644 --- a/test/unitary/server_config.test.ts +++ b/test/unitary/server_config.test.ts @@ -8,7 +8,7 @@ import * as speakeasy from "speakeasy"; import * as u2f from "authdog"; import { AppConfiguration, UserConfiguration } from "../../src/lib/Configuration"; -import { GlobalDependencies } from "../../src/lib/GlobalDependencies"; +import { GlobalDependencies, Nodemailer } from "../../src/lib/Dependencies"; import Server from "../../src/lib/Server"; @@ -20,18 +20,18 @@ describe("test server configuration", function () { sendMail: sinon.stub().yields() }; - const nodemailer = { + const nodemailer: Nodemailer = { createTransport: sinon.spy(function () { return transporter; }) }; deps = { + nodemailer: nodemailer, speakeasy: speakeasy, u2f: u2f, nedb: nedb, winston: winston, - nodemailer: nodemailer, ldapjs: { createClient: sinon.spy(function () { return { on: sinon.spy() }; @@ -57,8 +57,8 @@ describe("test server configuration", function () { }, notifier: { gmail: { - user: "user@example.com", - pass: "password" + username: "user@example.com", + password: "password" } } } as UserConfiguration; diff --git a/test/unitary/test_server_config.ts b/test/unitary/test_server_config.ts new file mode 100644 index 00000000..2bc02178 --- /dev/null +++ b/test/unitary/test_server_config.ts @@ -0,0 +1,69 @@ + +import Server from "../../src/lib/Server"; + +import { UserConfiguration } from "../../src/lib/Configuration"; +import { GlobalDependencies } from "../../src/lib/Dependencies"; +import * as express from "express"; + +const sinon = require("sinon"); +const assert = require("assert"); + +describe("test server configuration", function () { + let deps: GlobalDependencies; + + before(function () { + const transporter = { + sendMail: sinon.stub().yields() + }; + + const nodemailer = { + createTransport: sinon.spy(function () { + return transporter; + }) + }; + + deps = { + nodemailer: nodemailer, + speakeasy: sinon.spy(), + u2f: sinon.spy(), + nedb: require("nedb"), + winston: sinon.spy(), + ldapjs: { + createClient: sinon.spy(function () { + return { on: sinon.spy() }; + }) + }, + session: sinon.spy(function () { + return function (req: express.Request, res: express.Response, next: express.NextFunction) { next(); }; + }) + }; + }); + + + it("should set cookie scope to domain set in the config", function () { + const config = { + notifier: { + gmail: { + username: "user@example.com", + password: "password" + } + }, + session: { + domain: "example.com", + secret: "secret" + }, + ldap: { + url: "http://ldap", + base_dn: "cn=test,dc=example,dc=com", + user: "user", + password: "password" + } + }; + + const server = new Server(); + server.start(config, deps); + + assert(deps.session.calledOnce); + assert.equal(deps.session.getCall(0).args[0].cookie.domain, "example.com"); + }); +});