From 257c93a6c996c8c9c12255d9744787f338761c48 Mon Sep 17 00:00:00 2001 From: Marcelo Pereira Date: Sun, 26 Jan 2020 10:12:17 +0000 Subject: [PATCH] feat(base): add Configuration and Logger services --- .gitignore | 1 + .version | 1 + docs/{empty => .nojekyll} | 0 docs/CONFIGURATION.md | 51 ++ docs/_config.yml | 1 + docs/_home.md | 5 + docs/_sidebar.md | 2 + docs/index.html | 25 + package-lock.json | 600 +++++++++++++++++- package.json | 21 +- source/common/BaseError.ts | 28 + source/common/Constants.ts | 16 + source/common/Utilities.ts | 7 + source/common/Validator.ts | 27 + source/main.ts | 16 +- .../ConfigurationService.ts | 47 ++ .../ConfigurationServiceImpl.ts | 144 +++++ .../error/ConfigurationError.ts | 25 + source/services/ConfigurationService/index.ts | 3 + .../services/LoggerService/LoggerService.ts | 18 + source/services/LoggerService/index.ts | 3 + source/services/index.ts | 4 + tests/ConfigurationService.spec.ts | 254 ++++++++ 23 files changed, 1276 insertions(+), 23 deletions(-) create mode 100644 .version rename docs/{empty => .nojekyll} (100%) create mode 100644 docs/CONFIGURATION.md create mode 100644 docs/_config.yml create mode 100644 docs/_home.md create mode 100644 docs/_sidebar.md create mode 100644 docs/index.html create mode 100644 source/common/BaseError.ts create mode 100644 source/common/Constants.ts create mode 100644 source/common/Utilities.ts create mode 100644 source/common/Validator.ts create mode 100644 source/services/ConfigurationService/ConfigurationService.ts create mode 100644 source/services/ConfigurationService/ConfigurationServiceImpl.ts create mode 100644 source/services/ConfigurationService/error/ConfigurationError.ts create mode 100644 source/services/ConfigurationService/index.ts create mode 100644 source/services/LoggerService/LoggerService.ts create mode 100644 source/services/LoggerService/index.ts create mode 100644 source/services/index.ts create mode 100644 tests/ConfigurationService.spec.ts diff --git a/.gitignore b/.gitignore index 63bc28e..02cbab9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ ## untracked folders build +config dist node_modules diff --git a/.version b/.version new file mode 100644 index 0000000..1116d40 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +0.0.0-development \ No newline at end of file diff --git a/docs/empty b/docs/.nojekyll similarity index 100% rename from docs/empty rename to docs/.nojekyll diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 0000000..2673332 --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,51 @@ +# Configuration + +The `cxsast_custom_reporting` application relies on two types of configurations: `global configuration` and `run-time configuration`. + +While `global configuration` defines how appllication will communicate with other software (e.g CxSAST, SMTP, etc.) `run-time configuration` defines the behavior and actions that will be executed. + +This document describes in details both configurations over the next topics. + +## Global configuration + +Global configuration is defined on the `\config\config.ini`. +The file is divided in sections where each section is have definitions of key-value pairs as the example bellow: + +```ini +[sast] +url=http://localenv.net +username=cxsastuser@enterprise.net +password=cxsastuser_password + +[smtp] +host=smtp.enterprise.net +port=465 +username=smtpuser@enterprise.net +password=smtpuser_password +``` + +Currently global configuration file supports the following information: + +| Key | type | M/O | Description | +| ---------- | ---------- | --- | ---------------------------------------------------------------------- | +| `[sast]` | | _M_ | defines the section relatd with CxSAST configuration | +| `url` | _`string`_ | _M_ | the url that application will use to communicate with CxSAST Manager | +| `username` | _`string`_ | _M_ | the user that will be used to communicate with CxSAST Manager | +| `password` | _`string`_ | _M_ | the user password that will be used to communicate with CxSAST Manager | +| `[smtp]` | | _M_ | defines the section related with SMTP configuration | +| `host` | _`string`_ | _M_ | the smtp host that will be used by application | +| `port` | _`number`_ | _M_ | the smtp port that will be used by application | +| `username` | _`string`_ | _M_ | the smtp user that will be used by application | +| `password` | _`string`_ | _M_ | the smtp user password that will be used by application | + +## Run-Time configuration + +Run-time configuration items are defined as parametes during execution and allows end users the required flexibility to execute the application in different scnearios. + +Currently run-time configuration support the following parameters: + +| Key | type | M/O | Description | +| ---------------- | ---------- | --- | ------------------------------------------- | +| `reportType` | _`string`_ | _M_ | The type of report that should be generated | +| `reportTemplate` | _`string`_ | _M_ | The HTML template that should be generated | +| `reportAudience` | _`string`_ | _M_ | a comma separated list of email receivers | diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..2f7efbe --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-minimal \ No newline at end of file diff --git a/docs/_home.md b/docs/_home.md new file mode 100644 index 0000000..f4c14e9 --- /dev/null +++ b/docs/_home.md @@ -0,0 +1,5 @@ +# CxSAST Custom Reporting + +``` +Add initial page content +``` diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..f15e465 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,2 @@ +- [Home](/) +- [Configuration](CONFIGURATION.md) diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..254f8db --- /dev/null +++ b/docs/index.html @@ -0,0 +1,25 @@ + + + + + CxSAST Custom Reporting + + + + + + +
+ + + + diff --git a/package-lock.json b/package-lock.json index 22ca915..853c272 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1771,6 +1771,15 @@ "is-obj": "^1.0.0" } }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -1807,6 +1816,12 @@ "url-parse-lax": "^1.0.0" } }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, "is-ci": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", @@ -2062,6 +2077,20 @@ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, + "@types/flat": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@types/flat/-/flat-0.0.28.tgz", + "integrity": "sha1-XHiBSdhabPj/X18ACs3ZEs3qQnQ=", + "dev": true + }, + "@types/fs-extra": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==", + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -2122,8 +2151,7 @@ "@types/node": { "version": "13.1.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.2.tgz", - "integrity": "sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ==", - "dev": true + "integrity": "sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -2137,6 +2165,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/properties-reader": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@types/properties-reader/-/properties-reader-0.0.1.tgz", + "integrity": "sha512-uhOYv4GJo1GjinM1U9AztqoqBkPTJ5E82gC/7yR6LJCyu2JnX8/8wyiDwAFoDJhjvPRtczkrvHorv74+P7xgOg==", + "dev": true + }, "@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -2149,6 +2183,21 @@ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, + "@types/uuid": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.6.tgz", + "integrity": "sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/validator": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-12.0.1.tgz", + "integrity": "sha512-l57fIANZLMe8DArz+SDb+7ATXnDm15P7u2wHBw5mb0aSMd+UuvmvhouBF2hdLgQPDMJ39sh9g2MJO4GkZ0VAdQ==", + "dev": true + }, "@types/yargs": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.5.tgz", @@ -2368,6 +2417,12 @@ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", @@ -2998,6 +3053,15 @@ "regenerator-runtime": "^0.11.0" } }, + "backbone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz", + "integrity": "sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ==", + "dev": true, + "requires": { + "underscore": ">=1.8.3" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -4472,6 +4536,11 @@ } } }, + "date-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", + "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==" + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -4488,7 +4557,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -6018,12 +6086,12 @@ } }, "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.0.tgz", + "integrity": "sha512-6KSMM+cHHzXC/hpldXApL2S8Uz+QZv+tq5o/L0KQYleoG+GcwrnIJhTWC7tCOiKQp8D/fIvryINU1OZCCwevjA==", "dev": true, "requires": { - "is-buffer": "~2.0.3" + "is-buffer": "~2.0.4" }, "dependencies": { "is-buffer": { @@ -6034,6 +6102,11 @@ } } }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -6222,7 +6295,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -7071,8 +7143,7 @@ "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "graceful-readlink": { "version": "1.0.1", @@ -7280,6 +7351,12 @@ "minimalistic-assert": "^1.0.1" } }, + "highlight.js": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.0.tgz", + "integrity": "sha512-A97kI1KAUzKoAiEoaGcf2O9YPS8nbDTCRFokaaeBhnqjQTvbAuAJrQMm21zw8s8xzaMtCQBtgbyGXLGxdxQyqQ==", + "dev": true + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -7549,6 +7626,12 @@ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", "dev": true }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -8998,6 +9081,12 @@ "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", "dev": true }, + "jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==", + "dev": true + }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -9172,7 +9261,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -9557,6 +9645,18 @@ "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", "dev": true }, + "log4js": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.1.0.tgz", + "integrity": "sha512-fSCHMYsMJbHwfNTuMlopVVcfkKwIRLh5mpNZGB2oBbnSmr3yUTo4tL4xGBA0/q29xowlu96eTXGghJFNhPXMnA==", + "requires": { + "date-format": "^3.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.1", + "rfdc": "^1.1.4", + "streamroller": "^2.2.3" + } + }, "longest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", @@ -9612,6 +9712,12 @@ "integrity": "sha1-mgD3bco26yP6BTUK/htYXUKZ5ks=", "dev": true }, + "lunr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", + "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==", + "dev": true + }, "luxon": { "version": "1.21.3", "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.21.3.tgz", @@ -9873,8 +9979,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minimist-options": { "version": "3.0.2", @@ -9941,7 +10046,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -9975,8 +10079,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "msgpack-lite": { "version": "0.1.26", @@ -10235,12 +10338,333 @@ } } }, + "nodemon": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz", + "integrity": "sha512-GWhYPMfde2+M0FsHnggIHXTqPDHXia32HRhh6H0d75Mt9FKUoCBvumNHr7LdrpPBTKxsWmIEOjoN+P4IU6Hcaw==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.5.0" + }, + "dependencies": { + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + } + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + } + } + }, "nofilter": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.3.tgz", "integrity": "sha512-FlUlqwRK6reQCaFLAhMcF+6VkVG2caYjKQY3YsRDTl4/SEch595Qb3oLjJRDr8dkHAAOVj2pOx3VknfnSgkE5g==", "dev": true }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -14684,6 +15108,14 @@ "sisteransi": "^1.0.3" } }, + "properties-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/properties-reader/-/properties-reader-1.0.0.tgz", + "integrity": "sha512-bTjPVya6wFErwwOP3CasaRoyZ7n6sAt/MMJnDxBp3As7h2J19vmjCZX+Iw7YV0TqBPcA8i/Df/rxiCNutzEXZQ==", + "requires": { + "mkdirp": "~0.5.1" + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -14708,6 +15140,12 @@ "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", "dev": true }, + "pstree.remy": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", + "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "dev": true + }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -15224,6 +15662,11 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" + }, "right-pad": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", @@ -17053,6 +17496,23 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "streamroller": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.3.tgz", + "integrity": "sha512-AegmvQsscTRhHVO46PhCDerjIpxi7E+d2GxgUDu+nzw/HuLnUdxHWr6WQ+mVn/4iJgMKKFFdiUwFcFRDvcjCtw==", + "requires": { + "date-format": "^2.1.0", + "debug": "^4.1.1", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==" + } + } + }, "string-length": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", @@ -17708,6 +18168,15 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -17991,6 +18460,62 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typedoc": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.16.7.tgz", + "integrity": "sha512-sNrLlaZ/aZHxA2rCURGf3g5YabGVwrujiwC6SCV/rgx3LFfZh+goUCatAAyTEDk7evuu6pJ0APGDSde1mSYegw==", + "dev": true, + "requires": { + "@types/minimatch": "3.0.3", + "fs-extra": "^8.1.0", + "handlebars": "^4.7.2", + "highlight.js": "^9.17.1", + "lodash": "^4.17.15", + "marked": "^0.8.0", + "minimatch": "^3.0.0", + "progress": "^2.0.3", + "shelljs": "^0.8.3", + "typedoc-default-themes": "^0.7.2", + "typescript": "3.7.x" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "marked": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz", + "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==", + "dev": true + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + } + } + }, + "typedoc-default-themes": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.7.2.tgz", + "integrity": "sha512-fiFKlFO6VTqjcno8w6WpTsbCgXmfPHVjnLfYkmByZE7moaz+E2DSpAT+oHtDHv7E0BM5kAhPrHJELP2J2Y2T9A==", + "dev": true, + "requires": { + "backbone": "^1.4.0", + "jquery": "^3.4.1", + "lunr": "^2.3.8", + "underscore": "^1.9.1" + } + }, "typescript": { "version": "3.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", @@ -18033,6 +18558,38 @@ "through": "^2.3.8" } }, + "undefsafe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", + "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "dev": true, + "requires": { + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "underscore": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", + "integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==", + "dev": true + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -18095,8 +18652,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unpipe": { "version": "1.0.0", @@ -18298,8 +18854,7 @@ "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v8flags": { "version": "3.1.3", @@ -18320,6 +18875,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "validator": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-12.1.0.tgz", + "integrity": "sha512-gIC2RBuFRi574Rb9vewGCJ7TCLxHXNx6EKthEgs+Iz0pYa9a9Te1VLG/bGLsAyGWrqR5FfR7tbFUI7FEF2LiGA==" + }, "velocityjs": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/velocityjs/-/velocityjs-1.1.5.tgz", diff --git a/package.json b/package.json index 078b1dd..ddaa3b0 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,18 @@ "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }, - "scripts": {}, - "dependencies": {}, + "scripts": { + "dev": "nodemon --watch source --exec ts-node source/main.ts", + "docs": "docsify serve ./docs" + }, + "dependencies": { + "@types/fs-extra": "8.0.1", + "fs-extra": "8.1.0", + "log4js": "6.1.0", + "properties-reader": "1.0.0", + "uuid": "3.4.0", + "validator": "12.1.0" + }, "devDependencies": { "@commitlint/cli": "8.2.0", "@commitlint/config-conventional": "8.2.0", @@ -39,15 +49,21 @@ "@semantic-release/npm": "6.0.0-beta.9", "@semantic-release/release-notes-generator": "7.3.5", "@types/aws-lambda": "8.10.39", + "@types/flat": "0.0.28", "@types/jest": "24.0.25", "@types/node": "13.1.2", + "@types/properties-reader": "0.0.1", + "@types/uuid": "3.4.6", + "@types/validator": "12.0.1", "commitizen": "4.0.3", "conventional-changelog-conventionalcommits": "4.2.3", "cz-conventional-changelog": "3.0.2", "docsify-cli": "4.4.0", + "flat": "5.0.0", "fork-ts-checker-webpack-plugin": "3.1.1", "husky": "3.1.0", "jest": "24.9.0", + "nodemon": "2.0.2", "pkg": "4.4.2", "semantic-release": "16.0.0-beta.46", "serverless": "1.60.4", @@ -58,6 +74,7 @@ "ts-node": "8.5.4", "tslint": "5.20.1", "tslint-config-prettier": "1.18.0", + "typedoc": "0.16.7", "typescript": "3.7.4", "webpack": "4.41.5", "webpack-node-externals": "1.7.2" diff --git a/source/common/BaseError.ts b/source/common/BaseError.ts new file mode 100644 index 0000000..c8fa77c --- /dev/null +++ b/source/common/BaseError.ts @@ -0,0 +1,28 @@ +import { format } from 'util'; + +/** + * a definition of an error template + */ +export interface IErrorTemplate { + code: string; + message: string; +} + +/** + * implements a base structure for errors + */ +export default class BaseError extends Error { + public code: string; + + constructor(errorTemplate: IErrorTemplate, ...args: any) { + args.unshift(errorTemplate.code); + args.unshift(`%s: ${errorTemplate.message}`); + + super(format.apply(format, args)); + + this.code = errorTemplate.code; + this.name = this.constructor.name; + + Error.captureStackTrace(this, this.constructor); + } +} diff --git a/source/common/Constants.ts b/source/common/Constants.ts new file mode 100644 index 0000000..e12a2cb --- /dev/null +++ b/source/common/Constants.ts @@ -0,0 +1,16 @@ +import { join as joinPath } from 'path'; + +export const FILE_VERSION = `${joinPath(process.cwd(), '.version')}`; + +export const CONFIG_FILE = `${joinPath(process.cwd(), 'config/config.ini')}`; +export const CONFIG_ARGS_REPORT_TYPE = 'reportType'; +export const CONFIG_ARGS_REPORT_TEMPLATE = 'reportTemplate'; +export const CONFIG_ARGS_REPORT_AUDIENCE = 'reportAudience'; +export const CONFIG_FILE_KEY_SAST_URL = 'sast.url'; +export const CONFIG_FILE_KEY_SAST_USERNAME = 'sast.username'; +export const CONFIG_FILE_KEY_SAST_PASSWORD = 'sast.password'; +export const CONFIG_FILE_KEY_SMTP_HOST = 'smtp.host'; +export const CONFIG_FILE_KEY_SMTP_PORT = 'smtp.port'; +export const CONFIG_FILE_KEY_SMTP_USERNAME = 'smtp.username'; +export const CONFIG_FILE_KEY_SMTP_PASSWORD = 'smtp.password'; +export const CONFIG_FILE_KEY_SMTP_SENDER = 'smtp.sender'; diff --git a/source/common/Utilities.ts b/source/common/Utilities.ts new file mode 100644 index 0000000..1d538b8 --- /dev/null +++ b/source/common/Utilities.ts @@ -0,0 +1,7 @@ +import { readFileSync } from 'fs-extra'; + +export function readFile(path: string) { + const val = readFileSync(path, { encoding: 'UTF8' }); + + return val; +} diff --git a/source/common/Validator.ts b/source/common/Validator.ts new file mode 100644 index 0000000..e0fd2bf --- /dev/null +++ b/source/common/Validator.ts @@ -0,0 +1,27 @@ +import validator from 'validator'; + +export function isUrl(val: string): boolean { + return validator.isURL(val, { + protocols: ['http', 'https'], + require_tld: true, + require_protocol: false, + require_host: true, + require_valid_protocol: true, + allow_underscores: false, + allow_trailing_dot: false, + allow_protocol_relative_urls: false, + disallow_auth: true, + }); +} + +export function isFqdn(val: string): boolean { + return validator.isFQDN(val, { + require_tld: true, + allow_underscores: false, + allow_trailing_dot: false, + }); +} + +export function isIPV4(val: string): boolean { + return validator.isIP(val, '4'); +} diff --git a/source/main.ts b/source/main.ts index 4f3b676..6e9e247 100644 --- a/source/main.ts +++ b/source/main.ts @@ -1 +1,15 @@ -console.log('abc123'); +import { ConfigurationService, LoggerService } from './services'; + +const cnf = ConfigurationService.getConfig(); +const log = LoggerService.getLogger('main'); + +async function main() { + try { + log.info('initialized with %s', cnf.toString()); + } catch (e) { + log.fatal(e.message); + log.info('finished'); + } +} + +main(); diff --git a/source/services/ConfigurationService/ConfigurationService.ts b/source/services/ConfigurationService/ConfigurationService.ts new file mode 100644 index 0000000..e4acd54 --- /dev/null +++ b/source/services/ConfigurationService/ConfigurationService.ts @@ -0,0 +1,47 @@ +import ConfigurationServiceImpl from './ConfigurationServiceImpl'; + +/** + * defines how a logger service should be + */ +export interface IConfigurationService { + getConfig(): IConfigurationObject; +} + +export interface IConfigurationObject { + version: string; + report: { + type: string; + template: string; + audience: string; + }; + sast: { + url: string; + username: string; + password: string; + }; + smtp: { + host: string; + port: string; + username: string; + password: string; + sender: string; + }; + toString(): string; +} + +let instance: IConfigurationService; + +/** + * a singleton to retrieve the logger service + */ +export default class ConfigurationService { + /** + * retrieves the current instance of ConfigurationService + */ + public static getConfig(): IConfigurationObject { + if (!instance) { + instance = new ConfigurationServiceImpl(); + } + return instance.getConfig(); + } +} diff --git a/source/services/ConfigurationService/ConfigurationServiceImpl.ts b/source/services/ConfigurationService/ConfigurationServiceImpl.ts new file mode 100644 index 0000000..f06176b --- /dev/null +++ b/source/services/ConfigurationService/ConfigurationServiceImpl.ts @@ -0,0 +1,144 @@ +import PropertiesReader from 'properties-reader'; +import yargs from 'yargs'; +import { IConfigurationService, IConfigurationObject } from './ConfigurationService'; +import ConfigurationError from './error/ConfigurationError'; +import { isUrl, isFqdn, isIPV4 } from '../../common/Validator'; +import { readFile } from '../../common/Utilities'; + +import { + FILE_VERSION, + CONFIG_FILE, + CONFIG_FILE_KEY_SAST_URL, + CONFIG_FILE_KEY_SAST_USERNAME, + CONFIG_FILE_KEY_SAST_PASSWORD, + CONFIG_FILE_KEY_SMTP_HOST, + CONFIG_FILE_KEY_SMTP_PORT, + CONFIG_FILE_KEY_SMTP_USERNAME, + CONFIG_FILE_KEY_SMTP_PASSWORD, + CONFIG_FILE_KEY_SMTP_SENDER, +} from '../../common/Constants'; + +export default class ConfigurationServiceImpl implements IConfigurationService { + private props: any; + private args: any; + private config: IConfigurationObject; + + constructor() { + try { + this.props = PropertiesReader(CONFIG_FILE); + } catch (e) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_FILE, CONFIG_FILE); + } + + this.args = yargs.argv; + + console.log(this.args); + + const version = readFile(FILE_VERSION); + const reportType = this.args.reportType ? this.args.reportType : 'ScanSummary'; + const reportTemplate = this.args.reportTemplate ? this.args.reportTemplate : 'ScanSummaryTemplate'; + const reportAudience = this.args.reportAudience ? this.args.reportAudience : undefined; + const sastUrl: string = this.props.get(CONFIG_FILE_KEY_SAST_URL); + const sastUsername: string = this.props.get(CONFIG_FILE_KEY_SAST_USERNAME); + const sastPassword: string = this.props.get(CONFIG_FILE_KEY_SAST_PASSWORD); + const smtpHost: string = this.props.get(CONFIG_FILE_KEY_SMTP_HOST); + const smtpPort: string = this.props.get(CONFIG_FILE_KEY_SMTP_PORT); + const smtpUsername: string = this.props.get(CONFIG_FILE_KEY_SMTP_USERNAME); + const smtpPassword: string = this.props.get(CONFIG_FILE_KEY_SMTP_PASSWORD); + const smtpSender: string = this.props.get(CONFIG_FILE_KEY_SMTP_SENDER); + + // ################################################################### + // ### valiating SAST.URL configuratoin key + // ################################################################### + if (!sastUrl) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SAST_URL); + } + + if (!isUrl(sastUrl)) { + throw new ConfigurationError(ConfigurationError.INVALID_CONFIG_KEY, CONFIG_FILE_KEY_SAST_URL); + } + + // ################################################################### + // ### valiating SAST.USERNAME configuratoin key + // ################################################################### + if (!sastUsername) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SAST_USERNAME); + } + + // ################################################################### + // ### valiating SAST.PASSWORD configuratoin key + // ################################################################### + if (!sastPassword) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SAST_PASSWORD); + } + + // ################################################################### + // ### valiating SMTP.HOST configuratoin key + // ################################################################### + if (!smtpHost) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_HOST); + } + if (!isFqdn && !isIPV4) { + throw new ConfigurationError(ConfigurationError.INVALID_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_HOST); + } + + // ################################################################### + // ### valiating SMTP.PORT configuratoin key + // ################################################################### + if (!smtpPort) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_PORT); + } + + // ################################################################### + // ### valiating SMTP.USERNAME configuratoin key + // ################################################################### + if (!smtpUsername) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_USERNAME); + } + + // ################################################################### + // ### valiating SMTP.PASSWORD configuratoin key + // ################################################################### + if (!smtpPassword) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_PASSWORD); + } + + // ################################################################### + // ### valiating SMTP.SENDER configuratoin key + // ################################################################### + if (!smtpSender) { + throw new ConfigurationError(ConfigurationError.MISSING_CONFIG_KEY, CONFIG_FILE_KEY_SMTP_SENDER); + } + + this.config = { + version, + report: { + type: reportType, + template: reportTemplate, + audience: reportAudience, + }, + sast: { + url: sastUrl, + username: sastUsername, + password: sastPassword, + }, + smtp: { + host: smtpHost, + port: smtpPort, + username: smtpUsername, + password: smtpPassword, + sender: smtpSender, + }, + toString: () => + JSON.stringify({ + ...this.config, + sast: { ...this.config.sast, username: '******', password: '******' }, + smtp: { ...this.config.smtp, username: '******', password: '******' }, + }), + }; + } + + public getConfig(): IConfigurationObject { + return this.config; + } +} diff --git a/source/services/ConfigurationService/error/ConfigurationError.ts b/source/services/ConfigurationService/error/ConfigurationError.ts new file mode 100644 index 0000000..cd6cdf9 --- /dev/null +++ b/source/services/ConfigurationService/error/ConfigurationError.ts @@ -0,0 +1,25 @@ +import BaseError, { IErrorTemplate } from '../../../common/BaseError'; + +/** + * implements scturcted errors related to configuration problems + */ +export default class ConfigurationError extends BaseError { + public static MISSING_CONFIG_FILE: IErrorTemplate = { + code: 'CO_MISSING_CONFIG_FILE', + message: 'Missing configuration file. Could not access file on "%s"', + }; + + public static MISSING_CONFIG_KEY: IErrorTemplate = { + code: 'CO_MISSING_CONFIG_KEY', + message: 'Missing configuration key "%s"', + }; + + public static INVALID_CONFIG_KEY: IErrorTemplate = { + code: 'CO_INVALID_CONFIG_KEY', + message: 'Invalid configuration key "%s"', + }; + + constructor(template: IErrorTemplate, ...args: any) { + super(template, ...args); + } +} diff --git a/source/services/ConfigurationService/index.ts b/source/services/ConfigurationService/index.ts new file mode 100644 index 0000000..9524c37 --- /dev/null +++ b/source/services/ConfigurationService/index.ts @@ -0,0 +1,3 @@ +import ConfigurationService from './ConfigurationService'; + +export { ConfigurationService }; diff --git a/source/services/LoggerService/LoggerService.ts b/source/services/LoggerService/LoggerService.ts new file mode 100644 index 0000000..09c360c --- /dev/null +++ b/source/services/LoggerService/LoggerService.ts @@ -0,0 +1,18 @@ +import logger from 'log4js'; + +let configured: boolean; + +export default class LoggerService { + public static getLogger(name: string) { + if (!configured) { + logger.configure({ + appenders: { + console: { type: 'console', layout: { type: 'pattern', pattern: '%d %-6z %-5p %-16.16c %m' } }, + }, + categories: { default: { appenders: ['console'], level: 'debug' } }, + }); + configured = true; + } + return logger.getLogger(name); + } +} diff --git a/source/services/LoggerService/index.ts b/source/services/LoggerService/index.ts new file mode 100644 index 0000000..932b408 --- /dev/null +++ b/source/services/LoggerService/index.ts @@ -0,0 +1,3 @@ +import LoggerService from './LoggerService'; + +export { LoggerService }; diff --git a/source/services/index.ts b/source/services/index.ts new file mode 100644 index 0000000..54e0524 --- /dev/null +++ b/source/services/index.ts @@ -0,0 +1,4 @@ +import { ConfigurationService } from './ConfigurationService'; +import { LoggerService } from './LoggerService'; + +export { ConfigurationService, LoggerService }; diff --git a/tests/ConfigurationService.spec.ts b/tests/ConfigurationService.spec.ts new file mode 100644 index 0000000..33b91f1 --- /dev/null +++ b/tests/ConfigurationService.spec.ts @@ -0,0 +1,254 @@ +import PropertiesReader = require('properties-reader'); +import flatten = require('flat'); +import { ensureFileSync, removeSync } from 'fs-extra'; +// import { ConfigurationService } from '../source/services'; +import { CONFIG_FILE } from '../source/common/Constants'; + +const TEMPLATE = { + sast: { + url: 'http://127.0.0.1', + username: 'username', + password: 'password', + }, + smtp: { + host: '127.0.0.1', + port: '465', + username: 'username', + password: 'password', + sender: 'test@test.com', + }, +}; + +let ConfigurationService: any; + +async function createConfig(obj: any) { + ensureFileSync(CONFIG_FILE); + // @ts-ignore + const props = new PropertiesReader(CONFIG_FILE); + const flatenObj = flatten(obj, {}) as any; + + Object.keys(flatenObj).forEach(async key => { + if (flatenObj[key]) { + await props.set(key, flatenObj[key]); + } + }); + + await props.save(CONFIG_FILE); +} + +function removeConfig() { + removeSync(CONFIG_FILE); +} + +describe('ConfigurationService', () => { + describe('Global Configuration', () => { + beforeEach(() => { + jest.resetModules(); + ConfigurationService = require('../source/services/ConfigurationService/ConfigurationService').default; + }); + + afterEach(() => { + removeConfig(); + }); + + test('ensure same instance is retrieved', async done => { + await createConfig(TEMPLATE); + const cnf1 = ConfigurationService.getConfig(); + const cnf2 = ConfigurationService.getConfig(); + expect(cnf1).toEqual(cnf2); + done(); + }); + + test('ensure sensitive data is not printed then using toString()', async done => { + await createConfig(TEMPLATE); + const cnfString = ConfigurationService.getConfig().toString(); + const tmp = JSON.parse(cnfString); + expect(tmp.sast.username).toBe('******'); + expect(tmp.sast.password).toBe('******'); + expect(tmp.smtp.username).toBe('******'); + expect(tmp.smtp.password).toBe('******'); + done(); + }); + + test('throw CO_MISSING_CONFIG_FILE when configuration file is not accessible', async done => { + await createConfig(TEMPLATE); + removeConfig(); + try { + ConfigurationService.getConfig(); + done('expected to throw CO_MISSING_CONFIG_FILE'); + } catch (e) { + expect(e.code).toBe('CO_MISSING_CONFIG_FILE'); + expect(e.message).toBe(`CO_MISSING_CONFIG_FILE: Missing configuration file. Could not access file on "${CONFIG_FILE}"`); + done(); + } + }); + + const testCases: any[] = [ + { + key: 'sast.url', + name: 'is undefined', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "sast.url"', + }, + { + key: 'sast.url', + name: 'is invalid (sast.url=abc123)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'abc123' } }, + errCode: 'CO_INVALID_CONFIG_KEY', + errMsg: 'CO_INVALID_CONFIG_KEY: Invalid configuration key "sast.url"', + }, + { + key: 'sast.url', + name: 'is invalid (sast.url=ftp://test.com)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'ftp://test.com' } }, + errCode: 'CO_INVALID_CONFIG_KEY', + errMsg: 'CO_INVALID_CONFIG_KEY: Invalid configuration key "sast.url"', + }, + { + key: 'sast.url', + name: 'is invalid (sast.url=http://test)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'http://test' } }, + errCode: 'CO_INVALID_CONFIG_KEY', + errMsg: 'CO_INVALID_CONFIG_KEY: Invalid configuration key "sast.url"', + }, + { + key: 'sast.url', + name: 'is invalid (sast.url=sftp://test.com)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'sftp://test.com' } }, + errCode: 'CO_INVALID_CONFIG_KEY', + errMsg: 'CO_INVALID_CONFIG_KEY: Invalid configuration key "sast.url"', + }, + { + key: 'sast.url', + name: 'is invalid (sast.url=file://test.com)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'file://test.com' } }, + errCode: 'CO_INVALID_CONFIG_KEY', + errMsg: 'CO_INVALID_CONFIG_KEY: Invalid configuration key "sast.url"', + }, + { + key: 'sast.username', + name: 'is undefined', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, username: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "sast.username"', + }, + { + key: 'sast.password', + name: 'is undefined', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, password: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "sast.password"', + }, + // ################################################################ + // # scenarios for SMTP configuration + // ################################################################ + { + key: 'smtp.host', + name: 'is undefined', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, host: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "smtp.host"', + }, + { + key: 'smtp.port', + name: 'is undefined', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, port: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "smtp.port"', + }, + { + key: 'smtp.username', + name: 'is undefined', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, username: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "smtp.username"', + }, + { + key: 'smtp.password', + name: 'is undefined', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, password: undefined } }, + errCode: 'CO_MISSING_CONFIG_KEY', + errMsg: 'CO_MISSING_CONFIG_KEY: Missing configuration key "smtp.password"', + }, + + { + key: 'sast.url', + name: 'is valid (sast.url=http://test.com)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'http://test.com' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=http://test.com:10000)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'http://test.com:10000' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=http://127.0.0.1)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'http://127.0.0.1' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=http://127.0.0.1:10000)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'http://127.0.0.1:10000' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=https://test.com)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'https://test.com' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=https://test.com:10000)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'https://test.com:10000' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=https://127.0.0.1)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'https://127.0.0.1' } }, + }, + { + key: 'sast.url', + name: 'is valid (sast.url=https://127.0.0.1:10000)', + config: { ...TEMPLATE, sast: { ...TEMPLATE.sast, url: 'https://127.0.0.1:10000' } }, + }, + { + key: 'smtp.host', + name: 'is valid (smtp.host=local.net)', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, smtp: 'local.net' } }, + }, + { + key: 'smtp.host', + name: 'is valid (smtp.host=127.0.0.1)', + config: { ...TEMPLATE, smtp: { ...TEMPLATE.smtp, smtp: '127.0.0.1' } }, + }, + ]; + + testCases.forEach(testCase => { + if (!testCase.errCode) { + test(`${testCase.name}`, async done => { + await createConfig(testCase.config); + process.nextTick(() => { + const cnf = ConfigurationService.getConfig(); + const c1 = flatten(testCase.config) as any; + const c2 = flatten(cnf) as any; + expect(c2[testCase.key]).toBe(c1[testCase.key]); + done(); + }); + }); + } else { + test(`throw ${testCase.errCode} when ${testCase.key} ${testCase.name}`, async done => { + await createConfig(testCase.config); + try { + ConfigurationService.getConfig(); + done(`expected to throw ${testCase.errCode} when ${testCase.key} ${testCase.name}`); + } catch (e) { + expect(e.code).toBe(testCase.errCode); + expect(e.message).toBe(testCase.errMsg); + done(); + } + }); + } + }); + }); +});