diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 09a8422..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -!.eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index c31344c..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - extends: 'standard', - plugins: ['standard', 'promise'] -} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..048b1cf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [blueimp] diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..71ea8eb --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,25 @@ +name: Node CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm test + env: + CI: true diff --git a/.gitignore b/.gitignore index 9daa824..3c3629e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -.DS_Store node_modules diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7a56d2a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: node_js -node_js: - - "stable" diff --git a/LICENSE.txt b/LICENSE.txt index 6a88a0d..5f3636f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,20 +2,19 @@ MIT License Copyright © 2017 Sebastian Tschan, https://blueimp.net -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 9e69d90..6da69f3 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # AWS Lambda + A collection of functions for [AWS Lambda](https://aws.amazon.com/lambda/). ## Functions -* [Authorize the client IP for an EC2 security group](authorize-ip) -* [Return authorized keys for EC2 SSH access](ssh-authorized-keys) -* [Grant bucket owner full control over an S3 object](bucket-owner-full-control) -* [CloudWatch alarm notifications to Slack](cloudwatch-alarm-to-slack) -* [CloudWatch Events to BuildKite](cloudwatch-events-to-buildkite) -* [CloudWatch Logs to Elastic Cloud](cloudwatch-logs-to-elastic-cloud) -* [Elastic Beanstalk events to Slack](elastic-beanstalk-events-to-slack) -* [Subdomain or parent domain redirect](subdomain-redirect) -* [Security headers for CloudFront](cloudfront-security-headers) -* [Host header as X-Forwarded-Host for CloudFront](cloudfront-forwarded-host) + +- [Authorize the client IP for an EC2 security group](authorize-ip) +- [Return authorized keys for EC2 SSH access](ssh-authorized-keys) +- [Grant bucket owner full control over an S3 object](bucket-owner-full-control) +- [CloudWatch alarm notifications to Slack](cloudwatch-alarm-to-slack) +- [CloudWatch Events to BuildKite](cloudwatch-events-to-buildkite) +- [CloudWatch Logs to Elastic Cloud](cloudwatch-logs-to-elastic-cloud) +- [Elastic Beanstalk events to Slack](elastic-beanstalk-events-to-slack) +- [Subdomain or parent domain redirect](subdomain-redirect) +- [Security headers for CloudFront](cloudfront-security-headers) +- [Host header as X-Forwarded-Host for CloudFront](cloudfront-forwarded-host) ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/authorize-ip/README.md b/authorize-ip/README.md index e0730a0..5871ed0 100644 --- a/authorize-ip/README.md +++ b/authorize-ip/README.md @@ -1,11 +1,13 @@ # authorize-ip -[AWS Lambda](https://aws.amazon.com/lambda/) function to authorize the -client IP for an EC2 security group. + +[AWS Lambda](https://aws.amazon.com/lambda/) function to authorize the client IP +for an EC2 security group. Meant to be used with [Amazon API Gateway](https://aws.amazon.com/api-gateway/). ## Setup ### IAM role creation + Create a new [IAM](https://aws.amazon.com/iam/) role with the name `aws-lambda-authorize-ip-role`. Select the AWS Lambda role type and attach the managed policy `AWSLambdaBasicExecutionRole`. @@ -33,40 +35,43 @@ Attach an additional inline policy with the following content, replacing } ``` -**Notice:** +**Notice:** + > The `ec2:DescribeSecurityGroups` action currently does not support > [resource-level permissions](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html); -> therefore, the `*` wildcard is used for the Resource element in the -> statement. +> therefore, the `*` wildcard is used for the Resource element in the statement. ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | aws-lambda-authorize-ip-role -Memory | 128 (MB) -Timeout | 3 sec +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | ---------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | aws-lambda-authorize-ip-role | +| Memory | 128 (MB) | +| Timeout | 3 sec | ### Environment variables + Set the following required environment variables for the Lambda function: -Key | Value ----------|-------------- -groupid | The ID of the security group, e.g. ``"sg-xxxxxxxx"``. +| Key | Value | +| ------- | --------------------------------------------------- | +| groupid | The ID of the security group, e.g. `"sg-xxxxxxxx"`. | Set the following optional environment variables for the Lambda function: -Key | Value --------------|-------------- -protocol | The protocol to authorize, defaults to ``"tcp"``. -port | The port to authorize, defaults to `22` (SSH). -description | Description for the inbound rule, defaults to `"authorize-ip"`. -keepipranges | Comma-separated IP ranges to exclude from cleanup. +| Key | Value | +| ------------ | --------------------------------------------------------------- | +| protocol | The protocol to authorize, defaults to `"tcp"`. | +| port | The port to authorize, defaults to `22` (SSH). | +| description | Description for the inbound rule, defaults to `"authorize-ip"`. | +| keepipranges | Comma-separated IP ranges to exclude from cleanup. | ### Trigger configuration + Add an `API Gateway` trigger. This endpoint can then be used to authorize the IP of the requesting client. [test-event.json](test-event.json) contains a sample API Gateway event. @@ -77,7 +82,9 @@ trigger with a cron expression, e.g. `cron(0 3 * * ? *)` to run at 03:00 am [test-event2.json](test-event2.json) contains sample Cloudwatch Event data. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/authorize-ip/index.js b/authorize-ip/index.js index 2f29194..bc5e14f 100644 --- a/authorize-ip/index.js +++ b/authorize-ip/index.js @@ -30,10 +30,17 @@ const PROTOCOL = ENV.protocol || 'tcp' const PORT = ENV.port || 22 const DESCRIPTION = ENV.description || 'authorize-ip' +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') const EC2 = new AWS.EC2() -function authorizeIP (ip) { +/** + * Authprizes the given IP + * + * @param {string} ip IP address + * @returns {Promise} Resolves if the authorization succeeds + */ +function authorizeIP(ip) { const permission = { IpProtocol: PROTOCOL, FromPort: PORT, @@ -61,12 +68,14 @@ function authorizeIP (ip) { return new Promise((resolve, reject) => { EC2.authorizeSecurityGroupIngress(params) .promise() - .then(data => { + .then(() => { + // eslint-disable-next-line no-console console.log('IP newly authorized:', ip) resolve({ ip }) }) .catch(err => { if (err.code === 'InvalidPermission.Duplicate') { + // eslint-disable-next-line no-console console.log('IP already authorized:', ip) return resolve({ ip }) } @@ -75,7 +84,12 @@ function authorizeIP (ip) { }) } -function cleanupIPs () { +/** + * Cleans up authorized IPs + * + * @returns {Promise} Resolves if the cleanup operation succeeds + */ +function cleanupIPs() { const params = { GroupIds: [ENV.groupid], Filters: [ @@ -99,6 +113,7 @@ function cleanupIPs () { const ipPermissions = data.SecurityGroups.length ? data.SecurityGroups[0].IpPermissions : [] + // eslint-disable-next-line no-console console.log('IP permissions:', JSON.stringify(ipPermissions)) if (!ipPermissions.length) return null const keepIpRanges = (ENV.keepipranges || '').split(',') @@ -130,6 +145,7 @@ function cleanupIPs () { } exports.handler = (event, context, callback) => { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) if (event.source === 'aws.events') { return cleanupIPs() diff --git a/bucket-owner-full-control/README.md b/bucket-owner-full-control/README.md index a41562a..7b40f28 100644 --- a/bucket-owner-full-control/README.md +++ b/bucket-owner-full-control/README.md @@ -1,10 +1,12 @@ # bucket-owner-full-control + [AWS Lambda](https://aws.amazon.com/lambda/) function to grant the bucket owner full control over an S3 object. ## Setup ### Prerequisites + This setup assumes two AWS accounts. The main account (`Account A`) grants another account (`Account B`) access to an S3 bucket via [bucket policy](http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html), @@ -19,10 +21,7 @@ e.g. the following: "AWS": "arn:aws:iam::ACCOUNT_ID:root" }, "Action": "s3:*", - "Resource": [ - "arn:aws:s3:::BUCKET_NAME", - "arn:aws:s3:::BUCKET_NAME/*" - ] + "Resource": ["arn:aws:s3:::BUCKET_NAME", "arn:aws:s3:::BUCKET_NAME/*"] } ] } @@ -43,10 +42,7 @@ A sample bucket policy with this restriction would be the following: "AWS": "arn:aws:iam::ACCOUNT_ID:root" }, "Action": "s3:*", - "Resource": [ - "arn:aws:s3:::BUCKET_NAME", - "arn:aws:s3:::BUCKET_NAME/*" - ] + "Resource": ["arn:aws:s3:::BUCKET_NAME", "arn:aws:s3:::BUCKET_NAME/*"] }, { "Effect": "Deny", @@ -65,7 +61,8 @@ A sample bucket policy with this restriction would be the following: } ``` -A sample [s3 put-object](http://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html) +A sample +[s3 put-object](http://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html) command with the required `bucket-owner-full-control` ACL as argument: ```sh @@ -81,6 +78,7 @@ application like [Cyberduck](https://cyberduck.io/), this Lambda function comes in handy. ### IAM roles creation + In `Account B`, create a new cross-account [IAM](https://aws.amazon.com/iam/) role. Fill in the account ID of `Account A` as account that can use this role. As role name, choose `bucket-owner-full-control-role`. @@ -127,29 +125,34 @@ After creating the role, attach the following inline policy, replacing ``` ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | aws-lambda-bucket-owner-role -Memory | 128 (MB) -Timeout | 3 sec +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | ---------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | aws-lambda-bucket-owner-role | +| Memory | 128 (MB) | +| Timeout | 3 sec | ### Environment variables + Set the following required environment variable for the Lambda function: -Key | Value ---------|-------------- -rolearn | The ARN of the `bucket-owner-full-control-role` of `Account B`. +| Key | Value | +| ------- | --------------------------------------------------------------- | +| rolearn | The ARN of the `bucket-owner-full-control-role` of `Account B`. | ### Trigger configuration + Add an `S3` trigger for your bucket with the `PUT` event type. [test-event.json](test-event.json) contains a sample S3 PUT event. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/bucket-owner-full-control/index.js b/bucket-owner-full-control/index.js index 09275f7..e9c65f6 100644 --- a/bucket-owner-full-control/index.js +++ b/bucket-owner-full-control/index.js @@ -14,6 +14,7 @@ 'use strict' +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') AWS.config.credentials = new AWS.TemporaryCredentials({ @@ -21,6 +22,7 @@ AWS.config.credentials = new AWS.TemporaryCredentials({ }) exports.handler = (event, context, callback) => { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) const s3 = event.Records[0].s3 new AWS.S3().putObjectAcl( diff --git a/cloudfront-forwarded-host/README.md b/cloudfront-forwarded-host/README.md index 913b82d..6652acb 100644 --- a/cloudfront-forwarded-host/README.md +++ b/cloudfront-forwarded-host/README.md @@ -1,4 +1,5 @@ # cloudfront-forwarded-host + [AWS Lambda@Edge](https://aws.amazon.com/lambda/edge/) function to forward the `Host` header as `X-Forwarded-Host` to a [CloudFront](https://aws.amazon.com/cloudfront/) origin. @@ -6,6 +7,7 @@ ## Setup ### IAM role creation + Create a new [IAM](https://aws.amazon.com/iam/) role with the name `aws-lambda-edge-execution-role` and the following trust relationship: @@ -16,10 +18,7 @@ Create a new [IAM](https://aws.amazon.com/iam/) role with the name { "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com", - "edgelambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] }, "Action": "sts:AssumeRole" } @@ -28,28 +27,32 @@ Create a new [IAM](https://aws.amazon.com/iam/) role with the name ``` ### Function configuration + Add the function code to AWS Lambda in the `US East (N. Virginia)` region with -the following configuration options: +the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | aws-lambda-edge-execution-role -Memory | 128 (MB) -Timeout | 1 sec +| Key | Value | +| ------- | ------------------------------ | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | aws-lambda-edge-execution-role | +| Memory | 128 (MB) | +| Timeout | 1 sec | Next publish a version of the function and copy its [Lambda Function ARN](http://docs.aws.amazon.com/lambda/latest/dg/versioning-intro.html). ### CloudFront configuration -In the behavior settings of the CloudFront distribution, add a new -**Lambda Function Association** with the **Event Type** `Viewer Request` and -the **Lambda Function ARN** copied from the function configuration. + +In the behavior settings of the CloudFront distribution, add a new **Lambda +Function Association** with the **Event Type** `Viewer Request` and the **Lambda +Function ARN** copied from the function configuration. Save your edits and wait until the new settings have been deployed. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/cloudfront-security-headers/README.md b/cloudfront-security-headers/README.md index 44714e7..bd6ef7c 100644 --- a/cloudfront-security-headers/README.md +++ b/cloudfront-security-headers/README.md @@ -1,4 +1,5 @@ # cloudfront-security-headers + [AWS Lambda@Edge](https://aws.amazon.com/lambda/edge/) function to add common security headers for static content served via [CloudFront](https://aws.amazon.com/cloudfront/). @@ -6,6 +7,7 @@ security headers for static content served via ## Setup ### IAM role creation + Create a new [IAM](https://aws.amazon.com/iam/) role with the name `aws-lambda-edge-execution-role` and the following trust relationship: @@ -16,10 +18,7 @@ Create a new [IAM](https://aws.amazon.com/iam/) role with the name { "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com", - "edgelambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"] }, "Action": "sts:AssumeRole" } @@ -28,28 +27,32 @@ Create a new [IAM](https://aws.amazon.com/iam/) role with the name ``` ### Function configuration + Add the function code to AWS Lambda in the `US East (N. Virginia)` region with -the following configuration options: +the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | aws-lambda-edge-execution-role -Memory | 128 (MB) -Timeout | 3 sec +| Key | Value | +| ------- | ------------------------------ | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | aws-lambda-edge-execution-role | +| Memory | 128 (MB) | +| Timeout | 3 sec | Next publish a version of the function and copy its [Lambda Function ARN](http://docs.aws.amazon.com/lambda/latest/dg/versioning-intro.html). ### CloudFront configuration -In the behavior settings of the CloudFront distribution, add a new -**Lambda Function Association** with the **Event Type** `Origin Response` and -the **Lambda Function ARN** copied from the function configuration. + +In the behavior settings of the CloudFront distribution, add a new **Lambda +Function Association** with the **Event Type** `Origin Response` and the +**Lambda Function ARN** copied from the function configuration. Save your edits and wait until the new settings have been deployed. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/cloudwatch-alarm-to-slack/README.md b/cloudwatch-alarm-to-slack/README.md index 0608b35..2141643 100644 --- a/cloudwatch-alarm-to-slack/README.md +++ b/cloudwatch-alarm-to-slack/README.md @@ -1,4 +1,5 @@ # cloudwatch-alarm-to-slack + [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) alarm notifications to [Slack](https://slack.com/) streaming function for [AWS Lambda](https://aws.amazon.com/lambda/). @@ -6,39 +7,44 @@ ## Setup ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | AWSLambdaBasicExecutionRole -Memory | 128 (MB) -Timeout | 3 sec -KMS key | aws/lambda +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | --------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | AWSLambdaBasicExecutionRole | +| Memory | 128 (MB) | +| Timeout | 3 sec | +| KMS key | aws/lambda | ### Environment variables + Set the following required environment variable for the Lambda function: -Key | Value ---------|-------------- -webhook | [AWS KMS](https://aws.amazon.com/kms/) encrypted Slack WebHook URL. +| Key | Value | +| ------- | ------------------------------------------------------------------- | +| webhook | [AWS KMS](https://aws.amazon.com/kms/) encrypted Slack WebHook URL. | Set the following optional environment variables for the Lambda function: -Key | Value ------------|-------------- -channel | Slack channel to send the notifications to. -username | Bot username used for the slack messages. -icon_emoji | Bot icon emoji used for the slack messages. -icon_url | Bot icon url used for the slack messages. +| Key | Value | +| ---------- | ------------------------------------------- | +| channel | Slack channel to send the notifications to. | +| username | Bot username used for the slack messages. | +| icon_emoji | Bot icon emoji used for the slack messages. | +| icon_url | Bot icon url used for the slack messages. | ### Trigger configuration + Add the desired [Amazon SNS](https://aws.amazon.com/sns/) topic as trigger for the Lambda function. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/cloudwatch-alarm-to-slack/index.js b/cloudwatch-alarm-to-slack/index.js index 424c378..a75c9a5 100644 --- a/cloudwatch-alarm-to-slack/index.js +++ b/cloudwatch-alarm-to-slack/index.js @@ -25,8 +25,8 @@ if (!ENV.webhook) throw new Error('Missing environment variable: webhook') let webhook +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') -const url = require('url') const https = require('https') const statusColors = { @@ -35,15 +35,23 @@ const statusColors = { OK: 'good' } -function handleResponse (response, callback) { +/** + * Handles the HTTP response + * + * @param {*} response HTTP response + * @param {Function} callback Callback function + */ +function handleResponse(response, callback) { const statusCode = response.statusCode + // eslint-disable-next-line no-console console.log('Status code:', statusCode) let responseBody = '' response .on('data', chunk => { responseBody += chunk }) - .on('end', chunk => { + .on('end', () => { + // eslint-disable-next-line no-console console.log('Response:', responseBody) if (statusCode >= 200 && statusCode < 300) { callback(null, 'Request completed successfully.') @@ -53,18 +61,30 @@ function handleResponse (response, callback) { }) } -function post (requestURL, data, callback) { +/** + * Sends an HTTP Post request + * + * @param {string} requestURL Request URL + * @param {object} data Post data + * @param {Function} callback Callback function + */ +function post(requestURL, data, callback) { const body = JSON.stringify(data) - const options = url.parse(requestURL) - options.method = 'POST' - options.headers = { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(body) + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(body) + } } + // eslint-disable-next-line no-console + console.log('Request url:', requestURL) + // eslint-disable-next-line no-console console.log('Request options:', JSON.stringify(options)) + // eslint-disable-next-line no-console console.log('Request body:', body) https - .request(options, response => { + .request(requestURL, options, response => { handleResponse(response, callback) }) .on('error', err => { @@ -73,11 +93,19 @@ function post (requestURL, data, callback) { .end(body) } -function buildSlackMessage (data) { +/** + * Builds a Slack message object from the given message data + * + * @param {object} data Message data + * @returns {object} Slack message object + */ +function buildSlackMessage(data) { return { channel: ENV.channel, username: ENV.username, + // eslint-disable-next-line camelcase icon_emoji: ENV.icon_emoji, + // eslint-disable-next-line camelcase icon_url: ENV.icon_url, attachments: [ { @@ -102,19 +130,41 @@ function buildSlackMessage (data) { } } -function parseSNSMessage (message) { +/** + * Parses the given SNS message + * + * @param {string} message SNS message + * @returns {object} Parsed SNS message object + */ +function parseSNSMessage(message) { + // eslint-disable-next-line no-console console.log('SNS Message:', message) return JSON.parse(message) } -function processEvent (event, context, callback) { +/** + * Processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function processEvent(event, context, callback) { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) const snsMessage = parseSNSMessage(event.Records[0].Sns.Message) const postData = buildSlackMessage(snsMessage) post(webhook, postData, callback) } -function decryptAndProcess (event, context, callback) { +/** + * Decrypts the secrets and processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function decryptAndProcess(event, context, callback) { const kms = new AWS.KMS() const enc = { CiphertextBlob: Buffer.from(ENV.webhook, 'base64') } kms.decrypt(enc, (err, data) => { diff --git a/cloudwatch-events-to-buildkite/README.md b/cloudwatch-events-to-buildkite/README.md index 7a4fc38..f5995bd 100644 --- a/cloudwatch-events-to-buildkite/README.md +++ b/cloudwatch-events-to-buildkite/README.md @@ -1,4 +1,5 @@ # cloudwatch-events-to-buildkite + [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) Events to [BuildKite](https://buildkite.com/) trigger function for [AWS Lambda](https://aws.amazon.com/lambda/). @@ -6,34 +7,37 @@ ## Setup ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | AWSLambdaBasicExecutionRole -Memory | 128 (MB) -Timeout | 3 sec -KMS key | aws/lambda +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | --------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | AWSLambdaBasicExecutionRole | +| Memory | 128 (MB) | +| Timeout | 3 sec | +| KMS key | aws/lambda | ### Environment variables + Set the following required environment variables for the Lambda function: -Key | Value --------------|-------------- -token | [AWS KMS](https://aws.amazon.com/kms/) encrypted access token. -organization | BuildKite organization slug. +| Key | Value | +| ------------ | -------------------------------------------------------------- | +| token | [AWS KMS](https://aws.amazon.com/kms/) encrypted access token. | +| organization | BuildKite organization slug. | Set the following optional environment variables for the Lambda function: -Key | Value --------------|-------------- -pipeline | BuildKite pipeline slug (used if `event.pipeline` is empty). -branch | Git branch to build (*default:* `master`). -message | Build message (*default:* `:robot_face: scheduled build`). +| Key | Value | +| -------- | ------------------------------------------------------------ | +| pipeline | BuildKite pipeline slug (used if `event.pipeline` is empty). | +| branch | Git branch to build (_default:_ `master`). | +| message | Build message (_default:_ `:robot_face: scheduled build`). | ### Trigger configuration + 1. In the Amazon CloudWatch `Events => Rules` section, click on `Create rule`. 2. Choose `Schedule` as event source. 3. Select the created Lambda function as target. @@ -50,14 +54,16 @@ configured environment variable. The required request body properties are set to the following default values if not provided via event data: -Key | Value ---------|-------------- -commit | `HEAD` -branch | `master` -message | `:robot_face: scheduled build` +| Key | Value | +| ------- | ------------------------------ | +| commit | `HEAD` | +| branch | `master` | +| message | `:robot_face: scheduled build` | ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/cloudwatch-events-to-buildkite/index.js b/cloudwatch-events-to-buildkite/index.js index 9602749..edd7843 100644 --- a/cloudwatch-events-to-buildkite/index.js +++ b/cloudwatch-events-to-buildkite/index.js @@ -27,19 +27,27 @@ const ENV = process.env let token +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') -const url = require('url') const https = require('https') -function handleResponse (response, callback) { +/** + * Handles the HTTP response + * + * @param {*} response HTTP response + * @param {Function} callback Callback function + */ +function handleResponse(response, callback) { const statusCode = response.statusCode + // eslint-disable-next-line no-console console.log('Status code:', statusCode) let responseBody = '' response .on('data', chunk => { responseBody += chunk }) - .on('end', chunk => { + .on('end', () => { + // eslint-disable-next-line no-console console.log('Response:', responseBody) if (statusCode >= 200 && statusCode < 300) { callback(null, 'Request completed successfully.') @@ -49,19 +57,31 @@ function handleResponse (response, callback) { }) } -function post (requestURL, data, callback) { +/** + * Sends an HTTP Post request + * + * @param {string} requestURL Request URL + * @param {object} data Post data + * @param {Function} callback Callback function + */ +function post(requestURL, data, callback) { const body = JSON.stringify(data) - const options = url.parse(requestURL) - options.method = 'POST' - options.headers = { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(body) + const options = { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(body) + } } + // eslint-disable-next-line no-console + console.log('Request url:', requestURL) + // eslint-disable-next-line no-console console.log('Request options:', JSON.stringify(options)) + // eslint-disable-next-line no-console console.log('Request body:', body) https - .request(options, response => { + .request(requestURL, options, response => { handleResponse(response, callback) }) .on('error', err => { @@ -70,37 +90,64 @@ function post (requestURL, data, callback) { .end(body) } -function buildRequestURL (pipeline) { - return `https://api.buildkite.com/v2/organizations/${ - ENV.organization - }/pipelines/${pipeline}/builds` +/** + * Builds the request URL for the given build pipeline + * + * @param {string} pipeline Build pipeline + * @returns {string} Request URL + */ +function buildRequestURL(pipeline) { + return `https://api.buildkite.com/v2/organizations/${ENV.organization}/pipelines/${pipeline}/builds` } -function buildRequestData (event) { +/** + * Builds the request data for the given event + * + * @param {*} event Event object + * @returns {object} Request data object + */ +function buildRequestData(event) { return { commit: event.commit || 'HEAD', branch: event.branch || ENV.branch || 'master', message: event.message || ENV.message || ':robot_face: scheduled build', author: event.author, env: event.env, + // eslint-disable-next-line camelcase meta_data: event.meta_data } } -function processEvent (event, context, callback) { +/** + * Processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function processEvent(event, context, callback) { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) const pipeline = event.pipeline || ENV.pipeline if (!pipeline) { - return callback( + callback( new Error('No pipeline set in event data or as environment variable.') ) + return } const url = buildRequestURL(pipeline) const data = buildRequestData(event) post(url, data, callback) } -function decryptAndProcess (event, context, callback) { +/** + * Decrypts the secrets and processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function decryptAndProcess(event, context, callback) { const kms = new AWS.KMS() const enc = { CiphertextBlob: Buffer.from(ENV.token, 'base64') } kms.decrypt(enc, (err, data) => { diff --git a/cloudwatch-logs-to-elastic-cloud/README.md b/cloudwatch-logs-to-elastic-cloud/README.md index 7d3902f..4dc27e1 100644 --- a/cloudwatch-logs-to-elastic-cloud/README.md +++ b/cloudwatch-logs-to-elastic-cloud/README.md @@ -1,53 +1,59 @@ # cloudwatch-logs-to-elastic-cloud + CloudWatch Logs to Elasticsearch streaming function for [AWS Lambda](https://aws.amazon.com/lambda/). This is provided as alternative to the AWS Elasticsearch Service streaming -Lambda function and supports any Elasticsearch service with an -HTTPS endpoint and HTTP Basic Access Authentication, e.g. +Lambda function and supports any Elasticsearch service with an HTTPS endpoint +and HTTP Basic Access Authentication, e.g. [Elastic Cloud](https://cloud.elastic.co). ## Setup ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | AWSLambdaBasicExecutionRole -Memory | 128 (MB) -Timeout | 10 sec -KMS key | aws/lambda +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | --------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | AWSLambdaBasicExecutionRole | +| Memory | 128 (MB) | +| Timeout | 10 sec | +| KMS key | aws/lambda | ### Environment variables + Set the following required environment variables for the Lambda function: -Key | Value ----------|-------------- -hostname | Hostname of the Elasticsearch cluster **HTTPS** endpoint. -port | Port number of the Elasticsearch cluster **HTTPS** endpoint. -username | Name of an ES user with **create_index** and **write** permissions. -encpass | [AWS KMS](https://aws.amazon.com/kms/) encrypted password. +| Key | Value | +| -------- | ------------------------------------------------------------------- | +| hostname | Hostname of the Elasticsearch cluster **HTTPS** endpoint. | +| port | Port number of the Elasticsearch cluster **HTTPS** endpoint. | +| username | Name of an ES user with **create_index** and **write** permissions. | +| encpass | [AWS KMS](https://aws.amazon.com/kms/) encrypted password. | Set the following optional environment variables for the Lambda function: -Key | Value ------------|-------------- -pipeline | The Elasticsearch ingest pipeline to use. -piperegexp | RegExp matched with the log group if the pipeline applies. -pipefields | Required fields for the pipeline to add if missing, e.g.: - | `http_user_agent= real_ip=127.0.0.1` +| Key | Value | +| ------------------------------------ | ---------------------------------------------------------- | +| index | The Elasticsearch index name to override logGroup. | +| pipeline | The Elasticsearch ingest pipeline to use. | +| piperegexp | RegExp matched with the log group if the pipeline applies. | +| pipefields | Required fields for the pipeline to add if missing, e.g.: | +| `http_user_agent= real_ip=127.0.0.1` | ### Trigger configuration + Add any CloudWatch logs group as trigger for the Lambda function. ### Test event generation + The CloudWatch logs are forwarded to AWS Lambda with the following payload: ```json -{"awslogs":{"data":"BASE64ENCODED_GZIP_COMPRESSED_DATA"}} +{ "awslogs": { "data": "BASE64ENCODED_GZIP_COMPRESSED_DATA" } } ``` The decoded and decompressed data has the format shown in `awslogs-data.json`, @@ -64,7 +70,9 @@ jq -n --arg data $(jq -cj . awslogs-data.json | gzip | base64 | tr -d '\n') \ This command requires [jq](https://stedolan.github.io/jq/). ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/cloudwatch-logs-to-elastic-cloud/index.js b/cloudwatch-logs-to-elastic-cloud/index.js index be7eab6..56ed816 100644 --- a/cloudwatch-logs-to-elastic-cloud/index.js +++ b/cloudwatch-logs-to-elastic-cloud/index.js @@ -35,11 +35,18 @@ const PIPELINE_FIELDS = ENV.pipefields let password +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') const zlib = require('zlib') const https = require('https') -function extractJSON (message) { +/** + * Extracts JSON from the given message string + * + * @param {string} message Message string + * @returns {object} Message object + */ +function extractJSON(message) { const jsonStart = message.indexOf('{') if (jsonStart < 0) return null try { @@ -49,20 +56,32 @@ function extractJSON (message) { } } -function isNumeric (n) { +/** + * Tests if the given string is numeric + * + * @param {string} n Input string + * @returns {boolean} Returns true if the given string is numeric + */ +function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n) } -function buildExtractedSource (extractedFields) { +/** + * Builds an extracted source object from the given extracted fields + * + * @param {object} extractedFields Extracted fields object + * @returns {object} Extracted source object + */ +function buildExtractedSource(extractedFields) { const source = {} Object.keys(extractedFields).forEach(key => { - let value = extractedFields[key] + const value = extractedFields[key] if (!value) return if (isNumeric(value)) { source[key] = 1 * value return } - let obj = extractJSON(value) + const obj = extractJSON(value) if (obj) { source['$' + key] = obj } @@ -71,11 +90,16 @@ function buildExtractedSource (extractedFields) { return source } -function addMissingPipelineFields (source) { +/** + * Adds missing pipeline fields to the given source object + * + * @param {object} source Source object + */ +function addMissingPipelineFields(source) { PIPELINE_FIELDS.forEach(field => { - let key = field[0] + const key = field[0] if (source[key]) return - let value = field[1] + const value = field[1] if (isNumeric(value)) { source[key] = 1 * value return @@ -84,7 +108,15 @@ function addMissingPipelineFields (source) { }) } -function buildAction (logEvent, payload, index) { +/** + * Builds an action object from the given arguments + * + * @param {*} logEvent Log event + * @param {*} payload Payload (unused) + * @param {string} index Log index + * @returns {object} Action object + */ +function buildAction(logEvent, payload, index) { return { index: { _index: index, @@ -94,7 +126,15 @@ function buildAction (logEvent, payload, index) { } } -function buildSource (logEvent, payload, hasPipeline) { +/** + * Builds a source object from the given arguments + * + * @param {*} logEvent Log event + * @param {*} payload Payload (unused) + * @param {boolean} hasPipeline Has pipeline? + * @returns {object} Source object + */ +function buildSource(logEvent, payload, hasPipeline) { const source = logEvent.extractedFields ? buildExtractedSource(logEvent.extractedFields) : extractJSON(logEvent.message) || {} @@ -108,9 +148,16 @@ function buildSource (logEvent, payload, hasPipeline) { return source } -function transform (payload, hasPipeline) { +/** + * Transforms the payload into a request body + * + * @param {*} payload Payload + * @param {boolean} hasPipeline Has pipeline? + * @returns {string} Request body + */ +function transform(payload, hasPipeline) { let bulkRequestBody = '' - const index = payload.logGroup + const index = (ENV.index ? ENV.index : payload.logGroup) .replace(/\W+|_+/g, '-') .replace(/^-/, '') .toLowerCase() @@ -123,24 +170,34 @@ function transform (payload, hasPipeline) { }) return bulkRequestBody } - -function handleResponse (response, callback) { +/** + * Handles the HTTP response + * + * @param {*} response HTTP response + * @param {Function} callback Callback function + */ +function handleResponse(response, callback) { const statusCode = response.statusCode + // eslint-disable-next-line no-console console.log('Status code:', statusCode) let responseBody = '' response .on('data', chunk => { responseBody += chunk }) - .on('end', chunk => { + .on('end', () => { + // eslint-disable-next-line no-console console.log('Response:', responseBody) if (statusCode >= 200 && statusCode < 300) { const result = JSON.parse(responseBody) const items = result.items const failed = items.reduce((num, item) => { + // eslint-disable-next-line no-param-reassign return item.index.status >= 300 ? ++num : num }, 0) + // eslint-disable-next-line no-console console.log('Successful items:', items.length - failed) + // eslint-disable-next-line no-console console.log('Failed items:', failed) if (result.errors || failed) { return callback( @@ -156,11 +213,25 @@ function handleResponse (response, callback) { }) } -function queryString (hasPipeline) { +/** + * Builds the query string + * + * @param {boolean} hasPipeline Has pipeline? + * @returns {string} Query string + */ +function queryString(hasPipeline) { return hasPipeline ? '?pipeline=' + ENV.pipeline : '' } -function post (path, body, callback) { +/** + * Sends an HTTP Post request + * + * @param {string} path Request path + * @param {object} body Post data + * @param {Function} callback Callback function + */ +function post(path, body, callback) { + // eslint-disable-next-line no-console console.log('Request URL:', `https://${ENV.hostname}:${ENV.port}${path}`) const options = { hostname: ENV.hostname, @@ -183,11 +254,19 @@ function post (path, body, callback) { .end(body) } -function processEvent (event, context, callback) { +/** + * Processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function processEvent(event, context, callback) { const payload = Buffer.from(event.awslogs.data, 'base64') zlib.gunzip(payload, (err, res) => { if (err) return callback(err) const decodedPayload = JSON.parse(res.toString('utf8')) + // eslint-disable-next-line no-console console.log('Decoded payload:', JSON.stringify(decodedPayload)) if (decodedPayload.messageType === 'CONTROL_MESSAGE') { return callback(null, 'Control message handled successfully.') @@ -195,12 +274,20 @@ function processEvent (event, context, callback) { const hasPipeline = ENV.pipeline && PIPELINE_REGEXP.test(decodedPayload.logGroup) const transformedPayload = transform(decodedPayload, hasPipeline) + // eslint-disable-next-line no-console console.log('Transformed payload:', transformedPayload.replace(/\n/g, ' ')) post('/_bulk' + queryString(hasPipeline), transformedPayload, callback) }) } -function decryptAndProcess (event, context, callback) { +/** + * Decrypts the secrets and processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function decryptAndProcess(event, context, callback) { const kms = new AWS.KMS() const enc = { CiphertextBlob: Buffer.from(ENV.encpass, 'base64') } kms.decrypt(enc, (err, data) => { diff --git a/elastic-beanstalk-events-to-slack/README.md b/elastic-beanstalk-events-to-slack/README.md index b5fc861..c6c743c 100644 --- a/elastic-beanstalk-events-to-slack/README.md +++ b/elastic-beanstalk-events-to-slack/README.md @@ -1,4 +1,5 @@ # elastic-beanstalk-events-to-slack + [AWS Elastic Beanstalk](https://aws.amazon.com/elasticbeanstalk/) events to [Slack](https://slack.com/) streaming function for [AWS Lambda](https://aws.amazon.com/lambda/). @@ -6,39 +7,42 @@ ## Setup ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | AWSLambdaBasicExecutionRole -Memory | 128 (MB) -Timeout | 3 sec -KMS key | aws/lambda +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | --------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | AWSLambdaBasicExecutionRole | +| Memory | 128 (MB) | +| Timeout | 3 sec | +| KMS key | aws/lambda | ### Environment variables + Set the following required environment variable for the Lambda function: -Key | Value ---------|-------------- -webhook | [AWS KMS](https://aws.amazon.com/kms/) encrypted Slack WebHook URL. +| Key | Value | +| ------- | ------------------------------------------------------------------- | +| webhook | [AWS KMS](https://aws.amazon.com/kms/) encrypted Slack WebHook URL. | Set the following optional environment variables for the Lambda function: -Key | Value ------------|-------------- -channel | Slack channel to send the notifications to. -username | Bot username used for the slack messages. -icon_emoji | Bot icon emoji used for the slack messages. -icon_url | Bot icon url used for the slack messages. +| Key | Value | +| ---------- | ------------------------------------------- | +| channel | Slack channel to send the notifications to. | +| username | Bot username used for the slack messages. | +| icon_emoji | Bot icon emoji used for the slack messages. | +| icon_url | Bot icon url used for the slack messages. | ### Trigger configuration + Create an [Amazon SNS](https://aws.amazon.com/sns/) topic and add it as SNS trigger for the Lambda function. Add the `Topic ARN` as Notification setting to your Elastic Beanstalk -environment configuration: +[Environment Manifest (env.yaml)](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environment-cfg-manifest.html): ```yml OptionSettings: @@ -48,7 +52,9 @@ OptionSettings: ``` ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/elastic-beanstalk-events-to-slack/index.js b/elastic-beanstalk-events-to-slack/index.js index 130084e..acfbd73 100644 --- a/elastic-beanstalk-events-to-slack/index.js +++ b/elastic-beanstalk-events-to-slack/index.js @@ -25,8 +25,8 @@ if (!ENV.webhook) throw new Error('Missing environment variable: webhook') let webhook +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') -const url = require('url') const https = require('https') const STATUS_TYPES = [ @@ -58,15 +58,23 @@ const EXCLUDE_KEYS = [ ] const SHORT_KEYS = ['Application', 'Environment'] -function handleResponse (response, callback) { +/** + * Handles the HTTP response + * + * @param {*} response HTTP response + * @param {Function} callback Callback function + */ +function handleResponse(response, callback) { const statusCode = response.statusCode + // eslint-disable-next-line no-console console.log('Status code:', statusCode) let responseBody = '' response .on('data', chunk => { responseBody += chunk }) - .on('end', chunk => { + .on('end', () => { + // eslint-disable-next-line no-console console.log('Response:', responseBody) if (statusCode >= 200 && statusCode < 300) { callback(null, 'Request completed successfully.') @@ -76,18 +84,30 @@ function handleResponse (response, callback) { }) } -function post (requestURL, data, callback) { +/** + * Sends an HTTP Post request + * + * @param {string} requestURL Request URL + * @param {object} data Post data + * @param {Function} callback Callback function + */ +function post(requestURL, data, callback) { const body = JSON.stringify(data) - const options = url.parse(requestURL) - options.method = 'POST' - options.headers = { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(body) + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(body) + } } + // eslint-disable-next-line no-console + console.log('Request url:', requestURL) + // eslint-disable-next-line no-console console.log('Request options:', JSON.stringify(options)) + // eslint-disable-next-line no-console console.log('Request body:', body) https - .request(options, response => { + .request(requestURL, options, response => { handleResponse(response, callback) }) .on('error', err => { @@ -96,7 +116,13 @@ function post (requestURL, data, callback) { .end(body) } -function getStatusColor (data) { +/** + * Returns the status color for the given data object + * + * @param {object} data Data object + * @returns {string} Color + */ +function getStatusColor(data) { const message = data.Message if (!message) return let color @@ -110,7 +136,13 @@ function getStatusColor (data) { return color } -function generateAttachmentFields (data) { +/** + * Generates attachment fields + * + * @param {*} data Data object + * @returns {Array} Attachment fields + */ +function generateAttachmentFields(data) { return Object.keys(data).reduce((fields, key) => { if (EXCLUDE_KEYS.indexOf(key) === -1) { return [ @@ -126,11 +158,19 @@ function generateAttachmentFields (data) { }, []) } -function buildSlackMessage (data) { +/** + * Builds a Slack message object from the given message data + * + * @param {object} data Message data + * @returns {object} Slack message object + */ +function buildSlackMessage(data) { return { channel: ENV.channel, username: ENV.username, + // eslint-disable-next-line camelcase icon_emoji: ENV.icon_emoji, + // eslint-disable-next-line camelcase icon_url: ENV.icon_url, attachments: [ { @@ -143,7 +183,13 @@ function buildSlackMessage (data) { } } -function parseSNSMessage (message) { +/** + * Parses the given SNS message + * + * @param {string} message SNS message + * @returns {object} Parsed SNS message object + */ +function parseSNSMessage(message) { const parsedMessage = message.split('\n').reduce((obj, line) => { if (line.length) { const key = line.split(':', 1)[0] @@ -156,18 +202,34 @@ function parseSNSMessage (message) { } return obj }, {}) + // eslint-disable-next-line no-console console.log('Parsed SNS Message:', JSON.stringify(parsedMessage)) return parsedMessage } -function processEvent (event, context, callback) { +/** + * Processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function processEvent(event, context, callback) { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) const snsMessage = parseSNSMessage(event.Records[0].Sns.Message) const postData = buildSlackMessage(snsMessage) post(webhook, postData, callback) } -function decryptAndProcess (event, context, callback) { +/** + * Decrypts the secrets and processes the triggered event + * + * @param {*} event Event object + * @param {*} context Context object (unused) + * @param {Function} callback Callback function + */ +function decryptAndProcess(event, context, callback) { const kms = new AWS.KMS() const enc = { CiphertextBlob: Buffer.from(ENV.webhook, 'base64') } kms.decrypt(enc, (err, data) => { diff --git a/package-lock.json b/package-lock.json index 8548fff..a4f47db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,66 +1,93 @@ { - "name": "aws-lambda", - "version": "1.0.0", - "lockfileVersion": 1, + "name": "@blueimp/aws-lambda", "requires": true, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.10.4" } }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", "dev": true, "requires": { + "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/node": { + "version": "14.0.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", + "integrity": "sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA==", + "dev": true + }, "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "dev": true }, "acorn-jsx": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", - "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", - "dev": true, - "requires": { - "acorn": "^5.0.3" - } + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true }, "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "ansi-styles": { @@ -81,102 +108,120 @@ "sprintf-js": "~1.0.2" } }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "aws-sdk": { + "version": "2.720.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.720.0.tgz", + "integrity": "sha512-899YXs6iWae82GGJM95S5MFBPIG8pE9aq+GlSr47mz7te97hGX0OcjPs3GuGZWA6Nrp0MCR9eMqu6DwBlYGltA==", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "requires": { - "callsites": "^0.2.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -192,46 +237,36 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "comment-parser": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.5.tgz", + "integrity": "sha512-iH9YA35ccw94nx5244GVkpyC9eVTsL71jZz6iz5w6RIf79JLF2AsXHXq9p6Oaohyl3sx5qSMnGsWUDFIAfWL4w==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - } + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "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.0.0" + "ms": "^2.1.1" } }, "deep-is": { @@ -240,37 +275,28 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - } - }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "ansi-colors": "^4.1.1" } }, "escape-string-regexp": { @@ -280,204 +306,130 @@ "dev": true }, "eslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz", - "integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.5.0.tgz", + "integrity": "sha512-vlUP10xse9sWt9SGRtcr1LAC67BENcQMFeV+w5EvLEoFe3xJ8cF1Skd0msziRx/VMC+72B4DxreCE+OR12OA6Q==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", "debug": "^4.0.1", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.2.0", + "esquery": "^1.2.0", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", + "levn": "^0.4.1", + "lodash": "^4.17.19", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", + "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^2.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.0.2", - "text-table": "^0.2.0" - }, - "dependencies": { - "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - } + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" } }, - "eslint-config-standard": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", - "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", + "eslint-config-blueimp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-2.1.0.tgz", + "integrity": "sha512-Ox/sCVx9gX4yPkk1JTqKLEyGOqrPVjJQvK7m1FCg2zAVgZbzCTw64s4tLW7Svn1yfwVqPeNPX+1LL0iAXjO66Q==", "dev": true }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", "dev": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" - }, - "dependencies": { - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "get-stdin": "^6.0.0" } }, "eslint-plugin-es": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz", - "integrity": "sha512-9XcVyZiQRVeFjqHw8qHNDAZcQLqaHlOGGpeYqzYh8S4JYCWTCO3yzyen8yVmA5PratfzTRWDwCOFphtDEG+w/w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "requires": { - "eslint-utils": "^1.3.0", - "regexpp": "^2.0.0" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" } }, - "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", + "eslint-plugin-jsdoc": { + "version": "30.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.0.3.tgz", + "integrity": "sha512-EviSu0Hgc9Bhz00WhA6829KYC9BaP6JWoycOTA1xFxjQ/2XguRlB3r6nGNA/jkmMDQp5dTQ22s1kAJIaC+dE8Q==", "dev": true, "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" - }, - "dependencies": { - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } + "comment-parser": "^0.7.5", + "debug": "^4.1.1", + "jsdoctypeparser": "^8.0.0", + "lodash": "^4.17.15", + "regextras": "^0.7.1", + "semver": "^7.3.2", + "spdx-expression-parse": "^3.0.1" } }, "eslint-plugin-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz", - "integrity": "sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "requires": { - "eslint-plugin-es": "^1.3.1", - "eslint-utils": "^1.3.1", - "ignore": "^4.0.2", + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", "minimatch": "^3.0.4", - "resolve": "^1.8.1", - "semver": "^5.5.0" + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, - "eslint-plugin-promise": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz", - "integrity": "sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz", - "integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==", - "dev": true + "eslint-plugin-prettier": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", + "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -485,25 +437,29 @@ } }, "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, "espree": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", - "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", + "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", "dev": true, "requires": { - "acorn": "^5.6.0", - "acorn-jsx": "^4.1.1" + "acorn": "^7.3.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" } }, "esprima": { @@ -513,12 +469,20 @@ "dev": true }, "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } } }, "esrecurse": { @@ -531,38 +495,39 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fast-levenshtein": { @@ -571,69 +536,54 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "flat-cache": "^2.0.1" } }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" } }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -644,39 +594,22 @@ "path-is-absolute": "^1.0.0" } }, - "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", - "dev": true - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "is-glob": "^4.0.1" } }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "type-fest": "^0.8.1" } }, "has-flag": { @@ -685,27 +618,28 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -723,89 +657,32 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "is-extglob": "^2.1.1" } }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -818,6 +695,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -825,15 +708,21 @@ "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, + "jsdoctypeparser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-8.0.0.tgz", + "integrity": "sha512-eLCs6s4JqN8TjFJfgdiLHRvogLhOAJz+5RIA2FtoMe6ZDyuvghvppnlIToqAEnVbxRqLMrfnNXpW8FpmR6IMBw==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -847,55 +736,19 @@ "dev": true }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "minimatch": { @@ -908,30 +761,24 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "natural-compare": { @@ -940,30 +787,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -973,75 +796,27 @@ "wrappy": "1" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { - "error-ex": "^1.2.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "callsites": "^3.0.0" } }, "path-is-absolute": { @@ -1050,249 +825,141 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { + "prettier-linter-helpers": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { - "find-up": "^1.0.0" + "fast-diff": "^1.1.2" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - } - } + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } + "regextras": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz", + "integrity": "sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==", + "dev": true }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", "dev": true }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" } }, - "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -1300,9 +967,9 @@ } }, "spdx-license-ids": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", - "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "sprintf-js": { @@ -1312,34 +979,46 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.0" } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { @@ -1352,15 +1031,15 @@ } }, "table": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", - "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^6.5.3", - "lodash": "^4.17.10", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" } }, "text-table": { @@ -1369,36 +1048,21 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { - "os-tmpdir": "~1.0.2" + "prelude-ls": "^1.2.1" } }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1406,31 +1070,51 @@ "dev": true, "requires": { "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } } }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "punycode": "1.3.2", + "querystring": "0.2.0" } }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, "wrappy": { @@ -1440,13 +1124,29 @@ "dev": true }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" } + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true } } } diff --git a/package.json b/package.json index 6abad6b..094395b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "aws-lambda", - "version": "1.0.0", + "name": "@blueimp/aws-lambda", + "private": true, "description": "A collection of functions for AWS Lambda.", "keywords": [ "aws", @@ -16,15 +16,33 @@ "url": "git+https://github.com/blueimp/aws-lambda.git" }, "license": "MIT", + "devDependencies": { + "@types/node": "14", + "aws-sdk": "2", + "eslint": "7", + "eslint-config-blueimp": "2", + "eslint-config-prettier": "6", + "eslint-plugin-jsdoc": "30", + "eslint-plugin-node": "11", + "eslint-plugin-prettier": "3", + "prettier": "2" + }, + "eslintConfig": { + "extends": [ + "blueimp", + "plugin:jsdoc/recommended", + "plugin:node/recommended", + "plugin:prettier/recommended" + ] + }, + "prettier": { + "arrowParens": "avoid", + "proseWrap": "always", + "semi": false, + "singleQuote": true, + "trailingComma": "none" + }, "scripts": { "test": "eslint ." - }, - "devDependencies": { - "eslint": "^5.7.0", - "eslint-config-standard": "^12.0.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-node": "^7.0.1", - "eslint-plugin-promise": "^4.0.1", - "eslint-plugin-standard": "^4.0.0" } } diff --git a/ssh-authorized-keys/README.md b/ssh-authorized-keys/README.md index 2e49220..2287c35 100644 --- a/ssh-authorized-keys/README.md +++ b/ssh-authorized-keys/README.md @@ -1,4 +1,5 @@ # ssh-authorized-keys + [AWS Lambda](https://aws.amazon.com/lambda/) function to return authorized keys for EC2 SSH access. Meant to be used with [Amazon API Gateway](https://aws.amazon.com/api-gateway/). @@ -6,11 +7,13 @@ Meant to be used with [Amazon API Gateway](https://aws.amazon.com/api-gateway/). ## Setup ### IAM group creation + Create a new [IAM](https://aws.amazon.com/iam/) group and label it e.g. `ssh`. Attach the managed policy `IAMUserSSHKeys` and add all users that should be granted EC2 SSH access. ### IAM role creation + Create a new [IAM](https://aws.amazon.com/iam/) role with the name `aws-lambda-ssh-authorized-keys`. Select the AWS Lambda role type and attach the managed policy `AWSLambdaBasicExecutionRole`. @@ -28,38 +31,39 @@ replacing `ssh` with the IAM group created in the previous section. "iam:listSSHPublicKeys", "iam:getSSHPublicKey" ], - "Resource":[ - "arn:aws:iam::*:group/ssh", - "arn:aws:iam::*:user/*" - ] + "Resource": ["arn:aws:iam::*:group/ssh", "arn:aws:iam::*:user/*"] } ] } ``` ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | aws-lambda-ssh-authorized-keys -Memory | 128 (MB) -Timeout | 10 sec +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | ------------------------------ | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | aws-lambda-ssh-authorized-keys | +| Memory | 128 (MB) | +| Timeout | 10 sec | ### Environment variables + Set the following optional environment variable for the Lambda function: -Key | Value -------|-------------- -group | The IAM group of users authorized for SSH access, defaults to ``"ssh"``. +| Key | Value | +| ----- | ---------------------------------------------------------------------- | +| group | The IAM group of users authorized for SSH access, defaults to `"ssh"`. | ### Trigger configuration + Add an API Gateway trigger with "Open" security. No API key is necessary, as the returned keys are public by definition. #### Enable API Gateway Caching + 1. Go to the API Gateway console. 2. Navigate to the Stage Editor for the `prod` stage. 3. Choose `Settings`. @@ -68,6 +72,7 @@ No API key is necessary, as the returned keys are public by definition. 6. Set the `Cache time-to-live (TTL)` to `300` (5 mins). ### EC2 configuration + Use the following [EC2 user data shell script](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-shell-scripts) when launching your instances, replacing `ID` with the API Gateway ID of your @@ -96,7 +101,9 @@ sshd -t && service sshd reload ``` ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/ssh-authorized-keys/index.js b/ssh-authorized-keys/index.js index 760e3e3..1d8ef98 100644 --- a/ssh-authorized-keys/index.js +++ b/ssh-authorized-keys/index.js @@ -16,12 +16,19 @@ 'use strict' +// eslint-disable-next-line node/no-unpublished-require const AWS = require('aws-sdk') const IAM = new AWS.IAM() const GROUP = process.env.group || 'ssh' -function getGroupUsers (groupName) { +/** + * Retrievs the group users + * + * @param {string} groupName Group name + * @returns {Promise} Resolves with the group users + */ +function getGroupUsers(groupName) { return IAM.getGroup({ GroupName: groupName }) @@ -29,7 +36,13 @@ function getGroupUsers (groupName) { .then(data => data.Users.map(user => user.UserName)) } -function getSSHPublicKeyIDs (userName) { +/** + * Retrievs the public SSH key IDs of the user + * + * @param {string} userName User name + * @returns {Promise} Resolves with the public SSH key IDs + */ +function getSSHPublicKeyIDs(userName) { return IAM.listSSHPublicKeys({ UserName: userName }) @@ -42,7 +55,14 @@ function getSSHPublicKeyIDs (userName) { ) } -function getSSHPublicKey (userName, keyID) { +/** + * Retrievs the public SSH key of the user and key + * + * @param {string} userName User name + * @param {string} keyID Key ID + * @returns {Promise} Resolves with the public SSH key + */ +function getSSHPublicKey(userName, keyID) { return IAM.getSSHPublicKey({ Encoding: 'SSH', UserName: userName, @@ -52,15 +72,28 @@ function getSSHPublicKey (userName, keyID) { .then(data => data.SSHPublicKey.SSHPublicKeyBody) } -function getSSHPublicKeys (userName) { +/** + * Retrievs the public SSH keys of the user + * + * @param {string} userName User name + * @returns {Promise} Resolves with the public SSH keys + */ +function getSSHPublicKeys(userName) { return getSSHPublicKeyIDs(userName).then(keyIDs => { return Promise.all(keyIDs.map(keyID => getSSHPublicKey(userName, keyID))) }) } -function getGroupSSHPublicKeys (group) { +/** + * Retrievs the public SSH keys of the group users + * + * @param {string} group User group + * @returns {Promise} Resolves with the public SSH keys + */ +function getGroupSSHPublicKeys(group) { return getGroupUsers(group) .then(users => { + // eslint-disable-next-line no-console console.log('Users:', JSON.stringify(users)) return Promise.all(users.map(userName => getSSHPublicKeys(userName))) }) @@ -72,10 +105,13 @@ function getGroupSSHPublicKeys (group) { } exports.handler = (event, context, callback) => { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) + // eslint-disable-next-line no-console console.log('Group:', GROUP) getGroupSSHPublicKeys(GROUP) .then(keys => { + // eslint-disable-next-line no-console console.log('Keys count:', keys.length) callback(null, { statusCode: 200, diff --git a/subdomain-redirect/README.md b/subdomain-redirect/README.md index 473dcf3..127b1bc 100644 --- a/subdomain-redirect/README.md +++ b/subdomain-redirect/README.md @@ -1,4 +1,5 @@ # subdomain-redirect + [AWS Lambda](https://aws.amazon.com/lambda/) function to redirect a domain to its subdomain or parent domain. Meant to be used with [Amazon API Gateway](https://aws.amazon.com/api-gateway/). @@ -6,36 +7,40 @@ Meant to be used with [Amazon API Gateway](https://aws.amazon.com/api-gateway/). ## Setup ### Function configuration -Add the function code to AWS Lambda with the following configuration options: -Key | Value ---------|-------------- -Runtime | Node.js 6.10 -Handler | index.handler -Role | AWSLambdaBasicExecutionRole -Memory | 128 (MB) -Timeout | 3 sec +Add the function code to AWS Lambda with the following configuration options: + +| Key | Value | +| ------- | --------------------------- | +| Runtime | Node.js 10.x | +| Handler | index.handler | +| Role | AWSLambdaBasicExecutionRole | +| Memory | 128 (MB) | +| Timeout | 3 sec | ### Environment variables + Set the following optional environment variables for the Lambda function: -Key | Value --------|-------------- -label | The DNS label of the subdomain, defaults to `"www"`. -status | The status code of the response, defaults to `302`. -scheme | The scheme of the redirect URL, defaults to `"https"`. -hsts | The value for the `HSTS` header, by default empty. -type | The value for the `Content-Type` header, defaults to `"text/html"`. +| Key | Value | +| ------ | ------------------------------------------------------------------- | +| label | The DNS label of the subdomain, defaults to `"www"`. | +| status | The status code of the response, defaults to `302`. | +| scheme | The scheme of the redirect URL, defaults to `"https"`. | +| hsts | The value for the `HSTS` header, by default empty. | +| type | The value for the `Content-Type` header, defaults to `"text/html"`. | ### Certificate Manager configuration + Select the `US East (N. Virginia)` region, request a certificate for your custom domain with both the wildcard and naked domain - e.g. `*.example.org` and `example.org` - and confirm the email request. ### API Gateway configuration + 1. Create a new API in [Amazon API Gateway](https://aws.amazon.com/api-gateway/) with the name `subdomain-redirect`. -3. Select `Resources => Actions => Create Method` and choose `ANY` as HTTP +2. Select `Resources => Actions => Create Method` and choose `ANY` as HTTP method. Enable `Use Lambda Proxy integration`, choose your lambda region, enter the function name (`subdomain-redirect`) and save the method. 3. Select `Resources => Actions => Create Resource`, enable @@ -45,19 +50,22 @@ domain with both the wildcard and naked domain - e.g. `*.example.org` and 4. Next, deploy the API via `Resources => Actions => Deploy API` with `prod` as new stage name. 5. Create a custom domain name. Enter the naked domain (e.g. `example.org`) if - you want to redirect to the `www` subdomain. Enter the subdomain - (e.g. `www.example.org`) if you want to redirect to the parent domain. Add a - base path mapping to the `subdomain-redirect` API with the `Path` empty and - the stage set to `prod` and save the custom domain. + you want to redirect to the `www` subdomain. Enter the subdomain (e.g. + `www.example.org`) if you want to redirect to the parent domain. Add a base + path mapping to the `subdomain-redirect` API with the `Path` empty and the + stage set to `prod` and save the custom domain. ### Route53 configuration + In [Amazon Route 53](https://aws.amazon.com/route53/) in your hosted zone, create a new record for your custom domain. Set the `Type` to `A`, `Alias` to `Yes` and set the `Alias Target` to the `Target Domain Name` from the custom domain setup in API Gateway. ## License + Released under the [MIT license](https://opensource.org/licenses/MIT). ## Author + [Sebastian Tschan](https://blueimp.net/) diff --git a/subdomain-redirect/index.js b/subdomain-redirect/index.js index 528f5c5..d7344a9 100644 --- a/subdomain-redirect/index.js +++ b/subdomain-redirect/index.js @@ -27,6 +27,7 @@ const hsts = env.hsts const contentType = env.type || 'text/html' exports.handler = (event, context, callback) => { + // eslint-disable-next-line no-console console.log('Event:', JSON.stringify(event)) const host = event.headers.Host // If the subdomain matches, redirect to the parent domain. @@ -49,6 +50,7 @@ exports.handler = (event, context, callback) => { headers: { location, 'content-type': contentType } } if (hsts) response.headers['strict-transport-security'] = hsts + // eslint-disable-next-line no-console console.log('Response:', JSON.stringify(response)) callback(null, response) }