diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0529ee008..fa8a8b439 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 with: install-mode: "goinstall" - version: 2059b18a39d559552839476ba78ce6acaa499b43 # v1.59.0 + version: v1.59.0 args: -v -c .golangci.yml unit-tests: diff --git a/CHANGELOG.md b/CHANGELOG.md index d171dae1e..596040e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +# [v.1.7.0](https://github.com/auth0/auth0-cli/tree/v1.7.0) (Dec 9, 2024)) + +[Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.6.1...v1.7.0) + +### Added + +- Support for importing `auth0_prompt_screen_renderer` terraform resource [#1106] + +### Fixed + +- For `ul login` added check to filter and identify only support partials. [#1107] + +# [v1.6.1](https://github.com/auth0/auth0-cli/tree/v1.6.1) (Oct 31, 2024) + +[Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.6.0...v1.6.1) + +### Added + +- Added new flag (`tf-version`) to pass terraform version during `auth0 tf generate` command [#1098] + +### Removed + +- Removed iga-* triggers from triggerActionsResourceFetcher [#1099] + # [v1.6.0](https://github.com/auth0/auth0-cli/tree/v1.6.0) (Oct 17, 2024) [Full Changelog](https://github.com/auth0/auth0-cli/compare/v1.5.1...v1.6.0) @@ -315,6 +339,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updating of action triggers which inevitably results in error [#597] [unreleased]: https://github.com/auth0/auth0-cli/compare/v1.5.1...HEAD +[#1107]: https://github.com/auth0/auth0-cli/issues/1107 +[#1106]: https://github.com/auth0/auth0-cli/issues/1106 +[#1099]: https://github.com/auth0/auth0-cli/issues/1099 +[#1098]: https://github.com/auth0/auth0-cli/issues/1098 [#1091]: https://github.com/auth0/auth0-cli/issues/1091 [#1084]: https://github.com/auth0/auth0-cli/issues/1084 [#1083]: https://github.com/auth0/auth0-cli/issues/1083 diff --git a/Makefile b/Makefile index ada75aec7..328723e21 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ $(GO_BIN)/mockgen: $(GO_BIN)/golangci-lint: ${call print, "Installing golangci-lint"} - @go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@2059b18a39d559552839476ba78ce6acaa499b43 # v1.59.0 + @go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0 $(GO_BIN)/govulncheck: ${call print, "Installing go vulnerability checker"} diff --git a/docs/auth0_terraform_generate.md b/docs/auth0_terraform_generate.md index 02a4232a6..d6d5cba4a 100644 --- a/docs/auth0_terraform_generate.md +++ b/docs/auth0_terraform_generate.md @@ -33,7 +33,8 @@ auth0 terraform generate [flags] ``` --force Skip confirmation. -o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") - -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_flow,auth0_flow_vault_connection,auth0_form,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) + -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_flow,auth0_flow_vault_connection,auth0_form,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_prompt_screen_renderer,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) + -v, --tf-version string Terraform version that ought to be used while generating the terraform files for resources. If not provided, 1.5.0 is used by default (default "1.5.0") ``` diff --git a/docs/auth0_universal-login.md b/docs/auth0_universal-login.md index 45468c0a3..998587360 100644 --- a/docs/auth0_universal-login.md +++ b/docs/auth0_universal-login.md @@ -9,7 +9,7 @@ Manage a consistent, branded Universal Login experience that can handle all of y ## Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_customize.md b/docs/auth0_universal-login_customize.md index 727ad77ed..12a844cc1 100644 --- a/docs/auth0_universal-login_customize.md +++ b/docs/auth0_universal-login_customize.md @@ -5,7 +5,19 @@ has_toc: false --- # auth0 universal-login customize -Customize and preview changes to the Universal Login experience. This command will open a webpage within your browser where you can edit and preview your branding changes. For a comprehensive list of editable parameters and their values please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2). + +Customize your Universal Login Experience. Note that this requires a custom domain to be configured for the tenant. + +* Standard mode is recommended for creating a consistent, branded experience for users. Choosing Standard mode will open a webpage +within your browser where you can edit and preview your branding changes.For a comprehensive list of editable parameters and their values, +please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2) + +* Advanced mode is recommended for full customization/granular control of the login experience and to integrate your own component design system. +Choosing Advanced mode will open the default terminal editor, with the rendering configs: + +![storybook](settings.json) + +Closing the terminal editor will save the settings to your tenant. ## Usage ``` @@ -34,7 +46,7 @@ auth0 universal-login customize [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_show.md b/docs/auth0_universal-login_show.md index 53ab7fe33..896447d7a 100644 --- a/docs/auth0_universal-login_show.md +++ b/docs/auth0_universal-login_show.md @@ -40,7 +40,7 @@ auth0 universal-login show [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/docs/auth0_universal-login_update.md b/docs/auth0_universal-login_update.md index 30349e800..2548b2408 100644 --- a/docs/auth0_universal-login_update.md +++ b/docs/auth0_universal-login_update.md @@ -50,7 +50,7 @@ auth0 universal-login update [flags] ## Related Commands -- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience +- [auth0 universal-login customize](auth0_universal-login_customize.md) - Customize the Universal Login experience for the standard or advanced mode - [auth0 universal-login prompts](auth0_universal-login_prompts.md) - Manage custom text for prompts - [auth0 universal-login show](auth0_universal-login_show.md) - Display the custom branding settings for Universal Login - [auth0 universal-login templates](auth0_universal-login_templates.md) - Manage custom Universal Login templates diff --git a/go.mod b/go.mod index 04b9cc544..597d95486 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ replace github.com/mholt/archiver/v3 => github.com/anchore/archiver/v3 v3.5.2 require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 - github.com/auth0/go-auth0 v1.11.0 + github.com/auth0/go-auth0 v1.13.0 github.com/briandowns/spinner v1.23.1 github.com/charmbracelet/glamour v0.8.0 github.com/fsnotify/fsnotify v1.7.0 @@ -31,16 +31,16 @@ require ( github.com/schollz/progressbar/v3 v3.16.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/tidwall/pretty v1.2.1 github.com/zalando/go-keyring v0.2.6 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.23.0 - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.26.0 - golang.org/x/term v0.25.0 - golang.org/x/text v0.19.0 + golang.org/x/oauth2 v0.24.0 + golang.org/x/sync v0.9.0 + golang.org/x/sys v0.27.0 + golang.org/x/term v0.26.0 + golang.org/x/text v0.20.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -94,7 +94,7 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/zclconf/go-cty v1.14.4 // indirect - golang.org/x/crypto v0.28.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect diff --git a/go.sum b/go.sum index fd2048b7f..462b40822 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/auth0/go-auth0 v1.11.0 h1:gFBVhJCQUW1cET+f/fSH+aXiUebvH2IaaXhMiSaPclw= -github.com/auth0/go-auth0 v1.11.0/go.mod h1:VyYseHsdB4s9jmfBqoxnzJTvZr0w17ZJ5kjNdA+ag9Y= +github.com/auth0/go-auth0 v1.13.0 h1:GA7WyGAzlKBQ2ctHcCZwVf0aiOvPd2PB3QagC5heQJg= +github.com/auth0/go-auth0 v1.13.0/go.mod h1:G3oPT7sWjmM4mHbn6qkMYEsxnwm/5PnSbo0kpPLSS0E= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -229,8 +229,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -255,8 +255,8 @@ github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgr golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -271,13 +271,13 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -291,19 +291,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 5e354133d..0947600e5 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -130,6 +130,7 @@ var RequiredScopes = []string{ "read:branding", "update:branding", "read:email_templates", "update:email_templates", "read:email_provider", + "read:flows", "read:forms", "read:flows_vault_connections", "read:connections", "update:connections", "read:client_keys", "read:logs", "read:tenant_settings", "read:custom_domains", "create:custom_domains", "update:custom_domains", "delete:custom_domains", diff --git a/internal/auth0/branding_prompt.go b/internal/auth0/branding_prompt.go index 8fe393f54..259d5c837 100644 --- a/internal/auth0/branding_prompt.go +++ b/internal/auth0/branding_prompt.go @@ -38,4 +38,14 @@ type PromptAPI interface { // // See: https://auth0.com/docs/api/management/v2/prompts/put-partials SetPartials(ctx context.Context, prompt management.PromptType, c *management.PromptScreenPartials, opts ...management.RequestOption) error + + // ReadRendering retrieves the settings for the ACUL. + // + // See: https://auth0.com/docs/api/management/v2/prompts/get-rendering + ReadRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, opts ...management.RequestOption) (c *management.PromptRendering, err error) + + // UpdateRendering updates the settings for the ACUL. + // + // See: https://auth0.com/docs/api/management/v2/prompts/patch-rendering + UpdateRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, c *management.PromptRendering, opts ...management.RequestOption) error } diff --git a/internal/auth0/mock/branding_prompt_mock.go b/internal/auth0/mock/branding_prompt_mock.go index edf76e37b..70b12051e 100644 --- a/internal/auth0/mock/branding_prompt_mock.go +++ b/internal/auth0/mock/branding_prompt_mock.go @@ -95,6 +95,26 @@ func (mr *MockPromptAPIMockRecorder) Read(ctx interface{}, opts ...interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockPromptAPI)(nil).Read), varargs...) } +// ReadRendering mocks base method. +func (m *MockPromptAPI) ReadRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, opts ...management.RequestOption) (*management.PromptRendering, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, prompt, screen} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ReadRendering", varargs...) + ret0, _ := ret[0].(*management.PromptRendering) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadRendering indicates an expected call of ReadRendering. +func (mr *MockPromptAPIMockRecorder) ReadRendering(ctx, prompt, screen interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, prompt, screen}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadRendering", reflect.TypeOf((*MockPromptAPI)(nil).ReadRendering), varargs...) +} + // SetCustomText mocks base method. func (m *MockPromptAPI) SetCustomText(ctx context.Context, p, l string, b map[string]interface{}, opts ...management.RequestOption) error { m.ctrl.T.Helper() @@ -151,3 +171,22 @@ func (mr *MockPromptAPIMockRecorder) Update(ctx, p interface{}, opts ...interfac varargs := append([]interface{}{ctx, p}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockPromptAPI)(nil).Update), varargs...) } + +// UpdateRendering mocks base method. +func (m *MockPromptAPI) UpdateRendering(ctx context.Context, prompt management.PromptType, screen management.ScreenName, c *management.PromptRendering, opts ...management.RequestOption) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, prompt, screen, c} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "UpdateRendering", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateRendering indicates an expected call of UpdateRendering. +func (mr *MockPromptAPIMockRecorder) UpdateRendering(ctx, prompt, screen, c interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, prompt, screen, c}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRendering", reflect.TypeOf((*MockPromptAPI)(nil).UpdateRendering), varargs...) +} diff --git a/internal/cli/data/universal-login/prompt-screen-settings.json b/internal/cli/data/universal-login/prompt-screen-settings.json new file mode 100644 index 000000000..d6b4ed4af --- /dev/null +++ b/internal/cli/data/universal-login/prompt-screen-settings.json @@ -0,0 +1,33 @@ +{ + "__doc1__": "The rendering_mode could be either advanced or standard... default_head_tags_disabled is a toggle to override Universal Login default head tags... context_configuration are the set of Context values to make available(Refer docs for the possible values)... head_tags are the array of head tags)..", + "__doc2__": "Note1: while updating the rendering_mode to standard, only the rendering_mode field gets updated, the other fields shall not be updated.", + "__doc3__": "Note2: head_tags must contain at least one script tag", + "__doc4__": "Only the declared fields get updated, rest stays same", + "__doc5__": "See https://auth0.com/docs/customize/login-pages/advanced-customizations/getting-started/configure-acul-screens for all possible values for each field", + + "rendering_mode": "advanced", + "default_head_tags": false, + "context_configuration": [ + "screen.texts" + ], + "head_tags": [ + { + "tag": "script", + "attributes": { + "defer": true, + "src": "URL_TO_YOUR_ASSET", + "async": true, + "integrity": [ + "ASSET_SHA" + ] + } + }, + { + "tag": "link", + "attributes": { + "href": "URL_TO_YOUR_ASSET", + "rel": "stylesheet" + } + } + ] +} \ No newline at end of file diff --git a/internal/cli/prompts_custom_text.go b/internal/cli/prompts_custom_text.go index c201c1f27..5832f6ee8 100644 --- a/internal/cli/prompts_custom_text.go +++ b/internal/cli/prompts_custom_text.go @@ -15,7 +15,7 @@ import ( const ( textDocsKey = "__doc__" textDocsURL = "https://auth0.com/docs/customize/universal-login-pages/customize-login-text-prompts" - textLocalesURL = "https://cdn.auth0.com/ulp/react-components/1.66.3/languages/%s/prompts.json" + textLocalesURL = "https://cdn.auth0.com/ulp/react-components/1.102.1/languages/%s/prompts.json" textLanguageDefault = "en" ) diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index 973633b28..bfc4ff0dd 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -38,17 +38,26 @@ var tfFlags = terraformFlags{ Help: "Resource types to generate Terraform config for. If not provided, config files for all " + "available resources will be generated.", }, + TerraformVersion: Flag{ + Name: "Terraform Version", + LongForm: "tf-version", + ShortForm: "v", + Help: "Terraform version that ought to be used while generating the terraform files for resources. " + + "If not provided, 1.5.0 is used by default", + }, } type ( terraformFlags struct { - OutputDIR Flag - Resources Flag + OutputDIR Flag + Resources Flag + TerraformVersion Flag } terraformInputs struct { - OutputDIR string - Resources []string + OutputDIR string + Resources []string + TerraformVersion string } ) @@ -94,6 +103,8 @@ func (i *terraformInputs) parseResourceFetchers(api *auth0.API) ([]resourceDataF fetchers = append(fetchers, &promptResourceFetcher{}) case "auth0_prompt_custom_text": fetchers = append(fetchers, &promptCustomTextResourceFetcherResourceFetcher{api}) + case "auth0_prompt_screen_renderer": + fetchers = append(fetchers, &promptScreenRendererResourceFetcher{api}) case "auth0_resource_server", "auth0_resource_server_scopes": fetchers = append(fetchers, &resourceServerResourceFetcher{api}) case "auth0_role", "auth0_role_permissions": @@ -147,6 +158,7 @@ func generateTerraformCmd(cli *cli) *cobra.Command { cmd.Flags().BoolVar(&cli.force, "force", false, "Skip confirmation.") tfFlags.OutputDIR.RegisterString(cmd, &inputs.OutputDIR, "./") tfFlags.Resources.RegisterStringSlice(cmd, &inputs.Resources, defaultResources) + tfFlags.TerraformVersion.RegisterString(cmd, &inputs.TerraformVersion, "1.5.0") return cmd } @@ -175,7 +187,7 @@ func generateTerraformCmdRun(cli *cli, inputs *terraformInputs) func(cmd *cobra. return err } - if err := generateTerraformImportConfig(inputs.OutputDIR, data); err != nil { + if err := generateTerraformImportConfig(inputs, data); err != nil { return err } @@ -191,7 +203,7 @@ func generateTerraformCmdRun(cli *cli, inputs *terraformInputs) func(cmd *cobra. } err = ansi.Spinner("Generating Terraform configuration", func() error { - return generateTerraformResourceConfig(cmd.Context(), inputs.OutputDIR) + return generateTerraformResourceConfig(cmd.Context(), inputs) }) if err != nil { @@ -241,20 +253,20 @@ func fetchImportData(ctx context.Context, fetchers ...resourceDataFetcher) (impo return deduplicateResourceNames(importData), nil } -func generateTerraformImportConfig(outputDIR string, data importDataList) error { +func generateTerraformImportConfig(inputs *terraformInputs, data importDataList) error { if len(data) == 0 { return errors.New("no import data available") } - if err := createOutputDirectory(outputDIR); err != nil { + if err := createOutputDirectory(inputs.OutputDIR); err != nil { return err } - if err := createMainFile(outputDIR); err != nil { + if err := createMainFile(inputs); err != nil { return err } - return createImportFile(outputDIR, data) + return createImportFile(inputs.OutputDIR, data) } func createOutputDirectory(outputDIR string) error { @@ -267,8 +279,8 @@ func createOutputDirectory(outputDIR string) error { return nil } -func createMainFile(outputDIR string) error { - filePath := path.Join(outputDIR, "auth0_main.tf") +func createMainFile(input *terraformInputs) error { + filePath := path.Join(input.OutputDIR, "auth0_main.tf") file, err := os.Create(filePath) if err != nil { @@ -279,7 +291,7 @@ func createMainFile(outputDIR string) error { }() fileContent := `terraform { - required_version = ">= 1.5.0" + required_version = ">= ` + input.TerraformVersion + `" required_providers { auth0 = { source = "auth0/auth0" @@ -327,15 +339,15 @@ import { return t.Execute(file, data) } -func generateTerraformResourceConfig(ctx context.Context, outputDIR string) error { - absoluteOutputPath, err := filepath.Abs(outputDIR) +func generateTerraformResourceConfig(ctx context.Context, input *terraformInputs) error { + absoluteOutputPath, err := filepath.Abs(input.OutputDIR) if err != nil { return err } installer := &releases.ExactVersion{ Product: product.Terraform, - Version: version.Must(version.NewVersion("1.5.0")), + Version: version.Must(version.NewVersion(input.TerraformVersion)), InstallDir: absoluteOutputPath, } diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index c908b7b8c..7de5a0944 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -11,7 +11,21 @@ import ( "github.com/auth0/auth0-cli/internal/auth0" ) -var defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_flow", "auth0_flow_vault_connection", "auth0_form", "auth0_email_provider", "auth0_email_template", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} +var ( + defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_flow", "auth0_flow_vault_connection", "auth0_form", "auth0_email_provider", "auth0_email_template", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_prompt_screen_renderer", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} + ScreenPromptMap = map[string][]string{ + "signup-id": {"signup-id"}, + "signup-password": {"signup-password"}, + "login-id": {"login-id"}, + "login-password": {"login-password"}, + "login-passwordless": {"login-passwordless-email-code", "login-passwordless-sms-otp"}, + "phone-identifier-enrollment": {"phone-identifier-enrollment"}, + "phone-identifier-challenge": {"phone-identifier-challenge"}, + "email-identifier-challenge": {"email-identifier-challenge"}, + "passkeys": {"passkey-enrollment", "passkey-enrollment-local"}, + "captcha": {"interstitial-captcha"}, + } +) type ( importDataList []importDataItem @@ -83,7 +97,10 @@ type ( api *auth0.API } - promptResourceFetcher struct{} + promptResourceFetcher struct{} + promptScreenRendererResourceFetcher struct { + api *auth0.API + } promptCustomTextResourceFetcherResourceFetcher struct { api *auth0.API @@ -227,10 +244,16 @@ func (f *customDomainResourceFetcher) FetchData(ctx context.Context) (importData customDomains, err := f.api.CustomDomain.List(ctx) if err != nil { - if strings.Contains(err.Error(), "The account is not allowed to perform this operation, please contact our support team") { - return data, nil + errNotEnabled := []string{ + "The account is not allowed to perform this operation, please contact our support team", + "There must be a verified credit card on file to perform this operation", } + for _, e := range errNotEnabled { + if strings.Contains(err.Error(), e) { + return data, nil + } + } return nil, err } @@ -448,6 +471,31 @@ func (f *promptCustomTextResourceFetcherResourceFetcher) FetchData(ctx context.C return data, nil } +func (f *promptScreenRendererResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { + var data importDataList + + _, err := f.api.Prompt.ReadRendering(ctx, "login-id", "login-id") + // Checking for the ACUL enabled feature. + if err != nil { + if strings.Contains(err.Error(), "403 Forbidden: This tenant does not have Advanced Customizations enabled") { + return nil, nil + } + + return nil, err + } + + for promptType, screenNames := range ScreenPromptMap { + for _, screenName := range screenNames { + data = append(data, importDataItem{ + ResourceName: "auth0_prompt_screen_renderer." + sanitizeResourceName(promptType+"_"+screenName), + ImportID: promptType + ":" + screenName, + }) + } + } + + return data, nil +} + func (f *resourceServerResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { var data importDataList @@ -543,7 +591,7 @@ func (f *tenantResourceFetcher) FetchData(_ context.Context) (importDataList, er func (f *triggerActionsResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { var data importDataList - triggers := []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge", "iga-approval", "iga-certification", "iga-fulfillment-assignment", "iga-fulfillment-execution"} + triggers := []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge"} for _, trigger := range triggers { res, err := f.api.Action.Bindings(ctx, trigger) diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index 9b6dda9cf..0c7c75061 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -561,6 +561,26 @@ func TestCustomDomainResourceFetcher_FetchData(t *testing.T) { assert.NoError(t, err) assert.Len(t, data, 0) }) + + t.Run("it returns empty set error if no verified CC error occurs", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + customDomainAPI := mock.NewMockCustomDomainAPI(ctrl) + customDomainAPI.EXPECT(). + List(gomock.Any()). + Return(nil, fmt.Errorf("403 Forbidden: There must be a verified credit card on file to perform this operation")) + + fetcher := customDomainResourceFetcher{ + api: &auth0.API{ + CustomDomain: customDomainAPI, + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 0) + }) } func TestFormResourceFetcher_FetchData(t *testing.T) { @@ -1288,6 +1308,72 @@ func TestPromptProviderResourceFetcher_FetchData(t *testing.T) { }) } +func TestPromptScreenRendererResourceFetcher_FetchData(t *testing.T) { + t.Run("it successfully renders the prompts & screen settings import data", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, nil) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + expectedData := importDataList{} + for promptType, screenNames := range ScreenPromptMap { + for _, screenName := range screenNames { + expectedData = append(expectedData, importDataItem{ + ResourceName: "auth0_prompt_screen_renderer." + sanitizeResourceName(promptType+"_"+screenName), + ImportID: promptType + ":" + screenName, + }) + } + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.ElementsMatch(t, expectedData, data) + }) + t.Run("it handles error, even if tenant does not have ACUL enabled", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, fmt.Errorf("403 Forbidden: This tenant does not have Advanced Customizations enabled")) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 0) + }) + t.Run("it returns error, if the API call fails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + promptAPI := mock.NewMockPromptAPI(ctrl) + promptAPI.EXPECT().ReadRendering(gomock.Any(), management.PromptType("login-id"), management.ScreenName("login-id")). + Return(&management.PromptRendering{}, fmt.Errorf("failed to read rendering settings")) + + fetcher := promptScreenRendererResourceFetcher{ + api: &auth0.API{ + Prompt: promptAPI, + }, + } + + _, err := fetcher.FetchData(context.Background()) + assert.EqualError(t, err, "failed to read rendering settings") + }) +} + func TestPromptCustomTextResourceFetcher_FetchData(t *testing.T) { t.Run("it successfully retrieves custom text prompts data", func(t *testing.T) { ctrl := gomock.NewController(t) @@ -1658,7 +1744,7 @@ func TestTriggerActionsResourceFetcher_FetchData(t *testing.T) { defer ctrl.Finish() actionAPI := mock.NewMockActionAPI(ctrl) - for _, trigger := range []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge", "iga-approval", "iga-certification", "iga-fulfillment-assignment", "iga-fulfillment-execution"} { + for _, trigger := range []string{"post-login", "credentials-exchange", "pre-user-registration", "post-user-registration", "post-change-password", "send-phone-message", "password-reset-post-challenge"} { bindings := []*management.ActionBinding{} if trigger == "pre-user-registration" { diff --git a/internal/cli/terraform_test.go b/internal/cli/terraform_test.go index fe499c9f4..9fcef3ec6 100644 --- a/internal/cli/terraform_test.go +++ b/internal/cli/terraform_test.go @@ -79,78 +79,78 @@ func TestFetchImportData(t *testing.T) { func TestGenerateTerraformImportConfig(t *testing.T) { t.Run("it can correctly generate the terraform config files", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig(outputDIR, importData) + err := generateTerraformImportConfig(&input, importData) require.NoError(t, err) - assertTerraformMainFileWasGeneratedCorrectly(t, outputDIR) - assertTerraformImportFileWasGeneratedCorrectly(t, outputDIR, importData) + assertTerraformMainFileWasGeneratedCorrectly(t, input.OutputDIR) + assertTerraformImportFileWasGeneratedCorrectly(t, input.OutputDIR, importData) }) t.Run("it can correctly generate the terraform main config file even if the dir exists", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) require.NoError(t, err) - assertTerraformMainFileWasGeneratedCorrectly(t, outputDIR) - assertTerraformImportFileWasGeneratedCorrectly(t, outputDIR, importData) + assertTerraformMainFileWasGeneratedCorrectly(t, input.OutputDIR) + assertTerraformImportFileWasGeneratedCorrectly(t, input.OutputDIR, importData) }) t.Run("it fails to generate the terraform config files if there's no import data", func(t *testing.T) { - outputDIR, _ := setupTestDIRAndImportData(t) + input, _ := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig(outputDIR, importDataList{}) + err := generateTerraformImportConfig(&input, importDataList{}) assert.EqualError(t, err, "no import data available") }) t.Run("it fails to create the directory if path is empty", func(t *testing.T) { _, importData := setupTestDIRAndImportData(t) - err := generateTerraformImportConfig("", importData) + err := generateTerraformImportConfig(&terraformInputs{OutputDIR: ""}, importData) assert.EqualError(t, err, "mkdir : no such file or directory") }) t.Run("it fails to create the main.tf file if file is already created and read only", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - mainFilePath := path.Join(outputDIR, "auth0_main.tf") + mainFilePath := path.Join(input.OutputDIR, "auth0_main.tf") _, err = os.Create(mainFilePath) require.NoError(t, err) err = os.Chmod(mainFilePath, 0444) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) assert.EqualError(t, err, fmt.Sprintf("open %s: permission denied", mainFilePath)) }) t.Run("it fails to create the auth0_import.tf file if file is already created and read only", func(t *testing.T) { - outputDIR, importData := setupTestDIRAndImportData(t) + input, importData := setupTestDIRAndImportData(t) - err := os.MkdirAll(outputDIR, 0755) + err := os.MkdirAll(input.OutputDIR, 0755) require.NoError(t, err) - importFilePath := path.Join(outputDIR, "auth0_import.tf") + importFilePath := path.Join(input.OutputDIR, "auth0_import.tf") _, err = os.Create(importFilePath) require.NoError(t, err) err = os.Chmod(importFilePath, 0444) require.NoError(t, err) - err = generateTerraformImportConfig(outputDIR, importData) + err = generateTerraformImportConfig(&input, importData) assert.EqualError(t, err, fmt.Sprintf("open %s: permission denied", importFilePath)) }) } -func setupTestDIRAndImportData(t *testing.T) (string, importDataList) { +func setupTestDIRAndImportData(t *testing.T) (terraformInputs, importDataList) { dirPath, err := os.MkdirTemp("", "terraform-*") require.NoError(t, err) @@ -179,7 +179,12 @@ func setupTestDIRAndImportData(t *testing.T) (string, importDataList) { }, } - return outputDIR, importData + input := terraformInputs{ + outputDIR, + nil, + "1.5.0", + } + return input, importData } func assertTerraformMainFileWasGeneratedCorrectly(t *testing.T, outputDIR string) { diff --git a/internal/cli/universal_login_customize.go b/internal/cli/universal_login_customize.go index 50330d813..b1f4ea9a9 100644 --- a/internal/cli/universal_login_customize.go +++ b/internal/cli/universal_login_customize.go @@ -13,13 +13,16 @@ import ( "time" "github.com/auth0/go-auth0/management" + "github.com/gorilla/websocket" "github.com/pkg/browser" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/display" + "github.com/auth0/auth0-cli/internal/prompt" ) const ( @@ -38,6 +41,9 @@ const ( var ( //go:embed data/universal-login/* universalLoginPreviewAssets embed.FS + + //go:embed data/universal-login/prompt-screen-settings.json + promptScreenSettings string ) var allowedPromptsWithPartials = []management.PromptType{ @@ -179,14 +185,34 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { cmd := &cobra.Command{ Use: "customize", Args: cobra.NoArgs, - Short: "Customize the Universal Login experience", - Long: "Customize and preview changes to the Universal Login experience. This command will open a webpage " + - "within your browser where you can edit and preview your branding changes. For a comprehensive list of " + - "editable parameters and their values please visit the " + - "[Management API Documentation](https://auth0.com/docs/api/management/v2).", + Short: "Customize the Universal Login experience for the standard or advanced mode", + Long: "\nCustomize your Universal Login Experience. Note that this requires a custom domain to be configured for the tenant. \n\n" + + "* Standard mode is recommended for creating a consistent, branded experience for users. Choosing Standard mode will open a webpage\n" + + "within your browser where you can edit and preview your branding changes.For a comprehensive list of editable parameters and their values,\n" + + "please visit the [Management API Documentation](https://auth0.com/docs/api/management/v2)\n\n" + + "* Advanced mode is recommended for full customization/granular control of the login experience and to integrate your own component design system. \n" + + "Choosing Advanced mode will open the default terminal editor, with the rendering configs:\n\n" + + "![storybook](settings.json)\n\nClosing the terminal editor will save the settings to your tenant.", Example: ` auth0 universal-login customize auth0 ul customize`, RunE: func(cmd *cobra.Command, args []string) error { + var ( + selectedRenderingMode string + ) + + const advancedMode, standardMode = "advanced", "standard" + label := "Please choose the renderingMode: " + help := fmt.Sprintf( + "%s\n%s\n", + "standardMode is recommended for customizating consistent, branded experience for users.", + "Alternatively, advancedMode is recommended for full customization/granular control of the login experience and to integrate own component design system", + ) + + input := prompt.SelectInput("", label, help, []string{standardMode, advancedMode}, standardMode, true) + if err := prompt.AskOne(input, &selectedRenderingMode); err != nil { + return handleInputError(err) + } + ctx := cmd.Context() if err := ensureCustomDomainIsEnabled(ctx, cli.api); err != nil { @@ -197,6 +223,11 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { return err } + if selectedRenderingMode == advancedMode { + return advanceCustomize(cmd, cli) + } + + // RenderingMode as standard. return startWebSocketServer(ctx, cli.api, cli.renderer, cli.tenant) }, } @@ -204,6 +235,86 @@ func customizeUniversalLoginCmd(cli *cli) *cobra.Command { return cmd } +func advanceCustomize(cmd *cobra.Command, cli *cli) error { + var ( + headTags string + renderSettings = &management.PromptRendering{} + ) + + promptName, screenName, err := fetchPromptScreenInfo() + if err != nil { + return err + } + + cli.renderer.Infof("Updating the rendering settings for the prompt: %s and for the screen: %s", ansi.Green(promptName), ansi.Green(screenName)) + + readRendering, err := cli.api.Prompt.ReadRendering(cmd.Context(), management.PromptType(promptName), management.ScreenName(screenName)) + if err != nil { + return fmt.Errorf("failed to fetch the existing render settings: %w", err) + } + + if readRendering != nil { + jsonData, _ := json.MarshalIndent(readRendering, "", " ") + promptScreenSettings = string(jsonData) + } + + err = ruleScript.OpenEditor(cmd, &headTags, promptScreenSettings, promptName+"_"+screenName+".json", cli.ruleEditorHint) + if err != nil { + return fmt.Errorf("failed to capture input from the editor: %w", err) + } + + err = json.Unmarshal([]byte(headTags), renderSettings) + if err != nil { + return fmt.Errorf("failed to unmarshal JSON input: %w", err) + } + + if err := ansi.Waiting(func() error { + return cli.api.Prompt.UpdateRendering(cmd.Context(), management.PromptType(promptName), management.ScreenName(screenName), renderSettings) + }); err != nil { + return fmt.Errorf("failed to set the render settings: %w", err) + } + + cli.renderer.Infof("Successfully set the render settings") + + return nil +} + +func fetchPromptScreenInfo() (string, string, error) { + var ( + promptName, screenName string + help = "Auth0 supports customizing for many prompts & screens" + ) + + promptLabel := "Please choose the Prompt Name:" + + PromptInput := prompt.SelectInput("", promptLabel, help, fetchKeys(ScreenPromptMap), "login-id", true) + if err := prompt.AskOne(PromptInput, &promptName); err != nil { + return "", "", handleInputError(err) + } + + if len(ScreenPromptMap[promptName]) > 1 { + screenLabel := "Please choose the Screen Name:" + + screenInput := prompt.SelectInput("", screenLabel, help, ScreenPromptMap[promptName], ScreenPromptMap[promptName][0], true) + if err := prompt.AskOne(screenInput, &screenName); err != nil { + return "", "", handleInputError(err) + } + } else { + screenName = ScreenPromptMap[promptName][0] + } + + return promptName, screenName, nil +} + +// Utility function to get all keys from a map. +func fetchKeys[K comparable, V any](m map[K]V) []K { + keys := make([]K, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys +} + func ensureNewUniversalLoginExperienceIsActive(ctx context.Context, api *auth0.API) error { authenticationProfile, err := api.Prompt.Read(ctx) if err != nil { @@ -477,6 +588,16 @@ func (h *webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } +func isSupportedPartial(givenPrompt management.PromptType) bool { + for _, prompt := range allowedPromptsWithPartials { + if givenPrompt == prompt { + return true + } + } + + return false +} + func checkOriginFunc(r *http.Request) bool { origin := r.Header["Origin"] if len(origin) == 0 { @@ -707,6 +828,12 @@ func fetchAllApplications(ctx context.Context, api *auth0.API) ([]*applicationDa } func fetchPartial(ctx context.Context, api *auth0.API, prompt *partialData) (*management.PromptScreenPartials, error) { + var filteredPartials = management.PromptScreenPartials{} + + if !isSupportedPartial(management.PromptType(prompt.PromptName)) { + return &management.PromptScreenPartials{}, nil + } + partial, err := api.Prompt.GetPartials(ctx, management.PromptType(prompt.PromptName)) if err != nil { return nil, err @@ -716,8 +843,6 @@ func fetchPartial(ctx context.Context, api *auth0.API, prompt *partialData) (*ma return &management.PromptScreenPartials{}, nil } - filteredPartials := management.PromptScreenPartials{} - if screenPartials, ok := (*partial)[management.ScreenName(prompt.ScreenName)]; ok { filteredPartials[management.ScreenName(prompt.ScreenName)] = screenPartials } diff --git a/internal/cli/universal_login_customize_test.go b/internal/cli/universal_login_customize_test.go index 703f717e2..42955651f 100644 --- a/internal/cli/universal_login_customize_test.go +++ b/internal/cli/universal_login_customize_test.go @@ -383,42 +383,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -590,42 +601,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -799,42 +821,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, @@ -1088,42 +1121,53 @@ func TestFetchUniversalLoginBrandingData(t *testing.T) { Prompt: "login", CustomText: map[string]interface{}{ "login": map[string]interface{}{ - "alertListTitle": "Alerts", - "auth0-users-validation": "Something went wrong, please try again later", - "authentication-failure": "We are sorry, something went wrong when attempting to login", - "buttonText": "Continue", - "custom-script-error-code": "Something went wrong, please try again later.", - "description": "Log in to ${companyName} to continue to ${clientName}.", - "editEmailText": "Edit", - "emailPlaceholder": "Email address", - "federatedConnectionButtonText": "Continue with ${connectionName}", - "footerLinkText": "Sign up", - "footerText": "Don't have an account?", - "forgotPasswordText": "Forgot password?", - "hidePasswordText": "Hide password", - "invalid-connection": "Invalid connection", - "invalid-email-format": "Email is not valid.", - "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", - "invitationTitle": "You've Been Invited!", - "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", - "logoAltText": "${companyName}", - "no-db-connection": "Invalid connection", - "no-email": "Please enter an email address", - "no-password": "Password is required", - "no-username": "Username is required", - "pageTitle": "Log in | ${clientName}", - "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", - "passwordPlaceholder": "Password", - "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", - "separatorText": "Or", - "showPasswordText": "Show password", - "signupActionLinkText": "${footerLinkText}", - "signupActionText": "${footerText}", - "title": "Welcome friend, glad to have you!", - "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", - "usernamePlaceholder": "Username or email address", - "wrong-credentials": "Wrong username or password", - "wrong-email-credentials": "Wrong email or password", + "alertListTitle": "Alerts", + "auth0-users-validation": "Something went wrong, please try again later", + "authentication-failure": "We are sorry, something went wrong when attempting to log in", + "buttonText": "Continue", + "custom-script-error-code": "Something went wrong, please try again later.", + "description": "Log in to ${companyName} to continue to ${clientName}.", + "editEmailText": "Edit", + "emailPlaceholder": "Email address", + "federatedConnectionButtonText": "Continue with ${connectionName}", + "footerLinkText": "Sign up", + "footerText": "Don't have an account?", + "forgotPasswordText": "Forgot password?", + "hidePasswordText": "Hide password", + "invalid-connection": "Invalid connection", + "invitationDescription": "Log in to accept ${inviterName}'s invitation to join ${companyName} on ${clientName}.", + "invitationTitle": "You've Been Invited!", + "ip-blocked": "We have detected suspicious login behavior and further attempts will be blocked. Please contact the administrator.", + "logoAltText": "${companyName}", + "no-db-connection": "Invalid connection", + "no-email": "Please enter an email address", + "no-password": "Password is required", + "no-username": "Username is required", + "pageTitle": "Log in | ${clientName}", + "password-breached": "We have detected a potential security issue with this account. To protect your account, we have prevented this login. Please reset your password to proceed.", + "passwordPlaceholder": "Password", + "phoneOrEmailPlaceholder": "Phone number or Email address", + "phoneOrUsernameOrEmailPlaceholder": "Phone or Username or Email", + "phoneOrUsernamePlaceholder": "Phone Number or Username", + "phonePlaceholder": "Phone number", + "same-user-login": "Too many login attempts for this user. Please wait, and try again later.", + "separatorText": "Or", + "showPasswordText": "Show password", + "signupActionLinkText": "${footerLinkText}", + "signupActionText": "${footerText}", + "title": "Welcome friend, glad to have you!", + "user-blocked": "Your account has been blocked after multiple consecutive login attempts.", + "usernamePlaceholder": "Username or email address", + "usernameOnlyPlaceholder": "Username", + "usernameOrEmailPlaceholder": "Username or Email address", + "wrong-credentials": "Wrong username or password", + "wrong-email-credentials": "Wrong email or password", + "wrong-email-phone-credentials": "Incorrect email address, phone number, or password. Phone numbers must include the country code.", + "wrong-email-phone-username-credentials": " Incorrect email address, phone number, username, or password. Phone numbers must include the country code.", + "wrong-email-username-credentials": "Incorrect email address, username, or password", + "wrong-phone-credentials": "Incorrect phone number or password", + "wrong-phone-username-credentials": "Incorrect phone number, username or password. Phone numbers must include the country code.", + "wrong-username-credentials": "Incorrect username or password", }, }, }, diff --git a/test/integration/fixtures/update-ul-prompts-login.json b/test/integration/fixtures/update-ul-prompts-login.json index 473b4e0c5..28f9a1f71 100644 --- a/test/integration/fixtures/update-ul-prompts-login.json +++ b/test/integration/fixtures/update-ul-prompts-login.json @@ -22,7 +22,6 @@ "showPasswordText": "Show password", "hidePasswordText": "Hide password", "wrong-credentials": "Wrong username or password", - "invalid-email-format": "Email is not valid.", "wrong-email-credentials": "Wrong email or password", "custom-script-error-code": "Something went wrong, please try again later.", "auth0-users-validation": "Something went wrong, please try again later", diff --git a/test/integration/rules-test-cases.yaml b/test/integration/rules-test-cases.yaml index 9d61c5a69..9cf15d107 100644 --- a/test/integration/rules-test-cases.yaml +++ b/test/integration/rules-test-cases.yaml @@ -17,72 +17,72 @@ tests: stdout: exactly: "[]" - 003 - rules create and check data: - command: cat ./test/integration/fixtures/create-rule.json | jq '.[0]' | auth0 rules create --json - stdout: - json: - name: integration-test-rule-new1 - enabled: "true" - order: "1" - script: "function(user, context, cb) {\n cb(null, user, context);\n}\n" - exit-code: 0 - - 004 - rules create and check output: - command: cat ./test/integration/fixtures/create-rule.json | jq '.[1]' | auth0 rules create - stdout: - contains: - - NAME integration-test-rule-new2 - - ENABLED ✗ - - ORDER 2 - - SCRIPT function(user, context, cb) { - exit-code: 0 - - 005 - rules list all with data: - command: auth0 rules list - exit-code: 0 - stdout: - contains: - - ID - - NAME - - ENABLED - - ORDER - - 006 - rules show json: - command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - name: integration-test-rule-newRule - enabled: "false" - order: "3" - exit-code: 0 - - 007 - rules show: - command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) - stdout: - contains: - - NAME integration-test-rule-newRule - - ENABLED ✗ - - ORDER 3 - exit-code: 0 - - 008 - rules update: - command: cat ./test/integration/fixtures/update-rule.json | auth0 rules update --json - stdout: - json: - name: integration-test-rule-betterName - enabled: "false" - exit-code: 0 - - 009 - rules enable: - command: auth0 rules enable $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - enabled: "true" - exit-code: 0 - - 010 - rules disable: - command: auth0 rules disable $(./test/integration/scripts/get-rule-id.sh) --json - stdout: - json: - enabled: "false" - exit-code: 0 +# 003 - rules create and check data: +# command: cat ./test/integration/fixtures/create-rule.json | jq '.[0]' | auth0 rules create --json +# stdout: +# json: +# name: integration-test-rule-new1 +# enabled: "true" +# order: "1" +# script: "function(user, context, cb) {\n cb(null, user, context);\n}\n" +# exit-code: 0 +# +# 004 - rules create and check output: +# command: cat ./test/integration/fixtures/create-rule.json | jq '.[1]' | auth0 rules create +# stdout: +# contains: +# - NAME integration-test-rule-new2 +# - ENABLED ✗ +# - ORDER 2 +# - SCRIPT function(user, context, cb) { +# exit-code: 0 +# +# 005 - rules list all with data: +# command: auth0 rules list +# exit-code: 0 +# stdout: +# contains: +# - ID +# - NAME +# - ENABLED +# - ORDER +# +# 006 - rules show json: +# command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# name: integration-test-rule-newRule +# enabled: "false" +# order: "3" +# exit-code: 0 +# +# 007 - rules show: +# command: auth0 rules show $(./test/integration/scripts/get-rule-id.sh) +# stdout: +# contains: +# - NAME integration-test-rule-newRule +# - ENABLED ✗ +# - ORDER 3 +# exit-code: 0 +# +# 008 - rules update: +# command: cat ./test/integration/fixtures/update-rule.json | auth0 rules update --json +# stdout: +# json: +# name: integration-test-rule-betterName +# enabled: "false" +# exit-code: 0 +# +# 009 - rules enable: +# command: auth0 rules enable $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# enabled: "true" +# exit-code: 0 +# +# 010 - rules disable: +# command: auth0 rules disable $(./test/integration/scripts/get-rule-id.sh) --json +# stdout: +# json: +# enabled: "false" +# exit-code: 0