CVE-2023-50928 (JavaScript, published 2023-12-22T21:15Z)
Description: value: "Sandbox Accounts for Events" provides multiple, temporary AWS accounts to a number of authenticated users simultaneously via a browser-based GUI. Authenticated users could potentially claim and access empty AWS accounts by sending request payloads to the account API containing non-existent event ids and self-defined budget & duration. This issue only affects cleaned AWS accounts, it is not possible to access AWS accounts in use or existing data/infrastructure. This issue has been patched in version 1.1.0.
Severity: nan (CVSS v3 base score: 9)
Weakness: CWE-284 \u2014 Improper Access Control
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
Repository: https://github.com/awslabs/sandbox-accounts-for-events
Files changed:
.eslintignore
CHANGELOG.md
Makefile
amplify.yml
amplify/backend/api/AdminQueries/admin-queries-cloudformation-template.json
amplify/backend/api/safegraphql/cli-inputs.json
amplify/backend/api/safegraphql/schema.graphql
amplify/backend/auth/safeafe5208f/safeafe5208f-cloudformation-template.yml
amplify/backend/auth/userPoolGroups/template.json
amplify/backend/backend-config.json
amplify/backend/custom/cfnAdminUser/cfnAdminUser-cloudformation-template.json
amplify/backend/function/AdminQueries4757b5b2/AdminQueries4757b5b2-cloudformation-template.json
amplify/backend/function/safeAdminApi/safeAdminApi-cloudformation-template.json
amplify/backend/function/safeAdminApi/src/index.js
amplify/backend/function/safeLoginApi/custom-policies.json
amplify/backend/function/safeLoginApi/safeLoginApi-cloudformation-template.json
amplify/backend/function/safeLoginApi/src/index.js
amplify/backend/function/safeLoginApi/src/package-lock.json
amplify/backend/function/safeLoginApi/src/package.json
amplify/backend/function/safeOperatorApi/safeOperatorApi-cloudformation-template.json
amplify/backend/function/safeOperatorApi/src/index.js
amplify/backend/types/amplify-dependent-resources-ref.d.ts
amplify/cli.json
src/App.js
src/graphql/mutations.js
src/graphql/queries.js
src/graphql/schema.json
src/graphql/subscriptions.js
src/pages/DetailEvent.js
src/pages/OverviewEvents.js
src/pages/OverviewUsage.js
src/pages/Statistics.js
src/pages/components/EventLogin.js
src/pages/modals/CreateEventModal.js
src/pages/modals/CreateLeaseModal.js
src/pages/modals/EditEventModal.js
src/pages/modals/EditLeaseModal.js
src/redux/actions/aws_login.js
src/redux/actions/config.js
src/redux/actions/current_user.js
src/redux/actions/events.js
src/redux/actions/leases.js
src/redux/actions/usage.js
Commit message: Reduced end user API permissions


Vulnerable code:
- no changed.

[1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0
	git archive --format zip --output build-cfn/sandbox-accounts-for-events.zip $(branch)
	cd install/cfn-lambda/dceHandleTerraFormDeployment && zip -r ../../../build-cfn/sandbox-accounts-for-events-lambda-terraform.zip . && cd -
	cd install/cfn-lambda/dceHandleAmplifyDeployment && zip -r ../../../build-cfn/sandbox-accounts-for-events-lambda-amplify.zip . && cd -
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"api-API Gateway\",\"metadata\":{}}",
  { allow: private, operations: [read] },
        ZipFile:
          Fn::Join:
            - ''
            - - const response = require('cfn-response');
              - const aws = require('aws-sdk');
              - const identity = new aws.CognitoIdentityServiceProvider();
              - exports.handler = (event, context, callback) => {
              - ' if (event.RequestType == ''Delete'') { '
              - '   response.send(event, context, response.SUCCESS, {})'
              - ' }'
              - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
              - '   const params = {'
              - '     ClientId: event.ResourceProperties.clientId,'
              - '     UserPoolId: event.ResourceProperties.userpoolId'
              - '   };'
              - '   identity.describeUserPoolClient(params).promise()'
              - '     .then((res) => {'
              - '       response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});'
              - '     })'
              - '     .catch((err) => {'
              - '       response.send(event, context, response.FAILED, {err});'
              - '     });'
              - ' }'
              - '};'
      Runtime: nodejs14.x
  {"createdOn":"Linux","createdBy":"Amplify","createdWith":"7.6.15","stackType":"auth-Cognito","metadata":{}}
                "const AWS = require('aws-sdk');",
                "       const cognitoidentity = new AWS.CognitoIdentity();",
                "    cognitoidentity.setIdentityPoolRoles(params).promise();",
        "Runtime": "nodejs14.x",
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"auth-Cognito-UserPool-Groups\",\"metadata\":{}}"
  "auth": {
    "userPoolGroups": {
      "service": "Cognito-UserPool-Groups",
      "providerPlugin": "awscloudformation",
      "dependsOn": [
        {
          "category": "auth",
          "resourceName": "safeafe5208f",
          "attributes": [
            "UserPoolId",
            "AppClientIDWeb",
            "AppClientID",
            "IdentityPoolId"
          ]
        }
      ]
    },
    "safeafe5208f": {
      "service": "Cognito",
      "providerPlugin": "awscloudformation",
      "dependsOn": [],
      "customAuth": false
    }
  },
      "service": "API Gateway",
      "providerPlugin": "awscloudformation",
          "category": "auth",
          "resourceName": "safeafe5208f",
          ]
          "category": "function",
          "resourceName": "AdminQueries4757b5b2",
          ]
      ]
      "service": "AppSync",
      "providerPlugin": "awscloudformation",
          },
          "additionalAuthenticationProviders": []
      }
  "function": {
    "AdminQueries4757b5b2": {
      "service": "Lambda",
      "build": true,
          "category": "auth",
          "resourceName": "safeafe5208f",
            "UserPoolId"
          ]
      ]
    },
    "safeOperatorApi": {
      "build": true,
      "service": "Lambda",
      "dependsOn": []
    },
    "safeLoginApi": {
      "build": true,
      "providerPlugin": "awscloudformation",
      "service": "Lambda",
      "dependsOn": []
    },
    "safeAdminApi": {
      "build": true,
      "providerPlugin": "awscloudformation",
      "service": "Lambda",
      "dependsOn": []
      "service": "customCloudformation",
      "providerPlugin": "awscloudformation",
          "category": "auth",
          "resourceName": "safeafe5208f",
          ]
          "category": "auth",
          "resourceName": "userPoolGroups",
          ]
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"custom-customCloudformation\",\"metadata\":{}}"
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs14.x",
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs14.x",
const AWS = require("aws-sdk");
    const sts = new AWS.STS({ region: region });
    return sts
        .assumeRole({
        })
        .promise()
            const iam = new AWS.IAM({
            return iam
                .listAttachedRolePolicies({ RoleName: roleName })
                .promise()
                    return iam
                        .listAccountAliases({})
                        .promise()
    let ddb = new AWS.DynamoDB.DocumentClient({
        region: region
    });
    return ddb
        .update({
        })
        .promise()
exports.handler = async ({ arguments: args }, context) => {
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs14.x",
const getAwsLoginUrlForEvent = ({
    eventId,
    budgetAmount,
    budgetCurrency,
    expiresOn,
    principalId,
    user,
    maxAccounts
}) => {
    if (!principalId)
        return respondWithError("Internal error while trying to log in.", "Parameter 'principalId' missing.");
    if (!budgetAmount)
        return respondWithError("Internal error while trying to log in.", "Parameter 'budgetAmount' missing.");
    if (!budgetCurrency)
        return respondWithError("Internal error while trying to log in.", "Parameter 'budgetCurrency' missing.");
    if (!expiresOn) return respondWithError("Internal error while trying to log in.", "Parameter 'expiresOn' missing.");
    if (!user) return respondWithError("Internal error while trying to log in.", "Parameter 'user' missing.");
    if (!maxAccounts)
        return respondWithError("Internal error while trying to log in.", "Parameter 'maxAccounts' missing.");

    return invokeApi("leases", "GET")
        .then((leases) => {
            if (leases.message) return respondWithError("Failed to list leases.", leases.message);

            let foundLease = leases.find((item) => item.principalId === principalId);
            if (foundLease) {
                switch (foundLease.leaseStatus) {
                    case "Active":
                        return getLeaseLoginUrl(foundLease, user);
                    case "Expired":
                        return respondWithError(
                            "Your AWS account has expired its lifetime and has been terminated now."
                        );
                    case "OverBudget":
                            "Your AWS account has reached its maximum budget and has been terminated now."
                    case "Inactive":
                        return respondWithError("Your AWS account has been manually terminated.");
                    default:
                        return respondWithError("Your account is not available for logging in.");
                }
            } else {
                if (leases.filter((lease) => lease.principalId.startsWith(eventId)).length >= maxAccounts)
                    return respondWithError("No more free AWS accounts available for this event.");
                return invokeApi("leases", "POST", {
                    budgetAmount,
                    expiresOn,
                    principalId,
                    budgetNotificationEmails: [user],
                    budgetCurrency
                    .then((newLease) => {
                        if (newLease.error) {
                            switch (newLease.error.code) {
                                case "ServerError":
                                    if (newLease.error.message === "No Available accounts at this moment")
                                        return respondWithError("No more free AWS accounts available.", newLease.error);
                                    else
                                        return respondWithError(
                                            "Failed to create lease for " + user + ".",
                                            newLease.error
                                        );
                                case "AlreadyExistsError":
                                    return respondWithError(
                                        "Found already existing lease for " + user + ".",
                                        newLease.error
                                    );
                                default:
                                    return respondWithError(
                                        "Failed to create lease for " + user + ".",
                                        newLease.error
                                    );
                            }
                        }
                        return getLeaseLoginUrl(newLease, user);
                    })
                    .catch((error) => respondWithError("Failed to create lease for " + user + ".", error));
            }
        .catch((error) => respondWithError("Failed to list leases.", error));
exports.handler = async ({ arguments: args }) => {
                return getAwsLoginUrlForEvent(params);
    "aws4": "^1.11.0"
  "Description": "{\"createdOn\":\"Linux\",\"createdBy\":\"Amplify\",\"createdWith\":\"7.6.15\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs14.x",
const AWS = require("aws-sdk");
    if (!user) return respondWithError("Internal error while trying to update lease.", "Parameter 'user' missing.");
    const ddb = new AWS.DynamoDB.DocumentClient({
        region: region
    });
    return ddb
        .update({
        })
        .promise()
    const ddb = new AWS.DynamoDB.DocumentClient({
        region: region
    });
    return ddb
        .delete({
        })
        .promise()
exports.handler = async ({ arguments: args }) => {
    "auth": {
        "userPoolGroups": {
            "adminGroupRole": "string",
            "operatorGroupRole": "string"
        },
        "safeafe5208f": {
            "IdentityPoolId": "string",
            "IdentityPoolName": "string",
            "UserPoolId": "string",
            "UserPoolArn": "string",
            "UserPoolName": "string",
            "AppClientIDWeb": "string",
            "AppClientID": "string"
        }
    "api": {
        "AdminQueries": {
            "RootUrl": "string",
            "ApiName": "string",
            "ApiId": "string"
        },
        "safegraphql": {
            "GraphQLAPIIdOutput": "string",
            "GraphQLAPIEndpointOutput": "string"
        }
    "function": {
        "AdminQueries4757b5b2": {
            "Name": "string",
            "Arn": "string",
            "Region": "string",
            "LambdaExecutionRole": "string"
        },
        "safeOperatorApi": {
            "Name": "string",
            "Arn": "string",
            "Region": "string",
            "LambdaExecutionRole": "string"
        },
        "safeLoginApi": {
            "Name": "string",
            "Arn": "string",
            "Region": "string",
            "LambdaExecutionRole": "string"
        },
        "safeAdminApi": {
            "Name": "string",
            "Arn": "string",
            "Region": "string",
            "LambdaExecutionRole": "string"
        }
    "custom": {
        "cfnAdminUser": {
            "AdminUserEmailAddress": "string"
        }
      "useexperimentalpipelinedtransformer": false,
      "showfieldauthnotification": false
        if (authStatus === "authenticated") {
  query safeLoginApi($action: String, $paramJson: String) {
  query safeAdminApi($action: String, $paramJson: String) {
  query safeOperatorApi($action: String, $paramJson: String) {
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Event",
          "isDeprecated" : false,
          "deprecationReason" : null
          "name" : "onUpdateEvent",
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Event",
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onDeleteEvent",
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Event",
          "isDeprecated" : false,
          "deprecationReason" : null
          "name" : "onCreateConfig",
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Config",
          "isDeprecated" : false,
          "deprecationReason" : null
          "name" : "onUpdateConfig",
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Config",
          "isDeprecated" : false,
          "deprecationReason" : null
          "name" : "onDeleteConfig",
          "args" : [ ],
            "kind" : "OBJECT",
            "name" : "Config",
          "isDeprecated" : false,
          "deprecationReason" : null
        "inputFields" : null,
        "interfaces" : [ ],
        "name" : "ModelFloatInput",
          "name" : "attributeExists",
            "kind" : "SCALAR",
            "name" : "Boolean",
            "ofType" : null
          "name" : "attributeType",
            "kind" : "ENUM",
            "name" : "ModelAttributeTypes",
            "ofType" : null
        "name" : "ModelBooleanInput",
            "name" : "Boolean",
            "name" : "Boolean",
      }, {
        "name" : "aws_subscribe",
        "description" : "Tells the service which mutation triggers this subscription.",
        "locations" : [ "FIELD_DEFINITION" ],
        "args" : [ {
          "name" : "mutations",
          "description" : "List of mutations which will trigger this subscription when they are called.",
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "String",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "onOperation" : false,
        "onFragment" : false,
        "onField" : false
        "name" : "deprecated",
        "description" : null,
        "locations" : [ "FIELD_DEFINITION", "ENUM_VALUE" ],
          "name" : "reason",
          "description" : null,
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          "defaultValue" : "\"No longer supported\""
        "name" : "aws_cognito_user_pools",
        "description" : "Tells the service this field/object has access authorized by a Cognito User Pools token.",
        "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
          "name" : "cognito_groups",
          "description" : "List of cognito user pool groups which have access on this field",
        "name" : "aws_lambda",
        "description" : "Tells the service this field/object has access authorized by a Lambda Authorizer.",
        "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
        "args" : [ ],
        "onOperation" : false,
        "onFragment" : false,
        "onField" : false
      }, {
        "name" : "aws_publish",
        "description" : "Tells the service which subscriptions will be published to when this mutation is called. This directive is deprecated use @aws_susbscribe directive instead.",
          "name" : "subscriptions",
          "description" : "List of subscriptions which will be published to when this mutation is called.",
        "name" : "aws_iam",
        "description" : "Tells the service this field/object has access authorized by sigv4 signing.",
        "name" : "aws_api_key",
        "description" : "Tells the service this field/object has access authorized by an API key.",
  subscription OnCreateEvent {
    onCreateEvent {
  subscription OnUpdateEvent {
    onUpdateEvent {
  subscription OnDeleteEvent {
    onDeleteEvent {
  subscription OnCreateConfig {
    onCreateConfig {
  subscription OnUpdateConfig {
    onUpdateConfig {
  subscription OnDeleteConfig {
    onDeleteConfig {
                            {Item.eventBudget + " " + Config.BUDGET_CURRENCY}
                            {Item.eventSpend + " " + Config.BUDGET_CURRENCY}
                        cell: (item) => item.eventSpend + " " + Config.BUDGET_CURRENCY
                    {item.eventBudget + " " + Config.BUDGET_CURRENCY}
                    {item.eventSpend + " " + Config.BUDGET_CURRENCY}
                    cell: (item) => item.costAmount.toFixed(2) + " " + Config.BUDGET_CURRENCY
                        <Container header={<Header>AWS service spend in {Config.BUDGET_CURRENCY}</Header>}>
import moment from "moment";
import { fetchAwsLoginUrl } from "../../redux/actions/aws_login";
import { fetchEndUserEvent } from "../../redux/actions/events";
    const Event = useSelector((state) => state.events);
        dispatch({ type: "event/dismiss" });
        dispatch(fetchEndUserEvent(value));
        if (!valueChangedOnce && isEmpty(Event.item) && urlParamEventId && User.isLoggedIn) {
            dispatch(fetchEndUserEvent(urlParamEventId));
    }, [Event.item, urlParamEventId, dispatch, valueChangedOnce, User]);
        if (!Event.item.eventStatus) return;
        switch (Event.item.eventStatus) {
    }, [Event.item, dispatch]);
        dispatch({ type: "event/dismiss" });
                {!Event.item.id ? (
                        <Button variant="primary" onClick={submit} loading={Event.status === "loading"}>
                            Welcome to "{Event.item.eventName}"
                            onClick={() =>
                                dispatch(
                                    fetchAwsLoginUrl({
                                        principalId:
                                            Event.item.id +
                                            Config.EVENT_PRINCIPAL_SEPARATOR +
                                            User.email.replace(/[^a-zA-Z0-9]/g, Config.EVENT_EMAIL_SUBST),
                                        budgetAmount: Event.item.eventBudget,
                                        budgetCurrency: Config.BUDGET_CURRENCY,
                                        user: User.email,
                                        expiresOn: moment
                                            .unix(Event.item.eventOn)
                                            .add(Event.item.eventDays, "days")
                                            .add(Event.item.eventHours, "hours")
                                            .unix(),
                                        maxAccounts: Event.item.maxAccounts,
                                        eventId: Event.item.id
                                    })
                                )
                            }
                        label={"Budget in " + Config.BUDGET_CURRENCY}
            let user = newValue.user.replace(/[^a-zA-Z0-9]/g, Config.EVENT_EMAIL_SUBST);
                newValue.principalId = newValue.eventId + Config.EVENT_PRINCIPAL_SEPARATOR + user;
                        label={"Budget in " + Config.BUDGET_CURRENCY}
                            label={"Budget in " + Config.BUDGET_CURRENCY}
                            label={"Budget in " + Config.BUDGET_CURRENCY}
    url: ""
    BUDGET_CURRENCY: "USD",
    EVENT_PRINCIPAL_SEPARATOR: "__",
    EVENT_EMAIL_SUBST: "+",
        case "event/loading":
            return {
                ...state,
                status: "loading"
            };
            new RegExp("^(" + action.config.EVENT_ID_REGEX + ")" + action.config.EVENT_PRINCIPAL_SEPARATOR + "\\S{5,}$")
                        budgetCurrency: config.BUDGET_CURRENCY
        eventId: item.principalId.includes(action.config.EVENT_PRINCIPAL_SEPARATOR) ? item.principalId.substring(0, action.config.EVENT_ID_LENGTH) : ""

Fixed code:
amplify-codegen-temp/models/models

## [1.1.0] - 2023-11-04
### Added
- no additions.

### Changed
- Updated Lambda functions to Node18 and aws-sdk v3
- Security upgrade: Blocked ListEvents API call for end users to remove potential data leak
- Security upgrade: Blocked API calls requesting an AWS account for a non-existent event id
- Security upgrade: Reduced number of possible parameters for end user API calls to necessary minimum, retrieve event management metadata from backend and auth token only.

### Removed
- nothing removed.


- no changes.
	zip -FSr build-cfn/sandbox-accounts-for-events.zip . -x amplify/#current-cloud-backend/\* build/\* build-cfn/\* \*dist/\* \*.DS_Store\* \*.vscode/\* \*.git/\* src/aws-exports.json\* \*amplify-meta.json\* amplify/team-provider-info.json\* \*awscloudformation\* \*node_modules\* amplify/.config/local-\*
	cd install/cfn-lambda/dceHandleTerraFormDeployment && zip -FSr ../../../build-cfn/sandbox-accounts-for-events-lambda-terraform.zip . && cd -
	cd install/cfn-lambda/dceHandleAmplifyDeployment && zip -FSr ../../../build-cfn/sandbox-accounts-for-events-lambda-amplify.zip . && cd -
        - aws ssm put-parameter --cli-input-json "{\"Type\":\"String\",\"Name\":\"/amplify/${AWS_APP_ID}/main/AMPLIFY_function_safeLoginApi_dceApiGw\",\"Value\":\"${DCE_API_GW}\",\"Overwrite\":true}"
        - aws ssm put-parameter --cli-input-json "{\"Type\":\"String\",\"Name\":\"/amplify/${AWS_APP_ID}/main/AMPLIFY_function_safeOperatorApi_dceApiGw\",\"Value\":\"${DCE_API_GW}\",\"Overwrite\":true}"
        - aws ssm put-parameter --cli-input-json "{\"Type\":\"String\",\"Name\":\"/amplify/${AWS_APP_ID}/main/AMPLIFY_function_safeAdminApi_dceApiGw\",\"Value\":\"${DCE_API_GW}\",\"Overwrite\":true}"
        - aws ssm put-parameter --cli-input-json "{\"Type\":\"String\",\"Name\":\"/amplify/${AWS_APP_ID}/main/AMPLIFY_function_safeOperatorApi_dceLeasesTable\",\"Value\":\"${DCE_LEASES_TABLE}\",\"Overwrite\":true}"
        - aws ssm put-parameter --cli-input-json "{\"Type\":\"String\",\"Name\":\"/amplify/${AWS_APP_ID}/main/AMPLIFY_function_safeAdminApi_dceAccountsTable\",\"Value\":\"${DCE_ACCOUNTS_TABLE}\",\"Overwrite\":true}"
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"api-API Gateway\",\"metadata\":{}}",
{
  "version": 1,
  "serviceConfiguration": {
    "serviceName": "AppSync",
    "defaultAuthType": {
      "mode": "AMAZON_COGNITO_USER_POOLS",
      "cognitoUserPoolId": "authsafeafe5208f"
    },
    "conflictResolution": {},
    "apiName": "safegraphql"
  }
}
        ZipFile: | 
          const response = require('cfn-response');
          const { CognitoIdentityProviderClient, DescribeUserPoolClientCommand } = require("@aws-sdk/client-cognito-identity-provider");
          const identity = new CognitoIdentityProviderClient();
          exports.handler = (event, context, callback) => {
            console.log("Lambda invoked with the following parameters: ", event, context);
            if (event.RequestType == "Delete") { 
              response.send(event, context, response.SUCCESS, {})
            }
            if (event.RequestType == "Update" || event.RequestType == "Create") {
              const params = {
                ClientId: event.ResourceProperties.clientId,
                UserPoolId: event.ResourceProperties.userpoolId
              };
              identity.send(new DescribeUserPoolClientCommand(params))
                .then((res) => {
                  response.send(event, context, response.SUCCESS, {"appSecret": res.UserPoolClient.ClientSecret});
                })
                .catch((err) => {
                  response.send(event, context, response.FAILED, {err});
              });
            }
          };
      Runtime: nodejs18.x
  {"createdOn":"Mac","createdBy":"Amplify","createdWith":"12.7.1","stackType":"auth-Cognito","metadata":{}}
                "const { CognitoIdentityClient, SetIdentityPoolRolesCommand } = require('@aws-sdk/client-cognito-identity');",
                "console.log('Lambda invoked with the following parameters: ', event, context);",
                "       const cognitoidentity = new CognitoIdentityClient();",
                "    cognitoidentity.send(new SetIdentityPoolRolesCommand(params));",
        "Runtime": "nodejs18.x",
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"auth-Cognito-UserPool-Groups\",\"metadata\":{}}"
          ],
          "category": "auth",
          "resourceName": "safeafe5208f"
          ],
          "category": "function",
          "resourceName": "AdminQueries4757b5b2"
      ],
      "providerPlugin": "awscloudformation",
      "service": "API Gateway"
          "additionalAuthenticationProviders": [],
          }
      },
      "providerPlugin": "awscloudformation",
      "service": "AppSync"
  "auth": {
    "safeafe5208f": {
      "customAuth": false,
      "dependsOn": [],
      "service": "Cognito"
    },
    "userPoolGroups": {
            "UserPoolId",
            "AppClientIDWeb",
            "AppClientID",
            "IdentityPoolId"
          ],
          "category": "auth",
          "resourceName": "safeafe5208f"
      ],
      "service": "Cognito-UserPool-Groups"
          ],
          "category": "auth",
          "resourceName": "safeafe5208f"
          ],
          "category": "auth",
          "resourceName": "userPoolGroups"
        }
      ],
      "providerPlugin": "awscloudformation",
      "service": "customCloudformation"
    }
  },
  "function": {
    "AdminQueries4757b5b2": {
      "build": true,
      "dependsOn": [
        {
          "attributes": [
            "UserPoolId"
          ],
          "category": "auth",
          "resourceName": "safeafe5208f"
        }
      ],
      "providerPlugin": "awscloudformation",
      "service": "Lambda"
    },
    "safeAdminApi": {
      "build": true,
      "dependsOn": [],
      "providerPlugin": "awscloudformation",
      "service": "Lambda"
    },
    "safeLoginApi": {
      "build": true,
      "dependsOn": [],
      "providerPlugin": "awscloudformation",
      "service": "Lambda"
    },
    "safeOperatorApi": {
      "build": true,
      "dependsOn": [],
      "providerPlugin": "awscloudformation",
      "service": "Lambda"
    }
  },
  "parameters": {
    "AMPLIFY_function_AdminQueries4757b5b2_deploymentBucketName": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "AdminQueries4757b5b2"
        }
      ]
    },
    "AMPLIFY_function_AdminQueries4757b5b2_s3Key": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "AdminQueries4757b5b2"
        }
      ]
    },
    "AMPLIFY_function_safeAdminApi_dceAccountsTable": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeAdminApi"
        }
      ]
    },
    "AMPLIFY_function_safeAdminApi_dceApiGw": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeAdminApi"
        }
      ]
    },
    "AMPLIFY_function_safeAdminApi_deploymentBucketName": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeAdminApi"
        }
      ]
    },
    "AMPLIFY_function_safeAdminApi_s3Key": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeAdminApi"
        }
      ]
    },
    "AMPLIFY_function_safeLoginApi_dceApiGw": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeLoginApi"
        }
      ]
    },
    "AMPLIFY_function_safeLoginApi_deploymentBucketName": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeLoginApi"
        }
      ]
    },
    "AMPLIFY_function_safeLoginApi_s3Key": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeLoginApi"
        }
      ]
    },
    "AMPLIFY_function_safeOperatorApi_dceApiGw": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeOperatorApi"
        }
      ]
    },
    "AMPLIFY_function_safeOperatorApi_dceLeasesTable": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeOperatorApi"
        }
      ]
    },
    "AMPLIFY_function_safeOperatorApi_deploymentBucketName": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeOperatorApi"
        }
      ]
    },
    "AMPLIFY_function_safeOperatorApi_s3Key": {
      "usedBy": [
        {
          "category": "function",
          "resourceName": "safeOperatorApi"
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"custom-customCloudformation\",\"metadata\":{}}"
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs18.x",
    },
    "LambdaExecutionRoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaExecutionRole",
          "Arn"
        ]
      }
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs18.x",
    },
    "LambdaExecutionRoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaExecutionRole",
          "Arn"
        ]
      }
const { IAMClient, ListAttachedRolePoliciesCommand, ListAccountAliasesCommand } = require('@aws-sdk/client-iam');
const { STSClient, AssumeRoleCommand } = require('@aws-sdk/client-sts');
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, UpdateCommand } = require('@aws-sdk/lib-dynamodb');

const stsClient = new STSClient({ region });
const ddbClient = new DynamoDBClient({ region });
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);

    return stsClient
        .send(new AssumeRoleCommand({
        }))
            const iamClient = new IAMClient({
            return iamClient
                .send(new ListAttachedRolePoliciesCommand({ RoleName: roleName }))
                    return iamClient
                        .send(new ListAccountAliasesCommand({}))
    return ddbDocClient
        .send(new UpdateCommand({
        }))
exports.handler = async (event, context) => {
    console.log("Lambda invoked with the following parameters: ", event, context)
    let args = event.arguments

  },
  {
    "Effect": "Allow",
    "Action": [
        "dynamodb:UpdateItem",
        "dynamodb:GetItem",
        "dynamodb:ListTables"
    ],
    "Resource": ["arn:aws:dynamodb:*:*:table/*"]
  },
  {
    "Effect": "Allow",
    "Action": [
        "cognito-idp:ListUserPools",
        "cognito-idp:AdminGetUser"
    ],
    "Resource": ["*"]
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs18.x",
    },
    "LambdaExecutionRoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaExecutionRole",
          "Arn"
        ]
      }
const moment = require("moment");
const { DynamoDBClient, ListTablesCommand } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');
const { CognitoIdentityProviderClient, ListUserPoolsCommand, AdminGetUserCommand } = require('@aws-sdk/client-cognito-identity-provider');


const ddbClient = new DynamoDBClient({ region });
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
let eventsTable

const cognitoClient = new CognitoIdentityProviderClient({ region })
let userPoolId
const getEndUserEvent = ({ id }) => {
    if (!eventsTable)
        return respondWithError("Failed to get data for event ID " + id + ".")

    return ddbDocClient.send(new GetCommand({ TableName: eventsTable, Key: { id } }))
    .then((response) => {
        if (response.Item) {
            return respondWithSuccess("Successfully got DynamoDB event item",{
                id: response.Item.id,
                eventStatus: response.Item.eventStatus,
                eventName: response.Item.eventName
            })
        } else { 
            return respondWithError('Could not find matching event for event ID "' + id + '". Please double check if your event ID is correct or ask your event operator for help.')
        }
    })
    .catch((error) =>
        respondWithError("Failed to get data for event ID " + id + ".", error)
    );
};


const getAwsLoginUrlForEvent = async ({eventId}, event) => {
    

    if (!userPoolId)
        return respondWithError("Failed to get user authentication pool, cannot claim an AWS account.")

    if (!eventsTable)
        return respondWithError("Failed to get data for event ID " + eventId + ".")

    return cognitoClient.send(new AdminGetUserCommand({
            UserPoolId: userPoolId,
            Username: event.identity.username
        }))
        .then(cognitoResponse => {
            const user = cognitoResponse.UserAttributes.find(attr => attr.Name == "email").Value
            let principalId = eventId + "__" + user.replace(/[^a-zA-Z0-9]/g, "+")
            return ddbDocClient.send(new GetCommand({ TableName: eventsTable, Key: { id: eventId } }))
                .then(response => {
                    if (response.Item) {
                        return invokeApi("leases", "GET")
                            .then((leases) => {
                                if (leases.message) return respondWithError("Failed to list leases.", leases.message);
                    
                                let foundLease = leases.find((item) => item.principalId === principalId);
                                if (foundLease) {
                                    switch (foundLease.leaseStatus) {
                                        case "Active":
                                            return getLeaseLoginUrl(foundLease, user);
                                        case "Expired":
                                            return respondWithError(
                                                "Your AWS account has expired its lifetime and has been terminated now."
                                            );
                                        case "OverBudget":
                                            return respondWithError(
                                                "Your AWS account has reached its maximum budget and has been terminated now."
                                            );
                                        case "Inactive":
                                            return respondWithError("Your AWS account has been manually terminated.");
                                        default:
                                            return respondWithError("Your account is not available for logging in.");
                                    }
                                } else {
                                    if (leases.filter((lease) => lease.principalId.startsWith(eventId)).length >= response.Item.maxAccounts)
                                        return respondWithError("No more free AWS accounts available for this event.");
                                    return invokeApi("leases", "POST", {
                                        budgetAmount: response.Item.budgetAmount,
                                        expiresOn: moment
                                            .unix(response.Item.eventOn)
                                            .add(response.Item.eventDays, "days")
                                            .add(response.Item.eventHours, "hours")
                                            .unix(),
                                        principalId,
                                        budgetNotificationEmails: [user],
                                        budgetCurrency: "USD"
                                    })
                                        .then((newLease) => {
                                            if (newLease.error) {
                                                switch (newLease.error.code) {
                                                    case "ServerError":
                                                        if (newLease.error.message === "No Available accounts at this moment")
                                                            return respondWithError("No more free AWS accounts available.", newLease.error);
                                                        else
                                                            return respondWithError(
                                                                "Failed to create lease for " + user + ".",
                                                                newLease.error
                                                            );
                                                    case "AlreadyExistsError":
                                                        return respondWithError(
                                                            "Found already existing lease for " + user + ".",
                                                            newLease.error
                                                        );
                                                    default:
                                                        return respondWithError(
                                                            "Failed to create lease for " + user + ".",
                                                            newLease.error
                                                        );
                                                }
                                            }
                                            return getLeaseLoginUrl(newLease, user);
                                        })
                                        .catch((error) => respondWithError("Failed to create lease for " + user + ".", error));
                                }
                            })
                            .catch((error) => respondWithError("Failed to list leases.", error));
                
                    } else {
                            "Your EventId " + eventId + " is invalid. Please contact your event operator for help."
                    }
                .catch((error) => respondWithError("Failed to get data for event ID " + eventId + ".", error));
        .catch(error => respondWithError("Failed to get user authentication data, cannot claim an AWS account.", error))
exports.handler = async (event, context) => {
    console.log("Lambda invoked with the following parameters: ", event, context)
    let args = event.arguments

    
    if (!eventsTable) {
        const tables = await ddbClient.send(new ListTablesCommand())
        eventsTable = tables.TableNames.find(name => name.startsWith("Event-"))
    }

    if (!userPoolId) {
        const userPools = await cognitoClient.send(new ListUserPoolsCommand({ MaxResults: 10 }))
        userPoolId = userPools.UserPools.find(userPool => userPool.Name.startsWith("safeafe5208f")).Id
    }
            case "getEndUserEvent":
                return getEndUserEvent(params);
                return getAwsLoginUrlForEvent(params, event);
    },
    "moment": {
      "version": "2.29.4",
      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
    "aws4": "^1.11.0",
    "moment": "^2.29.4"
  "Description": "{\"createdOn\":\"Mac\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.7.1\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
        "Runtime": "nodejs18.x",
    },
    "LambdaExecutionRoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaExecutionRole",
          "Arn"
        ]
      }
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, UpdateCommand, DeleteCommand } = require('@aws-sdk/lib-dynamodb');

const ddbClient = new DynamoDBClient({ region });
const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);

    if (!user) 
        return respondWithError("Internal error while trying to update lease.", "Parameter 'user' missing.");

    return ddbDocClient
        .send(new UpdateCommand({
        }))
    return ddbDocClient
        .send(new DeleteCommand({
        }))
exports.handler = async (event, context) => {
    console.log("Lambda invoked with the following parameters: ", event, context)
    let args = event.arguments

  "api": {
    "AdminQueries": {
      "ApiId": "string",
      "ApiName": "string",
      "RootUrl": "string"
    "safegraphql": {
      "GraphQLAPIEndpointOutput": "string",
      "GraphQLAPIIdOutput": "string"
    }
  },
  "auth": {
    "safeafe5208f": {
      "AppClientID": "string",
      "AppClientIDWeb": "string",
      "IdentityPoolId": "string",
      "IdentityPoolName": "string",
      "UserPoolArn": "string",
      "UserPoolId": "string",
      "UserPoolName": "string"
    },
    "userPoolGroups": {
      "adminGroupRole": "string",
      "operatorGroupRole": "string"
    }
  },
  "custom": {
    "cfnAdminUser": {
      "AdminUserEmailAddress": "string"
    }
  },
  "function": {
    "AdminQueries4757b5b2": {
      "Arn": "string",
      "LambdaExecutionRole": "string",
      "LambdaExecutionRoleArn": "string",
      "Name": "string",
      "Region": "string"
    },
    "safeAdminApi": {
      "Arn": "string",
      "LambdaExecutionRole": "string",
      "LambdaExecutionRoleArn": "string",
      "Name": "string",
      "Region": "string"
    "safeLoginApi": {
      "Arn": "string",
      "LambdaExecutionRole": "string",
      "LambdaExecutionRoleArn": "string",
      "Name": "string",
      "Region": "string"
    "safeOperatorApi": {
      "Arn": "string",
      "LambdaExecutionRole": "string",
      "LambdaExecutionRoleArn": "string",
      "Name": "string",
      "Region": "string"
  }
      "useexperimentalpipelinedtransformer": true,
      "showfieldauthnotification": false,
      "transformerversion": 2,
      "suppressschemamigrationprompt": true,
      "securityEnhancementNotification": false
        if (authStatus === "authenticated" && user) {
      __typename
      __typename
      __typename
      __typename
      __typename
      __typename
  query SafeLoginApi($action: String, $paramJson: String) {
  query SafeAdminApi($action: String, $paramJson: String) {
  query SafeOperatorApi($action: String, $paramJson: String) {
      __typename
        __typename
      __typename
      __typename
        __typename
      __typename
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionEventFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Event",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onUpdateEvent",
          "description" : null,
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionEventFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Event",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onDeleteEvent",
          "description" : null,
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionEventFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Event",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onCreateConfig",
          "description" : null,
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionConfigFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Config",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onUpdateConfig",
          "description" : null,
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionConfigFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Config",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        }, {
          "name" : "onDeleteConfig",
          "description" : null,
          "args" : [ {
            "name" : "filter",
            "description" : null,
            "type" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionConfigFilterInput",
              "ofType" : null
            },
            "defaultValue" : null
          } ],
          "type" : {
            "kind" : "OBJECT",
            "name" : "Config",
            "ofType" : null
          },
          "isDeprecated" : false,
          "deprecationReason" : null
        } ],
        "inputFields" : null,
        "interfaces" : [ ],
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionEventFilterInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "id",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIDInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventName",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionStringInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventOn",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIntInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventDays",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIntInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventHours",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIntInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventOwner",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionStringInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "maxAccounts",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIntInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventBudget",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIntInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eventStatus",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionStringInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "and",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionEventFilterInput",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "or",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionEventFilterInput",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionIDInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "ne",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eq",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "le",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "lt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "ge",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "gt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "contains",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "notContains",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "between",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "ID",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "beginsWith",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "ID",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "in",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "ID",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "notIn",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "ID",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionStringInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "ne",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eq",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "le",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "lt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "ge",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "gt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "contains",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "notContains",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "between",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "String",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "beginsWith",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "in",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "String",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "notIn",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "String",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionIntInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "ne",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "eq",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "le",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "lt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "ge",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "gt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Int",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "between",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Int",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "in",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Int",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "notIn",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Int",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionConfigFilterInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "id",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionIDInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "config",
          "description" : null,
          "type" : {
            "kind" : "INPUT_OBJECT",
            "name" : "ModelSubscriptionStringInput",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "and",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionConfigFilterInput",
              "ofType" : null
            }
          },
          "defaultValue" : null
        }, {
          "name" : "or",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "INPUT_OBJECT",
              "name" : "ModelSubscriptionConfigFilterInput",
              "ofType" : null
            }
          },
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelSubscriptionBooleanInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "ne",
          "description" : null,
            "kind" : "SCALAR",
            "name" : "Boolean",
          "defaultValue" : null
          "name" : "eq",
            "kind" : "SCALAR",
            "name" : "Boolean",
          "defaultValue" : null
        } ],
        "interfaces" : null,
        "enumValues" : null,
        "possibleTypes" : null
      }, {
        "kind" : "INPUT_OBJECT",
        "name" : "ModelBooleanInput",
        "description" : null,
        "fields" : null,
        "inputFields" : [ {
          "name" : "ne",
            "kind" : "SCALAR",
            "name" : "Boolean",
          "defaultValue" : null
          "name" : "eq",
            "kind" : "SCALAR",
            "name" : "Boolean",
          "defaultValue" : null
          "name" : "attributeExists",
            "kind" : "SCALAR",
            "name" : "Boolean",
          "defaultValue" : null
          "name" : "attributeType",
            "kind" : "ENUM",
            "name" : "ModelAttributeTypes",
          "defaultValue" : null
        "interfaces" : null,
        "name" : "ModelSubscriptionFloatInput",
          "name" : "in",
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Float",
              "ofType" : null
            }
          "name" : "notIn",
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Float",
              "ofType" : null
            }
        "name" : "ModelFloatInput",
            "name" : "Float",
            "name" : "Float",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "le",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Float",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "lt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Float",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "ge",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Float",
            "ofType" : null
          },
          "defaultValue" : null
        }, {
          "name" : "gt",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "Float",
        }, {
          "name" : "between",
          "description" : null,
          "type" : {
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "Float",
              "ofType" : null
            }
          },
          "defaultValue" : null
        "name" : "aws_cognito_user_pools",
        "description" : "Tells the service this field/object has access authorized by a Cognito User Pools token.",
        "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
          "name" : "cognito_groups",
          "description" : "List of cognito user pool groups which have access on this field",
            "kind" : "LIST",
            "name" : null,
            "ofType" : {
              "kind" : "SCALAR",
              "name" : "String",
              "ofType" : null
            }
          "defaultValue" : null
        "name" : "aws_publish",
        "description" : "Tells the service which subscriptions will be published to when this mutation is called. This directive is deprecated use @aws_susbscribe directive instead.",
        "locations" : [ "FIELD_DEFINITION" ],
          "name" : "subscriptions",
          "description" : "List of subscriptions which will be published to when this mutation is called.",
      }, {
        "name" : "aws_api_key",
        "description" : "Tells the service this field/object has access authorized by an API key.",
        "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
        "args" : [ ],
        "onOperation" : false,
        "onFragment" : false,
        "onField" : false
        "name" : "aws_subscribe",
        "description" : "Tells the service which mutation triggers this subscription.",
          "name" : "mutations",
          "description" : "List of mutations which will trigger this subscription when they are called.",
        "name" : "aws_lambda",
        "description" : "Tells the service this field/object has access authorized by a Lambda Authorizer.",
        "name" : "aws_iam",
        "description" : "Tells the service this field/object has access authorized by sigv4 signing.",
      }, {
        "name" : "deprecated",
        "description" : null,
        "locations" : [ "FIELD_DEFINITION", "ENUM_VALUE" ],
        "args" : [ {
          "name" : "reason",
          "description" : null,
          "type" : {
            "kind" : "SCALAR",
            "name" : "String",
            "ofType" : null
          },
          "defaultValue" : "\"No longer supported\""
        } ],
        "onOperation" : false,
        "onFragment" : false,
        "onField" : false
  subscription OnCreateEvent($filter: ModelSubscriptionEventFilterInput) {
    onCreateEvent(filter: $filter) {
      __typename
  subscription OnUpdateEvent($filter: ModelSubscriptionEventFilterInput) {
    onUpdateEvent(filter: $filter) {
      __typename
  subscription OnDeleteEvent($filter: ModelSubscriptionEventFilterInput) {
    onDeleteEvent(filter: $filter) {
      __typename
  subscription OnCreateConfig($filter: ModelSubscriptionConfigFilterInput) {
    onCreateConfig(filter: $filter) {
      __typename
  subscription OnUpdateConfig($filter: ModelSubscriptionConfigFilterInput) {
    onUpdateConfig(filter: $filter) {
      __typename
  subscription OnDeleteConfig($filter: ModelSubscriptionConfigFilterInput) {
    onDeleteConfig(filter: $filter) {
      __typename
                            {Item.eventBudget + " USD"}
                            {Item.eventSpend + " USD"}
                        cell: (item) => item.eventSpend + " USD"
                    {item.eventBudget + " USD"}
                    {item.eventSpend + " USD"}
                    cell: (item) => item.costAmount.toFixed(2) + " USD"
                        <Container header={<Header>AWS service spend in USD</Header>}>
import { fetchAwsLoginUrl, getEndUserEvent } from "../../redux/actions/aws_login";
        dispatch({ type: "aws_login/event_dismiss" });
        dispatch(getEndUserEvent(value));
        if (!valueChangedOnce && isEmpty(AwsLogin.event) && urlParamEventId && User.isLoggedIn) {
            dispatch(getEndUserEvent(urlParamEventId));
    }, [AwsLogin.event, urlParamEventId, dispatch, valueChangedOnce, User]);
        if (!AwsLogin.event.eventStatus) return;
        switch (AwsLogin.event.eventStatus) {
    }, [AwsLogin.event, dispatch]);
        dispatch({ type: "aws_login/event_dismiss" });
                {!AwsLogin.event.id ? (
                        <Button variant="primary" onClick={submit} loading={AwsLogin.event_status === "loading"}>
                            Welcome to "{AwsLogin.event.eventName}"
                            onClick={() => dispatch(fetchAwsLoginUrl({ eventId: AwsLogin.event.id })) }
                        label={"Budget in USD"}
            let user = newValue.user.replace(/[^a-zA-Z0-9]/g, "+");
                newValue.principalId = newValue.eventId + "__" + user;
                        label={"Budget in USD"}
                            label={"Budget in USD"}
                            label={"Budget in USD"}
    event_status: "idle",
    url: "",
    event: {}
            return {
                ...state,
                url: "",
                status: "hidden"
            };
                
        case "aws_login/event_loading":
            return {
                ...state,
                event_status: "loading"
            };
        case "aws_login/event_loaded":
            return {
                ...state,
                event_status: "idle",
                event: action.payload
            };
        case "aws_login/event_loadError":
        case "aws_login/event_dismiss":
export const getEndUserEvent = (id) => async (dispatch) => {
    dispatch({ type: "aws_login/event_loading" });
    try {
        const response = await API.graphql(
            graphqlOperation(queries.safeLoginApi, {
                action: "getEndUserEvent",
                paramJson: JSON.stringify({id})
            })
        );
        const payload = JSON.parse(response.data.safeLoginApi);
        if (!payload || payload.status === "error") {
            throw payload;
        }
        dispatch({ type: "aws_login/event_loaded", payload: payload.body });
        dispatch({ type: "notification/dismiss" });
    } catch (error) {
        console.error(error);
        dispatch({ type: "aws_login/event_loadError" });
        dispatch({ type: "notification/error", message: error.message });
    }
};


    if (!data.attributes)
        return
        case "event/loading":
            new RegExp("^(" + action.config.EVENT_ID_REGEX + ")__\\S{5,}$")
                        budgetCurrency: "USD"
        eventId: item.principalId.includes("__") ? item.principalId.substring(0, action.config.EVENT_ID_LENGTH) : ""