├── cognito-setup ├── outputs.tf ├── versions.tf ├── ses-account.tf ├── .gitignore ├── provider.tf ├── testing-script.txt ├── variables.tf └── cognito.tf ├── email-passwordless-lambda ├── .gitignore ├── src │ ├── pre-sign-up.ts │ ├── verify-auth-challenge-response.ts │ ├── post-authentication.ts │ ├── define-auth-challenge.ts │ └── create-auth-challenge.ts ├── congnito.cmd.txt ├── package.json ├── tsconfig.json ├── serverless.yml └── package-lock.json ├── images ├── ses-email-verify.png ├── app-clients-detail.png ├── cognito-user-pool.png ├── cognito-lambda-triggers.png └── user-pool-passwordless-detail.png └── README.md /cognito-setup/outputs.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cognito-setup/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.13" 4 | } 5 | -------------------------------------------------------------------------------- /email-passwordless-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Dependency directories 3 | node_modules/ 4 | jspm_packages/ 5 | dist/ 6 | .serverless/ -------------------------------------------------------------------------------- /images/ses-email-verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajeshkumarbehura/aws-cognito-passwordless/main/images/ses-email-verify.png -------------------------------------------------------------------------------- /images/app-clients-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajeshkumarbehura/aws-cognito-passwordless/main/images/app-clients-detail.png -------------------------------------------------------------------------------- /images/cognito-user-pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajeshkumarbehura/aws-cognito-passwordless/main/images/cognito-user-pool.png -------------------------------------------------------------------------------- /cognito-setup/ses-account.tf: -------------------------------------------------------------------------------- 1 | # email address 2 | resource "aws_ses_email_identity" "email_address_1" { 3 | email = var.ses_email_address 4 | } -------------------------------------------------------------------------------- /images/cognito-lambda-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajeshkumarbehura/aws-cognito-passwordless/main/images/cognito-lambda-triggers.png -------------------------------------------------------------------------------- /images/user-pool-passwordless-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajeshkumarbehura/aws-cognito-passwordless/main/images/user-pool-passwordless-detail.png -------------------------------------------------------------------------------- /cognito-setup/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Dependency directories 3 | node_modules/ 4 | jspm_packages/ 5 | dist/ 6 | .serverless/ 7 | .terraform/ 8 | terraform.tfstate.backup 9 | terraform.tfstate -------------------------------------------------------------------------------- /cognito-setup/provider.tf: -------------------------------------------------------------------------------- 1 | # provider.tf 2 | 3 | # Specify the provider and access details 4 | provider "aws" { 5 | shared_credentials_file = "$HOME/.aws/credentials" 6 | profile = "default" 7 | region = var.aws_region 8 | } 9 | 10 | -------------------------------------------------------------------------------- /email-passwordless-lambda/src/pre-sign-up.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT-0 3 | 4 | import { PreSignUpTriggerHandler } from 'aws-lambda'; 5 | 6 | export const handler: PreSignUpTriggerHandler = async event => { 7 | event.response.autoConfirmUser = true; 8 | return event; 9 | }; 10 | -------------------------------------------------------------------------------- /cognito-setup/testing-script.txt: -------------------------------------------------------------------------------- 1 | -- signpup 2 | aws cognito-idp sign-up --client-id 6lklq0cd00nsikubmgq5k6tsm4 --username rajesh.hofo@gmail.com --password 123456 3 | 4 | -- get the session /send an email 5 | aws cognito-idp initiate-auth --client-id 6lklq0cd00nsikubmgq5k6tsm4 --auth-flow CUSTOM_AUTH --auth-parameters USERNAME="rajesh.hofo@gmail.com",PASSWORD="" 6 | 7 | // get the token 8 | aws cognito-idp respond-to-auth-challenge --client-id 6lklq0cd00nsikubmgq5k6tsm4 --challenge-name CUSTOM_CHALLENGE --challenge-responses ANSWER=030828,USERNAME="rajesh.hofo@gmail.com" 9 | --session "" -------------------------------------------------------------------------------- /email-passwordless-lambda/congnito.cmd.txt: -------------------------------------------------------------------------------- 1 | -- signpup 2 | aws cognito-idp sign-up --client-id 4cgrq69gatdp03sa7k63m05uo --username rajesh.hofo@gmail.com 3 | 4 | 5 | -- get the session /send an email 6 | aws cognito-idp initiate-auth --client-id 568fqvgq612k636hhol63rfgg3 --auth-flow CUSTOM_AUTH --auth-parameters USERNAME="rajesh.hofo@gmail.com",PASSWORD="" 7 | 8 | // get the token 9 | aws cognito-idp respond-to-auth-challenge --client-id 568fqvgq612k636hhol63rfgg3 --challenge-name CUSTOM_CHALLENGE --challenge-responses ANSWER=780322,USERNAME="rajesh.hofo@gmail.com" 10 | --session "" 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aws Cognito Email Passwordless 2 | 3 | Aws default Region = ap-southeast-1 4 | Ses Email Id = <> 5 | 6 | ### Steps to setup Passwordless using email id 7 | ```` 8 | 1. deploy the lambda using serveless framework 9 | 2. depploy aws cognito & ses email account using terraform 10 | 3. verfiy your email id for ses account 11 | 4. setup lambda for congnito triggers 12 | 5. test the passwordless using aws congnito cli commands 13 | ```` 14 | 15 | Follow the link for deployment : 16 | ```` 17 | https://dev.to/rajeshkumarbehura/aws-cognito-email-passwordless-me8 18 | ```` -------------------------------------------------------------------------------- /email-passwordless-lambda/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-auth-challenge", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "create-auth-challenge.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "rm -rf ./dist && tsc" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "crypto-secure-random-digit": "^1.0.9", 15 | "@types/aws-lambda": "^8.10.71", 16 | "@types/node": "^14.14.22", 17 | "aws-sdk": "^2.834.0", 18 | "typescript": "^4.1.3" 19 | }, 20 | "devDependencies": {} 21 | } 22 | -------------------------------------------------------------------------------- /email-passwordless-lambda/src/verify-auth-challenge-response.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT-0 3 | 4 | import { VerifyAuthChallengeResponseTriggerHandler } from 'aws-lambda'; 5 | 6 | export const handler: VerifyAuthChallengeResponseTriggerHandler = async event => { 7 | const expectedAnswer = event.request.privateChallengeParameters!.secretLoginCode; 8 | if (event.request.challengeAnswer === expectedAnswer) { 9 | event.response.answerCorrect = true; 10 | } else { 11 | event.response.answerCorrect = false; 12 | } 13 | return event; 14 | }; 15 | -------------------------------------------------------------------------------- /email-passwordless-lambda/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2017", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "noImplicitAny": false, 8 | "sourceMap": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "moduleResolution": "node", 12 | "declaration": false, 13 | "listFiles": false 14 | }, 15 | "exclude": [ 16 | ".vscode", 17 | ".serverless", 18 | ".git", 19 | "node_modules" 20 | ], 21 | "compileOnSave": false, 22 | "buildOnSave": false, 23 | "atom": { 24 | "rewriteTsconfig": false 25 | } 26 | } -------------------------------------------------------------------------------- /cognito-setup/variables.tf: -------------------------------------------------------------------------------- 1 | # variables.tf 2 | variable "ENV" { 3 | default = "DEV" 4 | } 5 | 6 | variable "user_pool_name" { 7 | description = "Define UserPool name" 8 | default = "PASSWORDLESS-USER-POOL" 9 | } 10 | 11 | variable "client_email_app_name" { 12 | description = "Define UserPool name" 13 | default = "EmailPasswordLessApp" 14 | } 15 | 16 | variable "aws_region" { 17 | description = "The AWS region things are created in" 18 | default = "ap-southeast-1" 19 | } 20 | 21 | # Update your Email Account 22 | variable "ses_email_address" { 23 | description = "Email account for ses account, verify the account after logging into your account." 24 | default = "exmaple@gmail.com" 25 | } -------------------------------------------------------------------------------- /email-passwordless-lambda/src/post-authentication.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT-0 3 | 4 | import { PostAuthenticationTriggerHandler } from 'aws-lambda'; 5 | import { CognitoIdentityServiceProvider } from 'aws-sdk'; 6 | 7 | const cup = new CognitoIdentityServiceProvider(); 8 | 9 | export const handler: PostAuthenticationTriggerHandler = async event => { 10 | if (event.request.userAttributes.email_verified !== 'true') { 11 | const params: CognitoIdentityServiceProvider.AdminUpdateUserAttributesRequest = { 12 | UserPoolId: event.userPoolId, 13 | UserAttributes: [{ 14 | Name: 'email_verified', 15 | Value: 'true', 16 | }], 17 | Username: event.userName!, 18 | }; 19 | await cup.adminUpdateUserAttributes(params).promise(); 20 | } 21 | return event; 22 | }; 23 | -------------------------------------------------------------------------------- /cognito-setup/cognito.tf: -------------------------------------------------------------------------------- 1 | resource "aws_cognito_user_pool" "pool" { 2 | name = "${var.ENV}-${var.user_pool_name}" 3 | 4 | # Possible values: 'phone_number', 'email', or 'preferred_username'. Conflicts with username_attributes." 5 | # alias_attributes = [null] 6 | username_attributes = [ 7 | "email"] 8 | auto_verified_attributes = [] 9 | 10 | username_configuration { 11 | case_sensitive = true 12 | } 13 | 14 | password_policy { 15 | minimum_length = 6 16 | require_lowercase = false 17 | require_numbers = false 18 | require_symbols = false 19 | require_uppercase = false 20 | temporary_password_validity_days = 7 21 | } 22 | 23 | mfa_configuration = "OFF" 24 | 25 | account_recovery_setting { 26 | recovery_mechanism { 27 | name = "admin_only" 28 | priority = 1 29 | } 30 | } 31 | } 32 | 33 | ## Create App Client in POOL 34 | resource "aws_cognito_user_pool_client" "client" { 35 | name = var.client_email_app_name 36 | user_pool_id = aws_cognito_user_pool.pool.id 37 | # Note : generate secret must be false. 38 | generate_secret = false 39 | explicit_auth_flows = [ 40 | "ALLOW_CUSTOM_AUTH", 41 | "ALLOW_REFRESH_TOKEN_AUTH" 42 | ] 43 | } -------------------------------------------------------------------------------- /email-passwordless-lambda/serverless.yml: -------------------------------------------------------------------------------- 1 | service: passwordless-authentication 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs14.x 6 | stage: dev 7 | # MAKE SURE ABOUT YOUR REGION 8 | region: ap-southeast-1 9 | memorySize: 128 10 | timeout: 30 11 | environment: 12 | #SES_FROM_ADDRESS: rajesh.xxxx@mail.com 13 | SES_FROM_ADDRESS: <> 14 | iamRoleStatements: 15 | - Effect: "Allow" 16 | Action: 17 | - "ses:SendEmail" 18 | Resource: "*" 19 | - Effect: "Allow" 20 | Action: 21 | - "cognito-idp:AdminUpdateUserAttributes" 22 | Resource: "*" 23 | 24 | functions: 25 | createAuthChallenge: 26 | handler: dist/create-auth-challenge.handler 27 | name: create-auth-challenge 28 | description: Passwordless create auth challenge 29 | 30 | preSignupTrigger: 31 | handler: dist/pre-sign-up.handler 32 | name: pre-signup-trigger 33 | description: Passwordless pre signup Trigger 34 | 35 | defineAuthChallenge: 36 | handler: dist/define-auth-challenge.handler 37 | name: define-auth-challenge 38 | description: Passwordless define auth challenge 39 | 40 | postAuthentication: 41 | handler: dist/post-authentication.handler 42 | name: post-authentication 43 | description: Passwordless post authentication 44 | 45 | verifyAuthChallengeResponse: 46 | handler: dist/verify-auth-challenge-response.handler 47 | name: verify-auth-challenge-response 48 | description: Passwordless verify auth challenge response -------------------------------------------------------------------------------- /email-passwordless-lambda/src/define-auth-challenge.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT-0 3 | 4 | import { DefineAuthChallengeTriggerHandler } from 'aws-lambda'; 5 | 6 | export const handler: DefineAuthChallengeTriggerHandler = async event => { 7 | if (event.request.session && 8 | event.request.session.find(attempt => attempt.challengeName !== 'CUSTOM_CHALLENGE')) { 9 | // We only accept custom challenges; fail auth 10 | event.response.issueTokens = false; 11 | event.response.failAuthentication = true; 12 | } else if (event.request.session && 13 | event.request.session.length >= 3 && 14 | event.request.session.slice(-1)[0].challengeResult === false) { 15 | // The user provided a wrong answer 3 times; fail auth 16 | event.response.issueTokens = false; 17 | event.response.failAuthentication = true; 18 | } else if (event.request.session && 19 | event.request.session.length && 20 | event.request.session.slice(-1)[0].challengeName === 'CUSTOM_CHALLENGE' && // Doubly stitched, holds better 21 | event.request.session.slice(-1)[0].challengeResult === true) { 22 | // The user provided the right answer; succeed auth 23 | event.response.issueTokens = true; 24 | event.response.failAuthentication = false; 25 | } else { 26 | // The user did not provide a correct answer yet; present challenge 27 | event.response.issueTokens = false; 28 | event.response.failAuthentication = false; 29 | event.response.challengeName = 'CUSTOM_CHALLENGE'; 30 | } 31 | 32 | return event; 33 | }; 34 | -------------------------------------------------------------------------------- /email-passwordless-lambda/src/create-auth-challenge.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT-0 3 | 4 | import { CreateAuthChallengeTriggerHandler } from 'aws-lambda'; 5 | import { randomDigits } from 'crypto-secure-random-digit'; 6 | import { SES } from 'aws-sdk'; 7 | 8 | const ses = new SES(); 9 | 10 | export const handler: CreateAuthChallengeTriggerHandler = async event => { 11 | 12 | let secretLoginCode: string; 13 | if (!event.request.session || !event.request.session.length) { 14 | 15 | // This is a new auth session 16 | // Generate a new secret login code and mail it to the user 17 | secretLoginCode = randomDigits(6).join(''); 18 | await sendEmail(event.request.userAttributes.email, secretLoginCode); 19 | 20 | } else { 21 | 22 | // There's an existing session. Don't generate new digits but 23 | // re-use the code from the current session. This allows the user to 24 | // make a mistake when keying in the code and to then retry, rather 25 | // then needing to e-mail the user an all new code again. 26 | const previousChallenge = event.request.session.slice(-1)[0]; 27 | secretLoginCode = previousChallenge.challengeMetadata!.match(/CODE-(\d*)/)![1]; 28 | } 29 | 30 | // This is sent back to the client app 31 | event.response.publicChallengeParameters = { email: event.request.userAttributes.email }; 32 | 33 | // Add the secret login code to the private challenge parameters 34 | // so it can be verified by the "Verify Auth Challenge Response" trigger 35 | event.response.privateChallengeParameters = { secretLoginCode }; 36 | 37 | // Add the secret login code to the session so it is available 38 | // in a next invocation of the "Create Auth Challenge" trigger 39 | event.response.challengeMetadata = `CODE-${secretLoginCode}`; 40 | 41 | return event; 42 | }; 43 | 44 | async function sendEmail(emailAddress: string, secretLoginCode: string) { 45 | const params: SES.SendEmailRequest = { 46 | Destination: { ToAddresses: [emailAddress] }, 47 | Message: { 48 | Body: { 49 | Html: { 50 | Charset: 'UTF-8', 51 | Data: `

This is your secret login code:

52 |

${secretLoginCode}

` 53 | }, 54 | Text: { 55 | Charset: 'UTF-8', 56 | Data: `Your secret login code: ${secretLoginCode}` 57 | } 58 | }, 59 | Subject: { 60 | Charset: 'UTF-8', 61 | Data: 'Your secret login code' 62 | } 63 | }, 64 | Source: process.env.SES_FROM_ADDRESS! 65 | }; 66 | await ses.sendEmail(params).promise(); 67 | } 68 | -------------------------------------------------------------------------------- /email-passwordless-lambda/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-auth-challenge", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/aws-lambda": { 8 | "version": "8.10.75", 9 | "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.75.tgz", 10 | "integrity": "sha512-orOKSsIVUMsAbKgbSX2ST3FwQt9pxinHVCAIAVl4SmmTxmki2Gu+cGqobMD3eYwDV5FV0YNtaXyxnvE9pLrKTw==" 11 | }, 12 | "@types/node": { 13 | "version": "14.14.37", 14 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", 15 | "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==" 16 | }, 17 | "aws-sdk": { 18 | "version": "2.882.0", 19 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.882.0.tgz", 20 | "integrity": "sha512-MC1tKQdvIBmSQmyFmS6McGGPrN6yvHmhP0SS0ovx+zF/BbvHPTpi5hIgqPSAkdb8/s0I16QtbwiLQgPT2pf1tA==", 21 | "requires": { 22 | "buffer": "4.9.2", 23 | "events": "1.1.1", 24 | "ieee754": "1.1.13", 25 | "jmespath": "0.15.0", 26 | "querystring": "0.2.0", 27 | "sax": "1.2.1", 28 | "url": "0.10.3", 29 | "uuid": "3.3.2", 30 | "xml2js": "0.4.19" 31 | } 32 | }, 33 | "base64-js": { 34 | "version": "1.5.1", 35 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 36 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 37 | }, 38 | "buffer": { 39 | "version": "4.9.2", 40 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 41 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 42 | "requires": { 43 | "base64-js": "^1.0.2", 44 | "ieee754": "^1.1.4", 45 | "isarray": "^1.0.0" 46 | } 47 | }, 48 | "crypto-secure-random-digit": { 49 | "version": "1.0.9", 50 | "resolved": "https://registry.npmjs.org/crypto-secure-random-digit/-/crypto-secure-random-digit-1.0.9.tgz", 51 | "integrity": "sha512-0jKZnjMf5lWYUdtu611xEdRCqMBD4xils04cGU5+5+50NyJ+DC2soGaLCVPTYAssK80NkPYHF2tlHjegGKSbcQ==" 52 | }, 53 | "events": { 54 | "version": "1.1.1", 55 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 56 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" 57 | }, 58 | "ieee754": { 59 | "version": "1.1.13", 60 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 61 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 62 | }, 63 | "isarray": { 64 | "version": "1.0.0", 65 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 66 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 67 | }, 68 | "jmespath": { 69 | "version": "0.15.0", 70 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", 71 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" 72 | }, 73 | "punycode": { 74 | "version": "1.3.2", 75 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 76 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 77 | }, 78 | "querystring": { 79 | "version": "0.2.0", 80 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 81 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" 82 | }, 83 | "sax": { 84 | "version": "1.2.1", 85 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 86 | "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" 87 | }, 88 | "typescript": { 89 | "version": "4.2.4", 90 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", 91 | "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" 92 | }, 93 | "url": { 94 | "version": "0.10.3", 95 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 96 | "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", 97 | "requires": { 98 | "punycode": "1.3.2", 99 | "querystring": "0.2.0" 100 | } 101 | }, 102 | "uuid": { 103 | "version": "3.3.2", 104 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 105 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 106 | }, 107 | "xml2js": { 108 | "version": "0.4.19", 109 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 110 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 111 | "requires": { 112 | "sax": ">=0.6.0", 113 | "xmlbuilder": "~9.0.1" 114 | } 115 | }, 116 | "xmlbuilder": { 117 | "version": "9.0.7", 118 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 119 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" 120 | } 121 | } 122 | } 123 | --------------------------------------------------------------------------------