From 1d5c153aefb9371e9fe644ec5e3de3b22a4f8e0d Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 29 Jun 2022 05:54:08 -0300 Subject: [PATCH 01/38] Use Xcode version `13.0.0` instead of `13` (#102) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b213951..53061376 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -94,7 +94,7 @@ jobs: ios_simulator: type: string macos: - xcode: 13 + xcode: '13.0.0' environment: BUNDLE_RETRY: 3 HOMEBREW_NO_AUTO_UPDATE: 1 From aa5a14e59205e02ae4eab64fd9dcea263e63d73e Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 29 Jun 2022 05:54:33 -0300 Subject: [PATCH 02/38] Fix test flakiness (#103) --- auth0_flutter/example/ios/UITests/SmokeTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/auth0_flutter/example/ios/UITests/SmokeTests.swift b/auth0_flutter/example/ios/UITests/SmokeTests.swift index 4e399ea6..9c5ab976 100644 --- a/auth0_flutter/example/ios/UITests/SmokeTests.swift +++ b/auth0_flutter/example/ios/UITests/SmokeTests.swift @@ -27,7 +27,6 @@ class SmokeTests: XCTestCase { let passwordInput = app.webViews.secureTextFields.firstMatch passwordInput.tap() passwordInput.typeText("\(password)\n") - app.webViews.buttons.firstMatch.tap() XCTAssertTrue(app.buttons[logoutButton].waitForExistence(timeout: timeout)) } From e2e6ca33e4b30dc741e3a299a00a7de8e863bb34 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Wed, 29 Jun 2022 10:25:15 +0100 Subject: [PATCH 03/38] [SDK-3451] SDK Documentation (#101) * [SDK-3437] Add NOTICE file (#100) * Doc comments for majority API * Add doc comments for Authentication API * Apply suggestions from code review Co-authored-by: Rita Zerrizuela * Further docs changes from feedback * Apply suggestions from code review Co-authored-by: Rita Zerrizuela * Documentation for redirectUrl * Documentation for returnTo * Apply suggestions from code review Co-authored-by: Rita Zerrizuela * Update auth0_flutter/lib/src/web_authentication.dart Co-authored-by: Rita Zerrizuela * Correct comment on Credentials.scopes Co-authored-by: Rita Zerrizuela --- NOTICE | 5227 +++++++++++++++++ auth0_flutter/.gitignore | 1 - auth0_flutter/doc/api/__404error.html | 103 + .../api/auth0_flutter/ApiException-class.html | 552 ++ .../ApiException.fromPlatformException.html | 173 + .../ApiException/ApiException.html | 167 + .../ApiException/ApiException.unknown.html | 164 + .../api/auth0_flutter/ApiException/code.html | 163 + .../auth0_flutter/ApiException/details.html | 163 + .../ApiException/isAccessDenied.html | 168 + .../isBrowserAppNotAvailable.html | 169 + .../ApiException/isCanceled.html | 168 + .../ApiException/isInvalidAuthorizeURL.html | 169 + .../ApiException/isInvalidConfiguration.html | 169 + .../ApiException/isInvalidCredentials.html | 169 + .../ApiException/isLoginRequired.html | 168 + .../isMultifactorCodeInvalid.html | 169 + .../isMultifactorEnrollRequired.html | 169 + .../ApiException/isMultifactorRequired.html | 169 + .../isMultifactorTokenInvalid.html | 169 + .../ApiException/isNetworkError.html | 168 + .../ApiException/isPKCENotAvailable.html | 169 + .../ApiException/isPasswordAlreadyUsed.html | 169 + .../ApiException/isPasswordLeaked.html | 169 + .../isPasswordNotStrongEnough.html | 169 + .../ApiException/isRefreshTokenDeleted.html | 169 + .../ApiException/isRuleError.html | 168 + .../ApiException/isTooManyAttempts.html | 169 + .../ApiException/isVerificationRequired.html | 169 + .../auth0_flutter/ApiException/message.html | 163 + .../ApiException/statusCode.html | 163 + .../auth0_flutter/ApiException/toString.html | 183 + .../doc/api/auth0_flutter/Auth0-class.html | 274 + .../doc/api/auth0_flutter/Auth0/Auth0.html | 143 + .../doc/api/auth0_flutter/Auth0/api.html | 158 + .../Auth0/webAuthentication.html | 153 + .../AuthenticationApi-class.html | 336 ++ .../AuthenticationApi/AuthenticationApi.html | 141 + .../AuthenticationApi/login.html | 186 + .../AuthenticationApi/renewCredentials.html | 180 + .../AuthenticationApi/resetPassword.html | 163 + .../AuthenticationApi/signup.html | 173 + .../AuthenticationApi/userProfile.html | 165 + .../api/auth0_flutter/Credentials-class.html | 330 ++ .../Credentials/Credentials.fromMap.html | 151 + .../Credentials/Credentials.html | 154 + .../Credentials/accessToken.html | 152 + .../auth0_flutter/Credentials/expiresAt.html | 147 + .../auth0_flutter/Credentials/idToken.html | 151 + .../Credentials/refreshToken.html | 149 + .../api/auth0_flutter/Credentials/scopes.html | 148 + .../Credentials/userProfile.html | 148 + .../IdTokenValidationConfig-class.html | 287 + .../IdTokenValidationConfig.html | 140 + .../IdTokenValidationConfig/issuer.html | 143 + .../IdTokenValidationConfig/leeway.html | 143 + .../IdTokenValidationConfig/maxAge.html | 143 + .../api/auth0_flutter/UserProfile-class.html | 511 ++ .../UserProfile/UserProfile.fromMap.html | 193 + .../UserProfile/UserProfile.html | 199 + .../auth0_flutter/UserProfile/address.html | 163 + .../auth0_flutter/UserProfile/birthdate.html | 163 + .../UserProfile/customClaims.html | 162 + .../api/auth0_flutter/UserProfile/email.html | 163 + .../auth0_flutter/UserProfile/familyName.html | 163 + .../api/auth0_flutter/UserProfile/gender.html | 163 + .../auth0_flutter/UserProfile/givenName.html | 163 + .../UserProfile/isEmailVerified.html | 163 + .../UserProfile/isPhoneNumberVerified.html | 163 + .../api/auth0_flutter/UserProfile/locale.html | 163 + .../auth0_flutter/UserProfile/middleName.html | 163 + .../api/auth0_flutter/UserProfile/name.html | 163 + .../auth0_flutter/UserProfile/nickname.html | 163 + .../UserProfile/phoneNumber.html | 163 + .../auth0_flutter/UserProfile/pictureURL.html | 163 + .../UserProfile/preferredUsername.html | 163 + .../auth0_flutter/UserProfile/profileURL.html | 163 + .../api/auth0_flutter/UserProfile/sub.html | 162 + .../auth0_flutter/UserProfile/updatedAt.html | 163 + .../auth0_flutter/UserProfile/websiteURL.html | 163 + .../auth0_flutter/UserProfile/zoneinfo.html | 163 + .../auth0_flutter/WebAuthException-class.html | 299 + ...ebAuthException.fromPlatformException.html | 141 + .../WebAuthException/WebAuthException.html | 144 + .../WebAuthException.unknown.html | 140 + .../auth0_flutter/WebAuthException/code.html | 142 + .../WebAuthException/details.html | 142 + .../WebAuthException/message.html | 142 + .../WebAuthException/toString.html | 162 + .../WebAuthentication-class.html | 289 + .../WebAuthentication/WebAuthentication.html | 138 + .../WebAuthentication/login.html | 190 + .../WebAuthentication/logout.html | 153 + .../auth0_flutter/auth0_flutter-library.html | 208 + auth0_flutter/doc/api/categories.json | 1 + auth0_flutter/doc/api/index.html | 473 ++ auth0_flutter/doc/api/index.json | 1 + .../doc/api/static-assets/favicon.png | Bin 0 -> 1767 bytes .../doc/api/static-assets/github.css | 99 + .../doc/api/static-assets/highlight.pack.js | 775 +++ .../doc/api/static-assets/play_button.svg | 1 + auth0_flutter/doc/api/static-assets/readme.md | 22 + auth0_flutter/doc/api/static-assets/script.js | 501 ++ .../doc/api/static-assets/styles.css | 1022 ++++ auth0_flutter/lib/auth0_flutter.dart | 39 +- auth0_flutter/lib/src/authentication_api.dart | 106 + auth0_flutter/lib/src/web_authentication.dart | 39 + .../lib/src/credentials.dart | 31 + .../lib/src/user_profile.dart | 92 +- .../web-auth/id_token_validation_config.dart | 6 + 110 files changed, 24872 insertions(+), 5 deletions(-) create mode 100644 NOTICE create mode 100644 auth0_flutter/doc/api/__404error.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/code.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/details.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/message.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/api.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html create mode 100644 auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html create mode 100644 auth0_flutter/doc/api/categories.json create mode 100644 auth0_flutter/doc/api/index.html create mode 100644 auth0_flutter/doc/api/index.json create mode 100644 auth0_flutter/doc/api/static-assets/favicon.png create mode 100644 auth0_flutter/doc/api/static-assets/github.css create mode 100644 auth0_flutter/doc/api/static-assets/highlight.pack.js create mode 100644 auth0_flutter/doc/api/static-assets/play_button.svg create mode 100644 auth0_flutter/doc/api/static-assets/readme.md create mode 100644 auth0_flutter/doc/api/static-assets/script.js create mode 100644 auth0_flutter/doc/api/static-assets/styles.css diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..e659b8f5 --- /dev/null +++ b/NOTICE @@ -0,0 +1,5227 @@ + +Auth0 Flutter + +Copyright 2022 Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + + +THE SOFTWARE IS PROVIDED โ€œAS ISโ€, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +-------------------------------------------------------------------------------- + + +The following 3rd-party software packages may be used by or distributed with Auth0 Flutter Certain licenses and notices may appear in other parts of the product in accordance with the applicable license requirements. + +The Okta product that this document references does not necessarily use all the open source software packages referred to below and may also only use portions of a given package. In addition, Okta makes available to customers certain complementary, unmodified open source software packages that facilitate customersโ€™ use of the Auth0 Flutter product. + + +================================================================================ + + Dependencies + +================================================================================ + +- _fe_analyzer_shared (31.0.0) [BSD-3-Clause] +- analyzer (2.8.0) [BSD-3-Clause] +- args (2.3.0) [BSD-3-Clause] +- async (2.8.2) [BSD-3-Clause] +- boolean_selector (2.1.0) [BSD-3-Clause] +- build (2.3.0) [BSD-3-Clause] +- build_config (1.0.0) [BSD-3-Clause] +- build_daemon (3.1.0) [BSD-3-Clause] +- build_resolvers (2.0.6) [BSD-3-Clause] +- build_runner_core (7.2.3) [BSD-3-Clause] +- built_collection (5.1.1) [BSD-3-Clause] +- built_value (8.2.3) [BSD-3-Clause] +- characters (1.2.0) [BSD-3-Clause, CC-BY-SA-3.0, Unicode-DFS-2020] +- charcode (1.3.1) [BSD-3-Clause] +- checked_yaml (2.0.1) [BSD-3-Clause] +- cli_util (0.3.5) [BSD-3-Clause] +- clock (1.1.0) [Apache-2.0, BSD-3-Clause] +- code_builder (4.1.0) [BSD-3-Clause] +- collection (1.15.0) [BSD-3-Clause] +- convert (3.0.1) [BSD-3-Clause] +- coverage (1.0.3) [Apache-2.0, BSD-3-Clause] +- crypto (3.0.2) [BSD-3-Clause] +- dart_style (2.2.1) [BSD-3-Clause] +- fake_async (1.2.0) [Apache-2.0, BSD-3-Clause] +- file (6.1.2) [BSD-3-Clause] +- fixnum (1.0.0) [BSD-3-Clause] +- frontend_server_client (2.1.2) [BSD-3-Clause] +- functional_data (1.0.0) [MIT] +- glob (2.0.2) [BSD-3-Clause] +- graphs (2.1.0) [BSD-3-Clause] +- http_multi_server (3.2.0) [BSD-3-Clause] +- http_parser (4.0.0) [BSD-3-Clause] +- io (1.0.3) [BSD-3-Clause] +- js (0.6.4) [BSD-3-Clause] +- json2yaml (3.0.0) [MIT] +- json_annotation (4.5.0) [BSD-3-Clause] +- lints (1.0.1) [BSD-3-Clause] +- logging (1.0.2) [BSD-3-Clause] +- matcher (0.12.11) [BSD-3-Clause] +- material_color_utilities (0.1.3) [Apache-2.0] +- meta (1.7.0) [BSD-3-Clause] +- mime (1.0.1) [BSD-3-Clause] +- mime (1.0.2) [BSD-3-Clause] +- node_preamble (2.0.1) [Multi-license: BSD-3-Clause OR MIT] +- package_config (2.0.2) [BSD-3-Clause] +- path (1.8.0) [BSD-3-Clause] +- plain_optional (1.0.0) [MIT] +- plugin_platform_interface (2.1.2) [BSD-3-Clause] +- pool (1.5.0) [BSD-3-Clause] +- pub_semver (2.1.1) [BSD-3-Clause] +- pubspec_parse (1.2.0) [BSD-3-Clause] +- shelf (1.3.0) [BSD-3-Clause] +- shelf_packages_handler (3.0.0) [BSD-3-Clause] +- shelf_static (1.1.0) [BSD-3-Clause] +- shelf_web_socket (1.0.1) [BSD-3-Clause] +- source_gen (1.2.2) [BSD-3-Clause] +- source_map_stack_trace (2.1.0) [BSD-3-Clause] +- source_maps (0.10.10) [BSD-3-Clause] +- source_span (1.8.1) [BSD-3-Clause] +- stack_trace (1.10.0) [BSD-3-Clause] +- stream_channel (2.1.0) [BSD-3-Clause] +- stream_transform (2.0.0) [BSD-3-Clause] +- string_scanner (1.1.0) [BSD-3-Clause] +- sum_types (0.3.1) [MIT] +- term_glyph (1.2.0) [BSD-3-Clause] +- test_api (0.4.8) [BSD-3-Clause] +- test_core (0.4.9) [BSD-3-Clause] +- timing (1.0.0) [BSD-3-Clause] +- typed_data (1.3.0) [BSD-3-Clause] +- vector_math (2.1.1) [Multi-license: BSD-3-Clause OR Zlib, BSD-3-Clause, Zlib] +- vm_service (7.5.0) [BSD-3-Clause, EPL-1.0, Multi-license: BSD-3-Clause OR EPL-1.0] +- watcher (1.0.1) [BSD-3-Clause] +- web_socket_channel (2.2.0) [BSD-3-Clause] +- webkit_inspection_protocol (1.0.0) [BSD-3-Clause] +- yaml (3.1.0) [BSD-3-Clause, MIT] + + +-------------------------------------------------------------------------------- +_fe_analyzer_shared (31.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +analyzer (2.8.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +args (2.3.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +async (2.8.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +boolean_selector (2.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +build (2.3.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +build_config (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +build_daemon (3.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +build_resolvers (2.0.6) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +build_runner_core (7.2.3) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +built_collection (5.1.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +built_value (8.2.3) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +characters (1.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +* Other Licenses * +CC-BY-SA-3.0, Unicode-DFS-2020 + + +<> CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +License<> +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + 1. Definitions + a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. + c. "Creative Commons Compatible License" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. + d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. + f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. + The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. + 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv), consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + 5. Representations, Warranties and Disclaimer + UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 7. Termination + a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + 8. Miscellaneous + a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. +Creative Commons Notice +Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. +Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. +Creative Commons may be contacted at http://creativecommons.org/. + + +\n\n UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE\n\n See Terms of Use for definitions of Unicode Inc.'s\n Data Files and Software.\n\n NOTICE TO USER: Carefully read the following legal agreement.\n BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S\n DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),\n YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\n TERMS AND CONDITIONS OF THIS AGREEMENT.\n IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE\n THE DATA FILES OR SOFTWARE.\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright ยฉ 1991-2020 Unicode, Inc. All rights reserved.\n Distributed under the Terms of Use in https://www.unicode.org/copyright.html.\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of the Unicode data files and any associated documentation\n (the "Data Files") or Unicode software and any associated documentation\n (the "Software") to deal in the Data Files or Software\n without restriction, including without limitation the rights to use,\n copy, modify, merge, publish, distribute, and/or sell copies of\n the Data Files or Software, and to permit persons to whom the Data Files\n or Software are furnished to do so, provided that either\n (a) this copyright and permission notice appear with all copies\n of the Data Files or Software, or\n (b) this copyright and permission notice appear in associated\n Documentation.\n\n THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF\n ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT OF THIRD PARTY RIGHTS.\n IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS\n NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL\n DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n PERFORMANCE OF THE DATA FILES OR SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder\n shall not be used in advertising or otherwise to promote the sale,\n use or other dealings in these Data Files or Software without prior\n written authorization of the copyright holder.\n\n + + +-------------------------------------------------------------------------------- +charcode (1.3.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +checked_yaml (2.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2019, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +cli_util (0.3.5) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +clock (1.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +* Other Licenses * +BSD-3-Clause + + +Copyright (c) to your . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +code_builder (4.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +collection (1.15.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +convert (3.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +coverage (1.0.3) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +* Other Licenses * +BSD-3-Clause + + +Copyright (c) 2014 the Dart project authors. Please see the AUTHORS file . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +crypto (3.0.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +dart_style (2.2.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +fake_async (1.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +* Other Licenses * +BSD-3-Clause + + +Copyright (c) to your . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +file (6.1.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +fixnum (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +frontend_server_client (2.1.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +functional_data (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +MIT + +MIT License + +Copyright (c) 2018 Sander Kersten + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +-------------------------------------------------------------------------------- +glob (2.0.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +graphs (2.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +http_multi_server (3.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +http_parser (4.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +io (1.0.3) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +js (0.6.4) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +json2yaml (3.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +MIT + +MIT License + +Copyright (c) 2019 Alexei Sintotski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +-------------------------------------------------------------------------------- +json_annotation (4.5.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +lints (1.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2021, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +logging (1.0.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +matcher (0.12.11) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +material_color_utilities (0.1.3) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Apache-2.0 + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +-------------------------------------------------------------------------------- +meta (1.7.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +mime (1.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +mime (1.0.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +node_preamble (2.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Multi-license: BSD-3-Clause OR MIT + +The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +package_config (2.0.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +path (1.8.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +plain_optional (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +MIT + +MIT License + +Copyright (c) 2019 Raman Fedaseyeu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +-------------------------------------------------------------------------------- +plugin_platform_interface (2.1.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +pool (1.5.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +pub_semver (2.1.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +pubspec_parse (1.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +shelf (1.3.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +shelf_packages_handler (3.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +shelf_static (1.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +shelf_web_socket (1.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +source_gen (1.2.2) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +source_map_stack_trace (2.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +source_maps (0.10.10) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +source_span (1.8.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +stack_trace (1.10.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +stream_channel (2.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +stream_transform (2.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +string_scanner (1.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +sum_types (0.3.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +MIT + +MIT License + +Copyright (c) 2019 Raman Fedaseyeus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +-------------------------------------------------------------------------------- +term_glyph (1.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +test_api (0.4.8) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +test_core (0.4.9) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +timing (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2018, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +typed_data (1.3.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +vector_math (2.1.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +Multi-license: BSD-3-Clause OR Zlib + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + + +* Other Licenses * +BSD-3-Clause, Zlib + + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +-------------------------------------------------------------------------------- +vm_service (7.5.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +* Other Licenses * +EPL-1.0, Multi-license: BSD-3-Clause OR EPL-1.0 + + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + 1. DEFINITIONS + "Contribution" means: + a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + "Contributor" means any person or entity that distributes the Program. + "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + "Program" means the Contributions distributed in accordance with this Agreement. + "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + 2. GRANT OF RIGHTS + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + 3. REQUIREMENTS + A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + a) it complies with the terms and conditions of this Agreement; and + b) its license agreement: + i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + When the Program is made available in source code form: + a) it must be made available under this Agreement; and + b) a copy of this Agreement must be included with each copy of the Program. + Contributors may not remove or alter any copyright notices contained within the Program. + Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + 4. COMMERCIAL DISTRIBUTION + Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + 5. NO WARRANTY + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + 6. DISCLAIMER OF LIABILITY + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 7. GENERAL + If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. + + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +watcher (1.0.1) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +web_socket_channel (2.2.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +webkit_inspection_protocol (1.0.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2013, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +-------------------------------------------------------------------------------- +yaml (3.1.0) +-------------------------------------------------------------------------------- + +* Declared Licenses * +BSD-3-Clause + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +* Other Licenses * +MIT + + +Copyright (c) 2006 Kirill Simonov +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +================================================================================ + Licenses + +================================================================================ + +* Apache-2.0 * + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +* BSD-3-Clause * + +Copyright (c) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +* CC-BY-SA-3.0 * + +Creative Commons Attribution-ShareAlike 3.0 Unported CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. +License +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + 1. Definitions + a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. + c. "Creative Commons Compatible License" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. + d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. + e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. + f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. + g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. + h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. + i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. + j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. + The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. + 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv), consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. + d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. + 5. Representations, Warranties and Disclaimer + UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 7. Termination + a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + 8. Miscellaneous + a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. +Creative Commons Notice +Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. +Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. +Creative Commons may be contacted at http://creativecommons.org/. + +* BSD-3-Clause * + +Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2013, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + +* BSD-3-Clause * + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2016, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +* BSD-3-Clause * + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2018, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2019, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* BSD-3-Clause * + +Copyright 2021, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* EPL-1.0 * + +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + 1. DEFINITIONS + "Contribution" means: + a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. + "Contributor" means any person or entity that distributes the Program. + "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + "Program" means the Contributions distributed in accordance with this Agreement. + "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. + 2. GRANT OF RIGHTS + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + 3. REQUIREMENTS + A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: + a) it complies with the terms and conditions of this Agreement; and + b) its license agreement: + i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and + iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. + When the Program is made available in source code form: + a) it must be made available under this Agreement; and + b) a copy of this Agreement must be included with each copy of the Program. + Contributors may not remove or alter any copyright notices contained within the Program. + Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. + 4. COMMERCIAL DISTRIBUTION + Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + 5. NO WARRANTY + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + 6. DISCLAIMER OF LIABILITY + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 7. GENERAL + If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. + This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. + +* MIT * + +MIT License +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* MIT * + +MIT License + +Copyright (c) 2018 Sander Kersten + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* MIT * + +MIT License + +Copyright (c) 2019 Alexei Sintotski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* MIT * + +MIT License + +Copyright (c) 2019 Raman Fedaseyeu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* MIT * + +MIT License + +Copyright (c) 2019 Raman Fedaseyeus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* BSD-3-Clause * + +The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +* Unicode-DFS-2020 * + +\n\n UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE\n\n See Terms of Use for definitions of Unicode Inc.'s\n Data Files and Software.\n\n NOTICE TO USER: Carefully read the following legal agreement.\n BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S\n DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),\n YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\n TERMS AND CONDITIONS OF THIS AGREEMENT.\n IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE\n THE DATA FILES OR SOFTWARE.\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright ยฉ 1991-2020 Unicode, Inc. All rights reserved.\n Distributed under the Terms of Use in https://www.unicode.org/copyright.html.\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of the Unicode data files and any associated documentation\n (the "Data Files") or Unicode software and any associated documentation\n (the "Software") to deal in the Data Files or Software\n without restriction, including without limitation the rights to use,\n copy, modify, merge, publish, distribute, and/or sell copies of\n the Data Files or Software, and to permit persons to whom the Data Files\n or Software are furnished to do so, provided that either\n (a) this copyright and permission notice appear with all copies\n of the Data Files or Software, or\n (b) this copyright and permission notice appear in associated\n Documentation.\n\n THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF\n ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT OF THIRD PARTY RIGHTS.\n IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS\n NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL\n DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n PERFORMANCE OF THE DATA FILES OR SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder\n shall not be used in advertising or otherwise to promote the sale,\n use or other dealings in these Data Files or Software without prior\n written authorization of the copyright holder.\n\n + +* Zlib * + +zlib License Copyright (c) +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +Report Generated by FOSSA on 2022-6-21 diff --git a/auth0_flutter/.gitignore b/auth0_flutter/.gitignore index 9be145fd..2de69c93 100644 --- a/auth0_flutter/.gitignore +++ b/auth0_flutter/.gitignore @@ -23,7 +23,6 @@ # Flutter/Dart/Pub related # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. /pubspec.lock -**/doc/api/ .dart_tool/ .packages build/ diff --git a/auth0_flutter/doc/api/__404error.html b/auth0_flutter/doc/api/__404error.html new file mode 100644 index 00000000..ef34672b --- /dev/null +++ b/auth0_flutter/doc/api/__404error.html @@ -0,0 +1,103 @@ + + + + + + + + + auth0_flutter - Dart API docs + + + + + + + + + + + + + + + + + +
+ +
+ + +
auth0_flutter
+ +
+ +
+ + +
+

404: Something's gone wrong :-(

+ +
+

You've tried to visit a page that doesn't exist. Luckily this site + has other pages.

+

If you were looking for something specific, try searching: +

+

+ +
+
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html b/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html new file mode 100644 index 00000000..cb113f0d --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html @@ -0,0 +1,552 @@ + + + + + + + + ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
ApiException
+ +
+ +
+ + +
+
+

ApiException class + Null safety + +

+ + + + + + +
+

Constructors

+ +
+
+ ApiException(String code, String message, Map<String, dynamic> details, Map _errorFlags, int statusCode) +
+
+ +
const
+
+
+ ApiException.fromPlatformException(PlatformException e) +
+
+ +
factory
+
+
+ ApiException.unknown(String message) +
+
+ +
const
+
+
+
+ +
+

Properties

+ +
+
+ code + String + +
+
+ +
final, inherited
+ +
+ +
+ details + Map<String, dynamic> + +
+
+ +
final, inherited
+ +
+ +
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ isAccessDenied + bool + +
+
+ +
read-only
+ +
+ +
+ isBrowserAppNotAvailable + bool + +
+
+ +
read-only
+ +
+ +
+ isCanceled + bool + +
+
+ +
read-only
+ +
+ +
+ isInvalidAuthorizeURL + bool + +
+
+ +
read-only
+ +
+ +
+ isInvalidConfiguration + bool + +
+
+ +
read-only
+ +
+ +
+ isInvalidCredentials + bool + +
+
+ +
read-only
+ +
+ +
+ isLoginRequired + bool + +
+
+ +
read-only
+ +
+ +
+ isMultifactorCodeInvalid + bool + +
+
+ +
read-only
+ +
+ +
+ isMultifactorEnrollRequired + bool + +
+
+ +
read-only
+ +
+ +
+ isMultifactorRequired + bool + +
+
+ +
read-only
+ +
+ +
+ isMultifactorTokenInvalid + bool + +
+
+ +
read-only
+ +
+ +
+ isNetworkError + bool + +
+
+ +
read-only
+ +
+ +
+ isPasswordAlreadyUsed + bool + +
+
+ +
read-only
+ +
+ +
+ isPasswordLeaked + bool + +
+
+ +
read-only
+ +
+ +
+ isPasswordNotStrongEnough + bool + +
+
+ +
read-only
+ +
+ +
+ isPKCENotAvailable + bool + +
+
+ +
read-only
+ +
+ +
+ isRefreshTokenDeleted + bool + +
+
+ +
read-only
+ +
+ +
+ isRuleError + bool + +
+
+ +
read-only
+ +
+ +
+ isTooManyAttempts + bool + +
+
+ +
read-only
+ +
+ +
+ isVerificationRequired + bool + +
+
+ +
read-only
+ +
+ +
+ message + String + +
+
+ +
final, inherited
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+ statusCode + int + +
+
+ +
final
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html new file mode 100644 index 00000000..ac14a61c --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html @@ -0,0 +1,173 @@ + + + + + + + + ApiException.fromPlatformException constructor - ApiException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
ApiException.fromPlatformException
+ +
+ +
+ + +
+
+

ApiException.fromPlatformException constructor + Null safety +

+ +
+ ApiException.fromPlatformException(
  1. PlatformException e
  2. +
) +
+ + + + + +
+

Implementation

+
factory ApiException.fromPlatformException(final PlatformException e) {
+  final Map<String, dynamic> errorDetails = e.detailsMap;
+  final statusCode =
+      errorDetails.getOrDefault(_statusCodeKey, 0);
+  final errorFlags =
+      errorDetails.getOrDefault(_errorFlagsKey, <dynamic, dynamic>{});
+
+  errorDetails.remove(_statusCodeKey);
+  errorDetails.remove(_errorFlagsKey);
+
+  return ApiException(
+      e.code, e.messageString, errorDetails, errorFlags, statusCode);
+}
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html new file mode 100644 index 00000000..6688bceb --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html @@ -0,0 +1,167 @@ + + + + + + + + ApiException constructor - ApiException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
ApiException
+ +
+ +
+ + +
+
+

ApiException constructor + Null safety +

+ +
const + ApiException(
  1. String code,
  2. +
  3. String message,
  4. +
  5. Map<String, dynamic> details,
  6. +
  7. Map _errorFlags,
  8. +
  9. int statusCode
  10. +
) +
+ + + + + +
+

Implementation

+
const ApiException(final String code, final String message,
+    final Map<String, dynamic> details, this._errorFlags, this.statusCode)
+    : super(code, message, details);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html new file mode 100644 index 00000000..694402ca --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html @@ -0,0 +1,164 @@ + + + + + + + + ApiException.unknown constructor - ApiException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
ApiException.unknown
+ +
+ +
+ + +
+
+

ApiException.unknown constructor + Null safety +

+ +
const + ApiException.unknown(
  1. String message
  2. +
) +
+ + + + + +
+

Implementation

+
const ApiException.unknown(final String message)
+    : _errorFlags = const {},
+      statusCode = 0,
+      super.unknown(message);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html new file mode 100644 index 00000000..72ae8ca7 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html @@ -0,0 +1,163 @@ + + + + + + + + code property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
code
+ +
+ +
+ + +
+
+

code property + Null safety +

+ +
+ String + code +
final, inherited
+ +
+ + + +
+

Implementation

+
final String code;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html new file mode 100644 index 00000000..952a1abb --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html @@ -0,0 +1,163 @@ + + + + + + + + details property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
details
+ +
+ +
+ + +
+
+

details property + Null safety +

+ +
+ Map<String, dynamic> + details +
final, inherited
+ +
+ + + +
+

Implementation

+
final Map<String, dynamic> details;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html new file mode 100644 index 00000000..2c3f7640 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html @@ -0,0 +1,168 @@ + + + + + + + + isAccessDenied property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isAccessDenied
+ +
+ +
+ + +
+
+

isAccessDenied property + Null safety +

+ + + +
+ +
+ bool + isAccessDenied + + +
+ + + + +
+

Implementation

+
bool get isAccessDenied => _errorFlags.getBooleanOrFalse('isAccessDenied');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html new file mode 100644 index 00000000..5afa8b54 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html @@ -0,0 +1,169 @@ + + + + + + + + isBrowserAppNotAvailable property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isBrowserAppNotAvailable
+ +
+ +
+ + +
+
+

isBrowserAppNotAvailable property + Null safety +

+ + + +
+ +
+ bool + isBrowserAppNotAvailable + + +
+ + + + +
+

Implementation

+
bool get isBrowserAppNotAvailable =>
+    _errorFlags.getBooleanOrFalse('isBrowserAppNotAvailable');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html new file mode 100644 index 00000000..4be42b14 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html @@ -0,0 +1,168 @@ + + + + + + + + isCanceled property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isCanceled
+ +
+ +
+ + +
+
+

isCanceled property + Null safety +

+ + + +
+ +
+ bool + isCanceled + + +
+ + + + +
+

Implementation

+
bool get isCanceled => _errorFlags.getBooleanOrFalse('isCanceled');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html new file mode 100644 index 00000000..f026623d --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html @@ -0,0 +1,169 @@ + + + + + + + + isInvalidAuthorizeURL property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isInvalidAuthorizeURL
+ +
+ +
+ + +
+
+

isInvalidAuthorizeURL property + Null safety +

+ + + +
+ +
+ bool + isInvalidAuthorizeURL + + +
+ + + + +
+

Implementation

+
bool get isInvalidAuthorizeURL =>
+    _errorFlags.getBooleanOrFalse('isInvalidAuthorizeURL');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html new file mode 100644 index 00000000..8a35b9e8 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html @@ -0,0 +1,169 @@ + + + + + + + + isInvalidConfiguration property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isInvalidConfiguration
+ +
+ +
+ + +
+
+

isInvalidConfiguration property + Null safety +

+ + + +
+ +
+ bool + isInvalidConfiguration + + +
+ + + + +
+

Implementation

+
bool get isInvalidConfiguration =>
+    _errorFlags.getBooleanOrFalse('isInvalidConfiguration');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html new file mode 100644 index 00000000..9a25e196 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html @@ -0,0 +1,169 @@ + + + + + + + + isInvalidCredentials property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isInvalidCredentials
+ +
+ +
+ + +
+
+

isInvalidCredentials property + Null safety +

+ + + +
+ +
+ bool + isInvalidCredentials + + +
+ + + + +
+

Implementation

+
bool get isInvalidCredentials =>
+    _errorFlags.getBooleanOrFalse('isInvalidCredentials');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html new file mode 100644 index 00000000..45df9ac3 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html @@ -0,0 +1,168 @@ + + + + + + + + isLoginRequired property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isLoginRequired
+ +
+ +
+ + +
+
+

isLoginRequired property + Null safety +

+ + + +
+ +
+ bool + isLoginRequired + + +
+ + + + +
+

Implementation

+
bool get isLoginRequired => _errorFlags.getBooleanOrFalse('isLoginRequired');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html new file mode 100644 index 00000000..de5e0ff0 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html @@ -0,0 +1,169 @@ + + + + + + + + isMultifactorCodeInvalid property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isMultifactorCodeInvalid
+ +
+ +
+ + +
+
+

isMultifactorCodeInvalid property + Null safety +

+ + + +
+ +
+ bool + isMultifactorCodeInvalid + + +
+ + + + +
+

Implementation

+
bool get isMultifactorCodeInvalid =>
+    _errorFlags.getBooleanOrFalse('isMultifactorCodeInvalid');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html new file mode 100644 index 00000000..ee0e511b --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html @@ -0,0 +1,169 @@ + + + + + + + + isMultifactorEnrollRequired property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isMultifactorEnrollRequired
+ +
+ +
+ + +
+
+

isMultifactorEnrollRequired property + Null safety +

+ + + +
+ +
+ bool + isMultifactorEnrollRequired + + +
+ + + + +
+

Implementation

+
bool get isMultifactorEnrollRequired =>
+    _errorFlags.getBooleanOrFalse('isMultifactorEnrollRequired');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html new file mode 100644 index 00000000..ab418a11 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html @@ -0,0 +1,169 @@ + + + + + + + + isMultifactorRequired property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isMultifactorRequired
+ +
+ +
+ + +
+
+

isMultifactorRequired property + Null safety +

+ + + +
+ +
+ bool + isMultifactorRequired + + +
+ + + + +
+

Implementation

+
bool get isMultifactorRequired =>
+    _errorFlags.getBooleanOrFalse('isMultifactorRequired');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html new file mode 100644 index 00000000..e2b77250 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html @@ -0,0 +1,169 @@ + + + + + + + + isMultifactorTokenInvalid property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isMultifactorTokenInvalid
+ +
+ +
+ + +
+
+

isMultifactorTokenInvalid property + Null safety +

+ + + +
+ +
+ bool + isMultifactorTokenInvalid + + +
+ + + + +
+

Implementation

+
bool get isMultifactorTokenInvalid =>
+    _errorFlags.getBooleanOrFalse('isMultifactorTokenInvalid');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html new file mode 100644 index 00000000..8c5cc6c1 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html @@ -0,0 +1,168 @@ + + + + + + + + isNetworkError property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isNetworkError
+ +
+ +
+ + +
+
+

isNetworkError property + Null safety +

+ + + +
+ +
+ bool + isNetworkError + + +
+ + + + +
+

Implementation

+
bool get isNetworkError => _errorFlags.getBooleanOrFalse('isNetworkError');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html new file mode 100644 index 00000000..d8569a2a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html @@ -0,0 +1,169 @@ + + + + + + + + isPKCENotAvailable property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isPKCENotAvailable
+ +
+ +
+ + +
+
+

isPKCENotAvailable property + Null safety +

+ + + +
+ +
+ bool + isPKCENotAvailable + + +
+ + + + +
+

Implementation

+
bool get isPKCENotAvailable =>
+    _errorFlags.getBooleanOrFalse('isPKCENotAvailable');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html new file mode 100644 index 00000000..a1f6d14c --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html @@ -0,0 +1,169 @@ + + + + + + + + isPasswordAlreadyUsed property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isPasswordAlreadyUsed
+ +
+ +
+ + +
+
+

isPasswordAlreadyUsed property + Null safety +

+ + + +
+ +
+ bool + isPasswordAlreadyUsed + + +
+ + + + +
+

Implementation

+
bool get isPasswordAlreadyUsed =>
+    _errorFlags.getBooleanOrFalse('isPasswordAlreadyUsed');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html new file mode 100644 index 00000000..33d790b7 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html @@ -0,0 +1,169 @@ + + + + + + + + isPasswordLeaked property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isPasswordLeaked
+ +
+ +
+ + +
+
+

isPasswordLeaked property + Null safety +

+ + + +
+ +
+ bool + isPasswordLeaked + + +
+ + + + +
+

Implementation

+
bool get isPasswordLeaked =>
+    _errorFlags.getBooleanOrFalse('isPasswordLeaked');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html new file mode 100644 index 00000000..8b41f64f --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html @@ -0,0 +1,169 @@ + + + + + + + + isPasswordNotStrongEnough property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isPasswordNotStrongEnough
+ +
+ +
+ + +
+
+

isPasswordNotStrongEnough property + Null safety +

+ + + +
+ +
+ bool + isPasswordNotStrongEnough + + +
+ + + + +
+

Implementation

+
bool get isPasswordNotStrongEnough =>
+    _errorFlags.getBooleanOrFalse('isPasswordNotStrongEnough');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html new file mode 100644 index 00000000..a4b762e6 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html @@ -0,0 +1,169 @@ + + + + + + + + isRefreshTokenDeleted property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isRefreshTokenDeleted
+ +
+ +
+ + +
+
+

isRefreshTokenDeleted property + Null safety +

+ + + +
+ +
+ bool + isRefreshTokenDeleted + + +
+ + + + +
+

Implementation

+
bool get isRefreshTokenDeleted =>
+    _errorFlags.getBooleanOrFalse('isRefreshTokenDeleted');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html new file mode 100644 index 00000000..cb995693 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html @@ -0,0 +1,168 @@ + + + + + + + + isRuleError property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isRuleError
+ +
+ +
+ + +
+
+

isRuleError property + Null safety +

+ + + +
+ +
+ bool + isRuleError + + +
+ + + + +
+

Implementation

+
bool get isRuleError => _errorFlags.getBooleanOrFalse('isRuleError');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html new file mode 100644 index 00000000..aa937c62 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html @@ -0,0 +1,169 @@ + + + + + + + + isTooManyAttempts property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isTooManyAttempts
+ +
+ +
+ + +
+
+

isTooManyAttempts property + Null safety +

+ + + +
+ +
+ bool + isTooManyAttempts + + +
+ + + + +
+

Implementation

+
bool get isTooManyAttempts =>
+    _errorFlags.getBooleanOrFalse('isTooManyAttempts');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html new file mode 100644 index 00000000..56c31b56 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html @@ -0,0 +1,169 @@ + + + + + + + + isVerificationRequired property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isVerificationRequired
+ +
+ +
+ + +
+
+

isVerificationRequired property + Null safety +

+ + + +
+ +
+ bool + isVerificationRequired + + +
+ + + + +
+

Implementation

+
bool get isVerificationRequired =>
+    _errorFlags.getBooleanOrFalse('isVerificationRequired');
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html new file mode 100644 index 00000000..7f158a2f --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html @@ -0,0 +1,163 @@ + + + + + + + + message property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
message
+ +
+ +
+ + +
+
+

message property + Null safety +

+ +
+ String + message +
final, inherited
+ +
+ + + +
+

Implementation

+
final String message;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html new file mode 100644 index 00000000..01422e9b --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html @@ -0,0 +1,163 @@ + + + + + + + + statusCode property - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
statusCode
+ +
+ +
+ + +
+
+

statusCode property + Null safety +

+ +
+ int + statusCode +
final
+ +
+ + + +
+

Implementation

+
final int statusCode;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html new file mode 100644 index 00000000..a12d2255 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html @@ -0,0 +1,183 @@ + + + + + + + + toString method - ApiException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
toString
+ +
+ +
+ + +
+
+

toString method + Null safety +

+ +
+ +
+
    +
  1. @override
  2. +
+
+ +String +toString() + +
inherited
+ +
+ +
+

A string representation of this object.

+

Some classes have a default textual representation, +often paired with a static parse function (like int.parse). +These classes will provide the textual representation as +their string representation.

+

Other classes have no meaningful textual representation +that a program will care about. +Such classes will typically override toString to provide +useful information when inspecting the object, +mainly for debugging or logging.

+
+ + + +
+

Implementation

+
@override
+String toString() => '$code: $message';
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html b/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html new file mode 100644 index 00000000..70cc7745 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html @@ -0,0 +1,274 @@ + + + + + + + + Auth0 class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
Auth0
+ +
+ +
+ + +
+
+

Auth0 class + Null safety + +

+ + +
+

Primary interface for interacting with Auth0 using web authentication, or the authentication API.

+
+ + + + +
+

Constructors

+ +
+
+ Auth0(String domain, String clientId) +
+
+ Creates an intance of an Auth0 client with the provided domain and clientId properties. +
+
+
+ +
+

Properties

+ +
+
+ api + AuthenticationApi + +
+
+ An instance of AuthenticationApi, the primary interface for interacting with the Auth0 Authentication API +
read-only
+ +
+ +
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+ webAuthentication + WebAuthentication + +
+
+ An instance of WebAuthentication, the primary interface for interacting with the Auth0 Universal Login page. +
read-only
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html new file mode 100644 index 00000000..d911039c --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html @@ -0,0 +1,143 @@ + + + + + + + + Auth0 constructor - Auth0 - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
Auth0
+ +
+ +
+ + +
+
+

Auth0 constructor + Null safety +

+ +
+ Auth0(
  1. String domain,
  2. +
  3. String clientId
  4. +
) +
+ + +
+

Creates an intance of an Auth0 client with the provided domain and clientId properties.

+

domain and clientId are both values that can be retrieved from the application in your Auth0 Dashboard.

+
+ + + +
+

Implementation

+
Auth0(final String domain, final String clientId)
+    : _account = Account(domain, clientId);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html new file mode 100644 index 00000000..f10c2bb2 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html @@ -0,0 +1,158 @@ + + + + + + + + api property - Auth0 class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
api
+ +
+ +
+ + +
+
+

api property + Null safety +

+ + + +
+ +
+ AuthenticationApi + api + + +
+ + +
+

An instance of AuthenticationApi, the primary interface for interacting with the Auth0 Authentication API

+

Usage example:

+
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
+
+final result = await auth0.api.login({
+  usernameOrEmail: 'my@email.com',
+  password: 'my_password'
+  connectionOrRealm: 'Username-Password-Authentication'
+});
+
+final accessToken = result.accessToken;
+
+
+ + +
+

Implementation

+
AuthenticationApi get api => AuthenticationApi(_account, _userAgent);
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html new file mode 100644 index 00000000..286db633 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html @@ -0,0 +1,153 @@ + + + + + + + + webAuthentication property - Auth0 class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
webAuthentication
+ +
+ +
+ + +
+
+

webAuthentication property + Null safety +

+ + + +
+ +
+ WebAuthentication + webAuthentication + + +
+ + +
+

An instance of WebAuthentication, the primary interface for interacting with the Auth0 Universal Login page.

+

Usage example:

+
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
+final result = await auth0.webAuthentication.login();
+final accessToken = result.accessToken;
+
+
+ + +
+

Implementation

+
WebAuthentication get webAuthentication =>
+    WebAuthentication(_account, _userAgent);
+
+ +
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html new file mode 100644 index 00000000..0929be64 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html @@ -0,0 +1,336 @@ + + + + + + + + AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
AuthenticationApi
+ +
+ +
+ + +
+
+

AuthenticationApi class + Null safety + +

+ + +
+

An interface for calling some of the endpoints in Auth0's Authentication API.

+

This class presents building blocks for doing more fine-grained authentication with Auth0 using Username and Password login. Unlike +WebAuthentication, these do not use Auth0 Universal Login (the recommended way of doing authentication), +and thus users are not redirected to Auth0 for authentication.

+

It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as Auth0.api.

+

Usage example:

+
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
+
+final result = await auth0.api.login({
+  usernameOrEmail: 'my@email.com',
+  password: 'my_password'
+  connectionOrRealm: 'Username-Password-Authentication'
+})
+
+final accessToken = result.accessToken;
+
+
+ + + + +
+

Constructors

+ +
+
+ AuthenticationApi(Account _account, UserAgent _userAgent) +
+
+ +
+
+
+ +
+

Properties

+ +
+
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+
+ + +
+

Methods

+
+
+ login({required String usernameOrEmail, required String password, required String connectionOrRealm, String? audience, Set<String> scopes = const {}, Map<String, String> parameters = const {}}) + Future<Credentials> + + + +
+
+ Authenticates the user using a usernameOrEmail and a password, with the specified connectionOrRealm. If successful, it returns +a set of tokens, as well as the user's profile (constructed from ID token claims). + + +
+ +
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ renewCredentials({required String refreshToken, Set<String> scopes = const {}, Map<String, String> parameters = const {}}) + Future<Credentials> + + + +
+
+ Uses a refreshToken to get a new access token. + + +
+ +
+ resetPassword({required String email, required String connection, Map<String, String> parameters = const {}}) + Future<void> + + + +
+
+ Initiates a reset of password of the user with the specific email address in the specific connection. + + +
+ +
+ signup({required String email, required String password, String? username, required String connection, Map<String, String> userMetadata = const {}, Map<String, String> parameters = const {}}) + Future<DatabaseUser> + + + +
+
+ Registers a new user with the specified email address and password in the specified connection. + + +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+ userProfile({required String accessToken, Map<String, String> parameters = const {}}) + Future<UserProfile> + + + +
+
+ Fetches the user's profile from the /userinfo endpoint. An accessToken from a successful authentication call must be supplied. + + +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html new file mode 100644 index 00000000..56d98436 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html @@ -0,0 +1,141 @@ + + + + + + + + AuthenticationApi constructor - AuthenticationApi - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
AuthenticationApi
+ +
+ +
+ + +
+
+

AuthenticationApi constructor + Null safety +

+ +
+ AuthenticationApi(
  1. Account _account,
  2. +
  3. UserAgent _userAgent
  4. +
) +
+ + + + + +
+

Implementation

+
AuthenticationApi(this._account, this._userAgent);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html new file mode 100644 index 00000000..56247cf4 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html @@ -0,0 +1,186 @@ + + + + + + + + login method - AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
login
+ +
+ +
+ + +
+
+

login method + Null safety +

+ +
+ + +Future<Credentials> +login(
  1. {required String usernameOrEmail,
  2. +
  3. required String password,
  4. +
  5. required String connectionOrRealm,
  6. +
  7. String? audience,
  8. +
  9. Set<String> scopes = const {},
  10. +
  11. Map<String, String> parameters = const {}}
  12. +
) + + + +
+ +
+

Authenticates the user using a usernameOrEmail and a password, with the specified connectionOrRealm. If successful, it returns +a set of tokens, as well as the user's profile (constructed from ID token claims).

+

If using the default username and password database connection, connectionOrRealm should be set to Username-Password-Authentication.

+

Endpoint docs

+

https://auth0.com/docs/api/authentication#login

+

Notes

+
    +
  • audience relates to the API Identifier you want to reference in your access tokens (see API settings)
  • +
  • scopes defaults to openid profile email
  • +
  • parameters can be used to sent through custom parameters to the endpoint to be picked up in a Rule or Action.
  • +
+

Usage example

+
final result = await auth0.api.login({
+  usernameOrEmail: 'my@email.com',
+  password: 'my_password'
+  connectionOrRealm: 'Username-Password-Authentication'
+});
+
+
+ + + +
+

Implementation

+
Future<Credentials> login({
+  required final String usernameOrEmail,
+  required final String password,
+  required final String connectionOrRealm,
+  final String? audience,
+  final Set<String> scopes = const {},
+  final Map<String, String> parameters = const {},
+}) =>
+    Auth0FlutterAuthPlatform.instance
+        .login(_createApiRequest(AuthLoginOptions(
+      usernameOrEmail: usernameOrEmail,
+      password: password,
+      connectionOrRealm: connectionOrRealm,
+      audience: audience,
+      scopes: scopes,
+      parameters: parameters,
+    )));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html new file mode 100644 index 00000000..f824128f --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html @@ -0,0 +1,180 @@ + + + + + + + + renewCredentials method - AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
renewCredentials
+ +
+ +
+ + +
+
+

renewCredentials method + Null safety +

+ +
+ + +Future<Credentials> +renewCredentials(
  1. {required String refreshToken,
  2. +
  3. Set<String> scopes = const {},
  4. +
  5. Map<String, String> parameters = const {}}
  6. +
) + + + +
+ +
+

Uses a refreshToken to get a new access token.

+

Endpoint

+

https://auth0.com/docs/api/authentication#refresh-token

+

Notes

+
    +
  • Refresh tokens can be retrieved by specifying the offline_access scope during authentication.
  • +
  • scopes can be specified if a reduced set of scopes is desired.
  • +
+

Further reading

+

Refresh Tokens on Auth0 docs

+

Usage example

+
final result = await auth0.api.login({
+  usernameOrEmail: 'my@email.com',
+  password: 'my_password'
+  connectionOrRealm: 'Username-Password-Authentication',
+  scopes: {'openid', 'profile', 'email', 'offline_access'}
+});
+
+if (result.refreshToken != null) {
+   await auth0.api.renewCredentials(refreshToken: result.refreshToken!);
+}
+
+
+ + + +
+

Implementation

+
Future<Credentials> renewCredentials({
+  required final String refreshToken,
+  final Set<String> scopes = const {},
+  final Map<String, String> parameters = const {},
+}) =>
+    Auth0FlutterAuthPlatform.instance.renew(_createApiRequest(
+        AuthRenewOptions(
+            refreshToken: refreshToken,
+            scopes: scopes,
+            parameters: parameters)));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html new file mode 100644 index 00000000..9e26b32d --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html @@ -0,0 +1,163 @@ + + + + + + + + resetPassword method - AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
resetPassword
+ +
+ +
+ + +
+
+

resetPassword method + Null safety +

+ +
+ + +Future<void> +resetPassword(
  1. {required String email,
  2. +
  3. required String connection,
  4. +
  5. Map<String, String> parameters = const {}}
  6. +
) + + + +
+ +
+

Initiates a reset of password of the user with the specific email address in the specific connection.

+

Endpoint

+

https://auth0.com/docs/api/authentication#change-password

+

Notes

+

Calling this endpoint does not reset the user's password in itself, but it asks Auth0 to send the user +an email with a link they can use to reset their password on the web.

+

Arbitrary parameters can be specified and then picked up in a custom Auth0 Action or + Rule.

+
+ + + +
+

Implementation

+
Future<void> resetPassword(
+        {required final String email,
+        required final String connection,
+        final Map<String, String> parameters = const {}}) =>
+    Auth0FlutterAuthPlatform.instance.resetPassword(_createApiRequest(
+        AuthResetPasswordOptions(
+            email: email, connection: connection, parameters: parameters)));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html new file mode 100644 index 00000000..3431ce7f --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html @@ -0,0 +1,173 @@ + + + + + + + + signup method - AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
signup
+ +
+ +
+ + +
+
+

signup method + Null safety +

+ +
+ + +Future<DatabaseUser> +signup(
  1. {required String email,
  2. +
  3. required String password,
  4. +
  5. String? username,
  6. +
  7. required String connection,
  8. +
  9. Map<String, String> userMetadata = const {},
  10. +
  11. Map<String, String> parameters = const {}}
  12. +
) + + + +
+ +
+

Registers a new user with the specified email address and password in the specified connection.

+

Endpoint +https://auth0.com/docs/api/authentication#signup

+

Notes

+
    +
  • username is only required if the connection you specify requires it
  • +
+
+ + + +
+

Implementation

+
Future<DatabaseUser> signup(
+        {required final String email,
+        required final String password,
+        final String? username,
+        required final String connection,
+        final Map<String, String> userMetadata = const {},
+        final Map<String, String> parameters = const {}}) =>
+    Auth0FlutterAuthPlatform.instance.signup(_createApiRequest(
+        AuthSignupOptions(
+            email: email,
+            password: password,
+            connection: connection,
+            username: username,
+            userMetadata: userMetadata,
+            parameters: parameters)));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html new file mode 100644 index 00000000..63d821a9 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html @@ -0,0 +1,165 @@ + + + + + + + + userProfile method - AuthenticationApi class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
userProfile
+ +
+ +
+ + +
+
+

userProfile method + Null safety +

+ +
+ + +Future<UserProfile> +userProfile(
  1. {required String accessToken,
  2. +
  3. Map<String, String> parameters = const {}}
  4. +
) + + + +
+ +
+

Fetches the user's profile from the /userinfo endpoint. An accessToken from a successful authentication call must be supplied.

+

Endpoint

+

https://auth0.com/docs/api/authentication#user-profile

+

Usage example

+
final result = await auth0.api.login({
+  usernameOrEmail: 'my@email.com',
+  password: 'my_password'
+  connectionOrRealm: 'Username-Password-Authentication'
+});
+
+final profile = await auth0.api.userProfile({ accessToken: result.accessToken });
+
+
+ + + +
+

Implementation

+
Future<UserProfile> userProfile(
+        {required final String accessToken,
+        final Map<String, String> parameters = const {}}) =>
+    Auth0FlutterAuthPlatform.instance.userInfo(_createApiRequest(
+        AuthUserInfoOptions(
+            accessToken: accessToken, parameters: parameters)));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html b/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html new file mode 100644 index 00000000..1aa62cae --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html @@ -0,0 +1,330 @@ + + + + + + + + Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
Credentials
+ +
+ +
+ + +
+
+

Credentials class + Null safety + +

+ + +
+

A collection of authentication artifacts obtained from Auth0 when a user logs in.

+
+ + + + +
+

Constructors

+ +
+
+ Credentials({required String idToken, required String accessToken, String? refreshToken, required DateTime expiresAt, Set<String> scopes = const {}, required UserProfile userProfile}) +
+
+ +
+
+ Credentials.fromMap(Map result) +
+
+ +
factory
+
+
+
+ +
+

Properties

+ +
+
+ accessToken + String + +
+
+ Token that can be used to make authenticated requests to the specified API (the audience value used on login). +
final
+ +
+ +
+ expiresAt + DateTime + +
+
+ The absolute date and time of when the access token expiries. +
final
+ +
+ +
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ idToken + String + +
+
+ A JSON Web Token that contains the user information. +
final
+ +
+ +
+ refreshToken + String? + +
+
+ Token that can be used to request a new access token. +
final
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+ scopes + Set<String> + +
+
+ The scopes that have been grated by the authorization server. +
final
+ +
+ +
+ userProfile + UserProfile + +
+
+ Properties and attributes relating to the authenticated user. +
final
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html new file mode 100644 index 00000000..e1852204 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html @@ -0,0 +1,151 @@ + + + + + + + + Credentials.fromMap constructor - Credentials - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
Credentials.fromMap
+ +
+ +
+ + +
+
+

Credentials.fromMap constructor + Null safety +

+ +
+ Credentials.fromMap(
  1. Map result
  2. +
) +
+ + + + + +
+

Implementation

+
factory Credentials.fromMap(final Map<dynamic, dynamic> result) =>
+    Credentials(
+      idToken: result['idToken'] as String,
+      accessToken: result['accessToken'] as String,
+      refreshToken: result['refreshToken'] as String?,
+      expiresAt: DateTime.parse(result['expiresAt'] as String),
+      scopes: Set<String>.from(result['scopes'] as List<Object?>),
+      userProfile: UserProfile.fromMap(Map<String, dynamic>.from(
+          result['userProfile'] as Map<dynamic, dynamic>)),
+    );
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html new file mode 100644 index 00000000..35156baf --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html @@ -0,0 +1,154 @@ + + + + + + + + Credentials constructor - Credentials - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
Credentials
+ +
+ +
+ + +
+
+

Credentials constructor + Null safety +

+ +
+ Credentials(
  1. {required String idToken,
  2. +
  3. required String accessToken,
  4. +
  5. String? refreshToken,
  6. +
  7. required DateTime expiresAt,
  8. +
  9. Set<String> scopes = const {},
  10. +
  11. required UserProfile userProfile}
  12. +
) +
+ + + + + +
+

Implementation

+
Credentials({
+  required this.idToken,
+  required this.accessToken,
+  this.refreshToken,
+  required this.expiresAt,
+  this.scopes = const {},
+  required this.userProfile,
+});
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html new file mode 100644 index 00000000..5305ca2a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html @@ -0,0 +1,152 @@ + + + + + + + + accessToken property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
accessToken
+ +
+ +
+ + +
+
+

accessToken property + Null safety +

+ +
+ String + accessToken +
final
+ +
+ +
+

Token that can be used to make authenticated requests to the specified API (the audience value used on login).

+

Futher reading

+ +
+ + +
+

Implementation

+
final String accessToken;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html new file mode 100644 index 00000000..f874ebf9 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html @@ -0,0 +1,147 @@ + + + + + + + + expiresAt property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
expiresAt
+ +
+ +
+ + +
+
+

expiresAt property + Null safety +

+ +
+ DateTime + expiresAt +
final
+ +
+ +
+

The absolute date and time of when the access token expiries.

+
+ + +
+

Implementation

+
final DateTime expiresAt;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html new file mode 100644 index 00000000..fbefe4ae --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html @@ -0,0 +1,151 @@ + + + + + + + + idToken property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
idToken
+ +
+ +
+ + +
+
+

idToken property + Null safety +

+ +
+ String + idToken +
final
+ +
+ +
+

A JSON Web Token that contains the user information.

+

Important: The ID tokens obtained from Web Auth login are automatically validated by the underlying native SDK, ensuring their +contents have not been tampered with.

+

This is not the case for the ID tokens obtained when using the authentication API directly.

+

You must validate ID tokens received from the Authentication API client before using the information they contain.

+
+ + +
+

Implementation

+
final String idToken;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html new file mode 100644 index 00000000..f9483350 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html @@ -0,0 +1,149 @@ + + + + + + + + refreshToken property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
refreshToken
+ +
+ +
+ + +
+
+

refreshToken property + Null safety +

+ +
+ String? + refreshToken +
final
+ +
+ +
+

Token that can be used to request a new access token.

+

The scope offline_access must have been requested on login for a refresh token to be returned.

+

Read more about refresh tokens.

+
+ + +
+

Implementation

+
final String? refreshToken;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html new file mode 100644 index 00000000..b8531562 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html @@ -0,0 +1,148 @@ + + + + + + + + scopes property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
scopes
+ +
+ +
+ + +
+
+

scopes property + Null safety +

+ +
+ Set<String> + scopes +
final
+ +
+ +
+

The scopes that have been grated by the authorization server.

+

Read more about scopes.

+
+ + +
+

Implementation

+
final Set<String> scopes;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html new file mode 100644 index 00000000..dc9e0078 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html @@ -0,0 +1,148 @@ + + + + + + + + userProfile property - Credentials class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
userProfile
+ +
+ +
+ + +
+
+

userProfile property + Null safety +

+ +
+ UserProfile + userProfile +
final
+ +
+ +
+

Properties and attributes relating to the authenticated user.

+

Read more about Auth0 User Profiles

+
+ + +
+

Implementation

+
final UserProfile userProfile;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html new file mode 100644 index 00000000..0252b60f --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html @@ -0,0 +1,287 @@ + + + + + + + + IdTokenValidationConfig class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
IdTokenValidationConfig
+ +
+ +
+ + +
+
+

IdTokenValidationConfig class + Null safety + +

+ + +
+

Configuration settings for ID token validation.

+
+ + + + +
+

Constructors

+ +
+
+ IdTokenValidationConfig({int? leeway, String? issuer, int? maxAge}) +
+
+ +
const
+
+
+
+ +
+

Properties

+ +
+
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ issuer + String? + +
+
+ The issuer to be used for validation of JWTs. Defaults to the domain used to when calling Auth0.new. +
final
+ +
+ +
+ leeway + int? + +
+
+ The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms. +
final
+ +
+ +
+ maxAge + int? + +
+
+ Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0. +
final
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html new file mode 100644 index 00000000..3e351542 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html @@ -0,0 +1,140 @@ + + + + + + + + IdTokenValidationConfig constructor - IdTokenValidationConfig - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
IdTokenValidationConfig
+ +
+ +
+ + +
+
+

IdTokenValidationConfig constructor + Null safety +

+ +
const + IdTokenValidationConfig(
  1. {int? leeway,
  2. +
  3. String? issuer,
  4. +
  5. int? maxAge}
  6. +
) +
+ + + + + +
+

Implementation

+
const IdTokenValidationConfig({this.leeway, this.issuer, this.maxAge});
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html new file mode 100644 index 00000000..f261cf25 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html @@ -0,0 +1,143 @@ + + + + + + + + issuer property - IdTokenValidationConfig class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
issuer
+ +
+ +
+ + +
+
+

issuer property + Null safety +

+ +
+ String? + issuer +
final
+ +
+ +
+

The issuer to be used for validation of JWTs. Defaults to the domain used to when calling Auth0.new.

+
+ + +
+

Implementation

+
final String? issuer;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html new file mode 100644 index 00000000..83325f1a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html @@ -0,0 +1,143 @@ + + + + + + + + leeway property - IdTokenValidationConfig class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
leeway
+ +
+ +
+ + +
+
+

leeway property + Null safety +

+ +
+ int? + leeway +
final
+ +
+ +
+

The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms.

+
+ + +
+

Implementation

+
final int? leeway;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html new file mode 100644 index 00000000..fc6b5ae3 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html @@ -0,0 +1,143 @@ + + + + + + + + maxAge property - IdTokenValidationConfig class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
maxAge
+ +
+ +
+ + +
+
+

maxAge property + Null safety +

+ +
+ int? + maxAge +
final
+ +
+ +
+

Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0.

+
+ + +
+

Implementation

+
final int? maxAge;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html new file mode 100644 index 00000000..3fa30f59 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html @@ -0,0 +1,511 @@ + + + + + + + + UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
UserProfile
+ +
+ +
+ + +
+
+

UserProfile class + Null safety + +

+ + +
+

A collection of properties that represents the authenticated user, extracted from ID token claims.

+
+ + + + +
+

Constructors

+ +
+
+ UserProfile({required String sub, String? name, String? givenName, String? familyName, String? middleName, String? nickname, String? preferredUsername, Uri? profileURL, Uri? pictureURL, Uri? websiteURL, String? email, bool? isEmailVerified, String? gender, String? birthdate, String? zoneinfo, String? locale, String? phoneNumber, bool? isPhoneNumberVerified, Map<String, String>? address, DateTime? updatedAt, Map<String, dynamic>? customClaims}) +
+
+ +
const
+
+
+ UserProfile.fromMap(Map<String, dynamic> result) +
+
+ +
factory
+
+
+
+ +
+

Properties

+ +
+
+ address + Map<String, String>? + +
+
+ The address of the user. +
final
+ +
+ +
+ birthdate + String? + +
+
+ The birthdate of the user. +
final
+ +
+ +
+ customClaims + Map<String, dynamic>? + +
+
+ Any custom claims +
final
+ +
+ +
+ email + String? + +
+
+ The email of the user. +
final
+ +
+ +
+ familyName + String? + +
+
+ The last name of the user. +
final
+ +
+ +
+ gender + String? + +
+
+ The gender of the user. +
final
+ +
+ +
+ givenName + String? + +
+
+ The first name of the user. +
final
+ +
+ +
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ isEmailVerified + bool? + +
+
+ If the user's email is verified. +
final
+ +
+ +
+ isPhoneNumberVerified + bool? + +
+
+ If the user's phone number is verified. +
final
+ +
+ +
+ locale + String? + +
+
+ The locale of the user. +
final
+ +
+ +
+ middleName + String? + +
+
+ The middle name of the user. +
final
+ +
+ +
+ name + String? + +
+
+ The name of the user. +
final
+ +
+ +
+ nickname + String? + +
+
+ The nickname of the user. +
final
+ +
+ +
+ phoneNumber + String? + +
+
+ The phone number of the user. +
final
+ +
+ +
+ pictureURL + Uri? + +
+
+ The URL of the user's picture. +
final
+ +
+ +
+ preferredUsername + String? + +
+
+ The preferred username of the user. +
final
+ +
+ +
+ profileURL + Uri? + +
+
+ The URL of the user's profile page. +
final
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+ sub + String + +
+
+ The Auth0 user identifier. +
final
+ +
+ +
+ updatedAt + DateTime? + +
+
+ The date and time the user's information was last updated. +
final
+ +
+ +
+ websiteURL + Uri? + +
+
+ The URL of the user's website. +
final
+ +
+ +
+ zoneinfo + String? + +
+
+ The time zone of the user. +
final
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html new file mode 100644 index 00000000..5063d1c2 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html @@ -0,0 +1,193 @@ + + + + + + + + UserProfile.fromMap constructor - UserProfile - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
UserProfile.fromMap
+ +
+ +
+ + +
+
+

UserProfile.fromMap constructor + Null safety +

+ +
+ UserProfile.fromMap(
  1. Map<String, dynamic> result
  2. +
) +
+ + + + + +
+

Implementation

+
factory UserProfile.fromMap(final Map<String, dynamic> result) => UserProfile(
+      sub: result['sub'] as String,
+      name: result['name'] as String?,
+      givenName: result['given_name'] as String?,
+      familyName: result['family_name'] as String?,
+      middleName: result['middle_name'] as String?,
+      nickname: result['nickname'] as String?,
+      preferredUsername: result['preferred_username'] as String?,
+      profileURL: result['profile'] != null
+          ? Uri.parse(result['profile'] as String)
+          : null,
+      pictureURL: result['picture'] != null
+          ? Uri.parse(result['picture'] as String)
+          : null,
+      websiteURL: result['website'] != null
+          ? Uri.parse(result['website'] as String)
+          : null,
+      email: result['email'] as String?,
+      isEmailVerified: result['email_verified'] as bool?,
+      gender: result['gender'] as String?,
+      birthdate: result['birthdate'] as String?,
+      zoneinfo: result['zoneinfo'] as String?,
+      locale: result['locale'] as String?,
+      phoneNumber: result['phone_number'] as String?,
+      isPhoneNumberVerified: result['phone_number_verified'] as bool?,
+      address: result['address'] != null
+          ? Map<String, String>.from(
+              result['address'] as Map<dynamic, dynamic>)
+          : null,
+      updatedAt: result['updated_at'] != null
+          ? DateTime.parse(result['updated_at'] as String)
+          : null,
+      customClaims: result['custom_claims'] != null
+          ? Map<String, dynamic>.from(
+              result['custom_claims'] as Map<dynamic, dynamic>)
+          : null,
+    );
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html new file mode 100644 index 00000000..9b90b660 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html @@ -0,0 +1,199 @@ + + + + + + + + UserProfile constructor - UserProfile - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
UserProfile
+ +
+ +
+ + +
+
+

UserProfile constructor + Null safety +

+ +
const + UserProfile(
  1. {required String sub,
  2. +
  3. String? name,
  4. +
  5. String? givenName,
  6. +
  7. String? familyName,
  8. +
  9. String? middleName,
  10. +
  11. String? nickname,
  12. +
  13. String? preferredUsername,
  14. +
  15. Uri? profileURL,
  16. +
  17. Uri? pictureURL,
  18. +
  19. Uri? websiteURL,
  20. +
  21. String? email,
  22. +
  23. bool? isEmailVerified,
  24. +
  25. String? gender,
  26. +
  27. String? birthdate,
  28. +
  29. String? zoneinfo,
  30. +
  31. String? locale,
  32. +
  33. String? phoneNumber,
  34. +
  35. bool? isPhoneNumberVerified,
  36. +
  37. Map<String, String>? address,
  38. +
  39. DateTime? updatedAt,
  40. +
  41. Map<String, dynamic>? customClaims}
  42. +
) +
+ + + + + +
+

Implementation

+
const UserProfile({
+  required final this.sub,
+  final this.name,
+  final this.givenName,
+  final this.familyName,
+  final this.middleName,
+  final this.nickname,
+  final this.preferredUsername,
+  final this.profileURL,
+  final this.pictureURL,
+  final this.websiteURL,
+  final this.email,
+  final this.isEmailVerified,
+  final this.gender,
+  final this.birthdate,
+  final this.zoneinfo,
+  final this.locale,
+  final this.phoneNumber,
+  final this.isPhoneNumberVerified,
+  final this.address,
+  final this.updatedAt,
+  final this.customClaims,
+});
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html new file mode 100644 index 00000000..1ac52639 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html @@ -0,0 +1,163 @@ + + + + + + + + address property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
address
+ +
+ +
+ + +
+
+

address property + Null safety +

+ +
+ Map<String, String>? + address +
final
+ +
+ +
+

The address of the user.

+

Requires the address scope.

+
+ + +
+

Implementation

+
final Map<String, String>? address;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html new file mode 100644 index 00000000..cd39c5c5 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html @@ -0,0 +1,163 @@ + + + + + + + + birthdate property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
birthdate
+ +
+ +
+ + +
+
+

birthdate property + Null safety +

+ +
+ String? + birthdate +
final
+ +
+ +
+

The birthdate of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? birthdate;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html new file mode 100644 index 00000000..71b932ba --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html @@ -0,0 +1,162 @@ + + + + + + + + customClaims property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
customClaims
+ +
+ +
+ + +
+
+

customClaims property + Null safety +

+ +
+ Map<String, dynamic>? + customClaims +
final
+ +
+ +
+

Any custom claims

+
+ + +
+

Implementation

+
final Map<String, dynamic>? customClaims;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html new file mode 100644 index 00000000..46e47eae --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html @@ -0,0 +1,163 @@ + + + + + + + + email property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
email
+ +
+ +
+ + +
+
+

email property + Null safety +

+ +
+ String? + email +
final
+ +
+ +
+

The email of the user.

+

Requires the email scope.

+
+ + +
+

Implementation

+
final String? email;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html new file mode 100644 index 00000000..a230b33b --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html @@ -0,0 +1,163 @@ + + + + + + + + familyName property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
familyName
+ +
+ +
+ + +
+
+

familyName property + Null safety +

+ +
+ String? + familyName +
final
+ +
+ +
+

The last name of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? familyName;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html new file mode 100644 index 00000000..cc8833b7 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html @@ -0,0 +1,163 @@ + + + + + + + + gender property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
gender
+ +
+ +
+ + +
+
+

gender property + Null safety +

+ +
+ String? + gender +
final
+ +
+ +
+

The gender of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? gender;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html new file mode 100644 index 00000000..823d404c --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html @@ -0,0 +1,163 @@ + + + + + + + + givenName property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
givenName
+ +
+ +
+ + +
+
+

givenName property + Null safety +

+ +
+ String? + givenName +
final
+ +
+ +
+

The first name of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? givenName;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html new file mode 100644 index 00000000..f2a38192 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html @@ -0,0 +1,163 @@ + + + + + + + + isEmailVerified property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isEmailVerified
+ +
+ +
+ + +
+
+

isEmailVerified property + Null safety +

+ +
+ bool? + isEmailVerified +
final
+ +
+ +
+

If the user's email is verified.

+

Requires the email scope.

+
+ + +
+

Implementation

+
final bool? isEmailVerified;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html new file mode 100644 index 00000000..1a9ed490 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html @@ -0,0 +1,163 @@ + + + + + + + + isPhoneNumberVerified property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
isPhoneNumberVerified
+ +
+ +
+ + +
+
+

isPhoneNumberVerified property + Null safety +

+ +
+ bool? + isPhoneNumberVerified +
final
+ +
+ +
+

If the user's phone number is verified.

+

Requires the phone scope.

+
+ + +
+

Implementation

+
final bool? isPhoneNumberVerified;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html new file mode 100644 index 00000000..bb73dd34 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html @@ -0,0 +1,163 @@ + + + + + + + + locale property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
locale
+ +
+ +
+ + +
+
+

locale property + Null safety +

+ +
+ String? + locale +
final
+ +
+ +
+

The locale of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? locale;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html new file mode 100644 index 00000000..89257643 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html @@ -0,0 +1,163 @@ + + + + + + + + middleName property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
middleName
+ +
+ +
+ + +
+
+

middleName property + Null safety +

+ +
+ String? + middleName +
final
+ +
+ +
+

The middle name of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? middleName;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html new file mode 100644 index 00000000..8aad3202 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html @@ -0,0 +1,163 @@ + + + + + + + + name property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
name
+ +
+ +
+ + +
+
+

name property + Null safety +

+ +
+ String? + name +
final
+ +
+ +
+

The name of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? name;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html new file mode 100644 index 00000000..07463b7c --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html @@ -0,0 +1,163 @@ + + + + + + + + nickname property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
nickname
+ +
+ +
+ + +
+
+

nickname property + Null safety +

+ +
+ String? + nickname +
final
+ +
+ +
+

The nickname of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? nickname;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html new file mode 100644 index 00000000..5f41c595 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html @@ -0,0 +1,163 @@ + + + + + + + + phoneNumber property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
phoneNumber
+ +
+ +
+ + +
+
+

phoneNumber property + Null safety +

+ +
+ String? + phoneNumber +
final
+ +
+ +
+

The phone number of the user.

+

Requires the phone scope.

+
+ + +
+

Implementation

+
final String? phoneNumber;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html new file mode 100644 index 00000000..ae15c4af --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html @@ -0,0 +1,163 @@ + + + + + + + + pictureURL property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
pictureURL
+ +
+ +
+ + +
+
+

pictureURL property + Null safety +

+ +
+ Uri? + pictureURL +
final
+ +
+ +
+

The URL of the user's picture.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final Uri? pictureURL;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html new file mode 100644 index 00000000..9a267f77 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html @@ -0,0 +1,163 @@ + + + + + + + + preferredUsername property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
preferredUsername
+ +
+ +
+ + +
+
+

preferredUsername property + Null safety +

+ +
+ String? + preferredUsername +
final
+ +
+ +
+

The preferred username of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? preferredUsername;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html new file mode 100644 index 00000000..34087e92 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html @@ -0,0 +1,163 @@ + + + + + + + + profileURL property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
profileURL
+ +
+ +
+ + +
+
+

profileURL property + Null safety +

+ +
+ Uri? + profileURL +
final
+ +
+ +
+

The URL of the user's profile page.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final Uri? profileURL;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html new file mode 100644 index 00000000..ce1c17c3 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html @@ -0,0 +1,162 @@ + + + + + + + + sub property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
sub
+ +
+ +
+ + +
+
+

sub property + Null safety +

+ +
+ String + sub +
final
+ +
+ +
+

The Auth0 user identifier.

+
+ + +
+

Implementation

+
final String sub;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html new file mode 100644 index 00000000..b6716bc9 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html @@ -0,0 +1,163 @@ + + + + + + + + updatedAt property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
updatedAt
+ +
+ +
+ + +
+
+

updatedAt property + Null safety +

+ +
+ DateTime? + updatedAt +
final
+ +
+ +
+

The date and time the user's information was last updated.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final DateTime? updatedAt;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html new file mode 100644 index 00000000..fda019d2 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html @@ -0,0 +1,163 @@ + + + + + + + + websiteURL property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
websiteURL
+ +
+ +
+ + +
+
+

websiteURL property + Null safety +

+ +
+ Uri? + websiteURL +
final
+ +
+ +
+

The URL of the user's website.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final Uri? websiteURL;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html new file mode 100644 index 00000000..0eb5bc70 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html @@ -0,0 +1,163 @@ + + + + + + + + zoneinfo property - UserProfile class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
zoneinfo
+ +
+ +
+ + +
+
+

zoneinfo property + Null safety +

+ +
+ String? + zoneinfo +
final
+ +
+ +
+

The time zone of the user.

+

Requires the profile scope.

+
+ + +
+

Implementation

+
final String? zoneinfo;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html new file mode 100644 index 00000000..6284b8b4 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html @@ -0,0 +1,299 @@ + + + + + + + + WebAuthException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthException
+ +
+ +
+ + +
+
+

WebAuthException class + Null safety + +

+ + + + + + +
+

Constructors

+ +
+
+ WebAuthException(String code, String message, Map<String, dynamic> details) +
+
+ +
const
+
+
+ WebAuthException.fromPlatformException(PlatformException e) +
+
+ +
+
+ WebAuthException.unknown(String message) +
+
+ +
const
+
+
+
+ +
+

Properties

+ +
+
+ code + String + +
+
+ +
final, inherited
+ +
+ +
+ details + Map<String, dynamic> + +
+
+ +
final, inherited
+ +
+ +
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ message + String + +
+
+ +
final, inherited
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+
+ + +
+

Methods

+
+
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html new file mode 100644 index 00000000..181695d2 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html @@ -0,0 +1,141 @@ + + + + + + + + WebAuthException.fromPlatformException constructor - WebAuthException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthException.fromPlatformException
+ +
+ +
+ + +
+
+

WebAuthException.fromPlatformException constructor + Null safety +

+ +
+ WebAuthException.fromPlatformException(
  1. PlatformException e
  2. +
) +
+ + + + + +
+

Implementation

+
WebAuthException.fromPlatformException(final PlatformException e)
+    : this(e.code, e.messageString, e.detailsMap);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html new file mode 100644 index 00000000..f69460c4 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html @@ -0,0 +1,144 @@ + + + + + + + + WebAuthException constructor - WebAuthException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthException
+ +
+ +
+ + +
+
+

WebAuthException constructor + Null safety +

+ +
const + WebAuthException(
  1. String code,
  2. +
  3. String message,
  4. +
  5. Map<String, dynamic> details
  6. +
) +
+ + + + + +
+

Implementation

+
const WebAuthException(final String code, final String message,
+    final Map<String, dynamic> details)
+    : super(code, message, details);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html new file mode 100644 index 00000000..ce519b9a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html @@ -0,0 +1,140 @@ + + + + + + + + WebAuthException.unknown constructor - WebAuthException - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthException.unknown
+ +
+ +
+ + +
+
+

WebAuthException.unknown constructor + Null safety +

+ +
const + WebAuthException.unknown(
  1. String message
  2. +
) +
+ + + + + +
+

Implementation

+
const WebAuthException.unknown(final String message) : super.unknown(message);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html new file mode 100644 index 00000000..5bae622a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html @@ -0,0 +1,142 @@ + + + + + + + + code property - WebAuthException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
code
+ +
+ +
+ + +
+
+

code property + Null safety +

+ +
+ String + code +
final, inherited
+ +
+ + + +
+

Implementation

+
final String code;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html new file mode 100644 index 00000000..f99e83b2 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html @@ -0,0 +1,142 @@ + + + + + + + + details property - WebAuthException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
details
+ +
+ +
+ + +
+
+

details property + Null safety +

+ +
+ Map<String, dynamic> + details +
final, inherited
+ +
+ + + +
+

Implementation

+
final Map<String, dynamic> details;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html new file mode 100644 index 00000000..77051ede --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html @@ -0,0 +1,142 @@ + + + + + + + + message property - WebAuthException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
message
+ +
+ +
+ + +
+
+

message property + Null safety +

+ +
+ String + message +
final, inherited
+ +
+ + + +
+

Implementation

+
final String message;
+
+
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html new file mode 100644 index 00000000..94a8b03a --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html @@ -0,0 +1,162 @@ + + + + + + + + toString method - WebAuthException class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
toString
+ +
+ +
+ + +
+
+

toString method + Null safety +

+ +
+ +
+
    +
  1. @override
  2. +
+
+ +String +toString() + +
inherited
+ +
+ +
+

A string representation of this object.

+

Some classes have a default textual representation, +often paired with a static parse function (like int.parse). +These classes will provide the textual representation as +their string representation.

+

Other classes have no meaningful textual representation +that a program will care about. +Such classes will typically override toString to provide +useful information when inspecting the object, +mainly for debugging or logging.

+
+ + + +
+

Implementation

+
@override
+String toString() => '$code: $message';
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html new file mode 100644 index 00000000..67e570fb --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html @@ -0,0 +1,289 @@ + + + + + + + + WebAuthentication class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthentication
+ +
+ +
+ + +
+
+

WebAuthentication class + Null safety + +

+ + +
+

An interface for authenticating users using the Auth0 Universal Login page.

+

Authentication using Universal Login works by redirecting your user to a login page hosted on Auth0's servers. To achieve this on a native device, +this class uses the Auth0.Android and Auth0.Swift SDKs on Android and iOS respectively to +perform interactions with Universal Login.

+

It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as Auth0.webAuthentication.

+

Usage example:

+
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
+final result = await auth0.webAuthentication.login();
+final accessToken = result.accessToken;
+
+
+ + + + +
+

Constructors

+ +
+
+ WebAuthentication(Account _account, UserAgent _userAgent) +
+
+ +
+
+
+ +
+

Properties

+ +
+
+ hashCode + int + +
+
+ The hash code for this object. +
read-only, inherited
+ +
+ +
+ runtimeType + Type + +
+
+ A representation of the runtime type of the object. +
read-only, inherited
+ +
+ +
+
+ + +
+

Methods

+
+
+ login({String? audience, Set<String> scopes = const {}, String? redirectUrl, String? organizationId, String? invitationUrl, String? scheme, bool useEphemeralSession = false, Map<String, String> parameters = const {}, IdTokenValidationConfig idTokenValidationConfig = const IdTokenValidationConfig()}) + Future<Credentials> + + + +
+
+ Redirects the user to the Auth0 Universal Login page for authentication. If successful, it returns +a set of tokens, as well as the user's profile (constructed from ID token claims). + + +
+ +
+ logout({String? returnTo, String? scheme}) + Future<void> + + + +
+
+ Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application +once logout is complete. + + +
+ +
+ noSuchMethod(Invocation invocation) + → dynamic + + + +
+
+ Invoked when a non-existent method or property is accessed. +
inherited
+ +
+ +
+ toString() + String + + + +
+
+ A string representation of this object. +
inherited
+ +
+ +
+
+ +
+

Operators

+
+
+ operator ==(Object other) + bool + + + +
+
+ The equality operator. +
inherited
+ +
+ +
+
+ + + + + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html new file mode 100644 index 00000000..488b66f9 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html @@ -0,0 +1,138 @@ + + + + + + + + WebAuthentication constructor - WebAuthentication - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
WebAuthentication
+ +
+ +
+ + +
+
+

WebAuthentication constructor + Null safety +

+ +
+ WebAuthentication(
  1. Account _account,
  2. +
  3. UserAgent _userAgent
  4. +
) +
+ + + + + +
+

Implementation

+
WebAuthentication(this._account, this._userAgent);
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html new file mode 100644 index 00000000..c6cc0c0d --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html @@ -0,0 +1,190 @@ + + + + + + + + login method - WebAuthentication class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
login
+ +
+ +
+ + +
+
+

login method + Null safety +

+ +
+ + +Future<Credentials> +login(
  1. {String? audience,
  2. +
  3. Set<String> scopes = const {},
  4. +
  5. String? redirectUrl,
  6. +
  7. String? organizationId,
  8. +
  9. String? invitationUrl,
  10. +
  11. String? scheme,
  12. +
  13. bool useEphemeralSession = false,
  14. +
  15. Map<String, String> parameters = const {},
  16. +
  17. IdTokenValidationConfig idTokenValidationConfig = const IdTokenValidationConfig()}
  18. +
) + + + +
+ +
+

Redirects the user to the Auth0 Universal Login page for authentication. If successful, it returns +a set of tokens, as well as the user's profile (constructed from ID token claims).

+

If redirectUrl is not specified, a default URL is used that incorporates the domain value specified to Auth0.new, and scheme on Android, or the +bundle identifier in iOS. redirectUrl must appear in your Allowed Callback URLs list for the Auth0 app. Read more about redirecting users.

+

How the ID token is validated can be configured using idTokenValidationConfig, but in general the defaults for this are adequate.

+

Additonal notes:

+
    +
  • (iOS only): useEphemeralSession controls whether shared persistent storage is used for cookies. Read more on the effects this setting has
  • +
  • (Android only): specify scheme if you're using a custom URL scheme for your app. This value must match the value used to configure the auth0Scheme manifest placeholder, for the Redirect intent filter to work
  • +
  • audience relates to the API Identifier you want to reference in your access tokens (see API settings)
  • +
  • scopes defaults to openid profile email. You can override these scopes, but openid is always requested regardless of this setting.
  • +
  • Arbitrary parameters can be specified and then picked up in a custom Auth0 Action or
  • +
  • If you want to log into a specific organization, provide the organizationId. Provide invitationUrl if a user has been invited to +join an organization. + Rule.
  • +
+
+ + + +
+

Implementation

+
Future<Credentials> login({
+  final String? audience,
+  final Set<String> scopes = const {},
+  final String? redirectUrl,
+  final String? organizationId,
+  final String? invitationUrl,
+  final String? scheme,
+  final bool useEphemeralSession = false,
+  final Map<String, String> parameters = const {},
+  final IdTokenValidationConfig idTokenValidationConfig =
+      const IdTokenValidationConfig(),
+}) =>
+    Auth0FlutterWebAuthPlatform.instance.login(_createWebAuthRequest(
+        WebAuthLoginOptions(
+            audience: audience,
+            scopes: scopes,
+            redirectUrl: redirectUrl,
+            organizationId: organizationId,
+            invitationUrl: invitationUrl,
+            parameters: parameters,
+            idTokenValidationConfig: idTokenValidationConfig,
+            scheme: scheme,
+            useEphemeralSession: useEphemeralSession)));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html new file mode 100644 index 00000000..54ff2cfd --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html @@ -0,0 +1,153 @@ + + + + + + + + logout method - WebAuthentication class - auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
logout
+ +
+ +
+ + +
+
+

logout method + Null safety +

+ +
+ + +Future<void> +logout(
  1. {String? returnTo,
  2. +
  3. String? scheme}
  4. +
) + + + +
+ +
+

Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application +once logout is complete.

+

If returnTo is not specified, a default URL is used that incorporates the domain value specified to Auth0.new, and scheme on Android, or the +bundle identifier in iOS. returnTo must appear in your Allowed Logout URLs list for the Auth0 app. Read more about redirecting users after logout.

+

(Android only): scheme must match the scheme that was used to configure the auth0Scheme manifest placeholder

+
+ + + +
+

Implementation

+
Future<void> logout({final String? returnTo, final String? scheme}) =>
+    Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest(
+      WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme),
+    ));
+
+ + +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html b/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html new file mode 100644 index 00000000..7f0f8c59 --- /dev/null +++ b/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html @@ -0,0 +1,208 @@ + + + + + + + + auth0_flutter library - Dart API + + + + + + + + + + + + + + + + + +
+ +
+ + +
auth0_flutter
+ +
+ +
+ + +
+
+

auth0_flutter library + Null safety + +

+ + + + +
+

Classes

+ +
+
+ Auth0 + +
+
+ Primary interface for interacting with Auth0 using web authentication, or the authentication API. +
+ +
+ AuthenticationApi + +
+
+ An interface for calling some of the endpoints in Auth0's Authentication API. +
+ +
+ Credentials + +
+
+ A collection of authentication artifacts obtained from Auth0 when a user logs in. +
+ +
+ IdTokenValidationConfig + +
+
+ Configuration settings for ID token validation. +
+ +
+ UserProfile + +
+
+ A collection of properties that represents the authenticated user, extracted from ID token claims. +
+ +
+ WebAuthentication + +
+
+ An interface for authenticating users using the Auth0 Universal Login page. +
+ +
+
+ + + + + + + + +
+

Exceptions / Errors

+ +
+
+ ApiException + +
+
+ +
+ +
+ WebAuthException + +
+
+ +
+ +
+
+ +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/categories.json b/auth0_flutter/doc/api/categories.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/auth0_flutter/doc/api/categories.json @@ -0,0 +1 @@ +[] diff --git a/auth0_flutter/doc/api/index.html b/auth0_flutter/doc/api/index.html new file mode 100644 index 00000000..302f18fc --- /dev/null +++ b/auth0_flutter/doc/api/index.html @@ -0,0 +1,473 @@ + + + + + + + + + auth0_flutter - Dart API docs + + + + + + + + + + + + + + + + + +
+ +
+ + +
auth0_flutter
+ +
+ +
+ + +
+ +
+

Auth0 SDK for Flutter (Beta)

+

CircleCI

+

Auth0 SDK for Android / iOS Flutter apps.

+
+

โš ๏ธ This library is currently in Beta. We do not recommend using this library in production yet. As we move towards First Availability, please be aware that releases may contain breaking changes.

+
+
+

Table of Contents

+ +

Requirements

+
FlutterAndroidiOS
SDK 3.0+Android API 21+iOS 12+
Dart 2.17+Java 8+Swift 5.3+
Xcode 12.x / 13.x
+

Installation

+

During the Beta stage the SDK will not be published to Pub.dev, but you can install it as a path package. Extract the contents of the provided zip file and then add the following dependency in your pubspec.yaml file:

+
auth0_flutter:
+    path: path/to/auth0_flutter
+
+

Then, run flutter pub get.

+

Getting Started

+

Configuration

+

auth0_flutter needs the Client ID and Domain of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your Auth0 application. If you are using a Custom Domain, use the value of your Custom Domain instead of the value from the settings page.

+
+

โš ๏ธ Make sure that the application type of the Auth0 application is Native. If you donโ€™t have a Native Auth0 application already, create one before continuing.

+
+
final auth0 = Auth0('YOUR_AUTH0_DOMAIN', 'YOUR_AUTH0_CLIENT_ID');
+
+

Web Auth Configuration

+ +

Configure callback and logout URLs

+

The callback and logout URLs are the URLs that Auth0 invokes to redirect back to your app. Auth0 invokes the callback URL after authenticating the user, and the logout URL after removing the session cookie.

+

Since callback and logout URLs can be manipulated, you will need to add your URLs to the Allowed Callback URLs and Allowed Logout URLs fields in the settings page of your Auth0 application. This will enable Auth0 to recognize these URLs as valid. If the callback and logout URLs are not set, users will be unable to log in and out of the app and will get an error.

+

Go to the settings page of your Auth0 application and add the corresponding URLs to Allowed Callback URLs and Allowed Logout URLs, according to the platforms used by your app. If you are using a Custom Domain, replace YOUR_AUTH0_DOMAIN with the value of your Custom Domain instead of the value from the settings page.

+
Android
+
https://YOUR_AUTH0_DOMAIN/android/YOUR_APP_PACKAGE_NAME/callback
+
+

E.g. if your Auth0 Domain was company.us.auth0.com and your Android app package name was com.company.myapp, then this value would be:

+
https://company.us.auth0.com/android/com.company.myapp/callback
+
+
iOS
+
YOUR_BUNDLE_IDENTIFIER://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback
+
+

E.g. if your iOS bundle identifier was com.company.myapp and your Auth0 Domain was company.us.auth0.com, then this value would be:

+
com.company.myapp://company.us.auth0.com/ios/com.company.myapp/callback
+
+

Android configuration: manifest placeholders

+

Open the android/build.gradle file and add the following manifest placeholders inside android > defaultConfig. The applicationId value will be auto-replaced at runtime with your Android app package name.

+
// android/build.gradle
+
+android {
+    // ...
+    defaultConfig {
+        // ...
+        // Add the following line
+        manifestPlaceholders = [auth0Domain: "YOUR_AUTH0_DOMAIN", auth0Scheme: "${applicationId}"]
+    }
+    // ...
+}
+
+

E.g. if your Auth0 Domain was company.us.auth0.com, then the manifest placeholders line would be:

+
manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${applicationId}"]
+
+
+

๐Ÿ’ก If your Android app is using product flavors, you might need to specify different manifest placeholders for each flavor.

+
+ Skipping the Android Web Auth configuration +

If you don't plan to use Web Auth, you will notice that the compiler will still prompt you to provide the manifestPlaceholders values, since the RedirectActivity included in this library will require them, and the Gradle tasks won't be able to run without them.

+

Re-declare the activity manually using tools:node="remove" in the android/src/main/AndroidManifest.xml file to make the manifest merger remove it from the final manifest file. Additionally, one more unused activity can be removed from the final APK by using the same process. A complete snippet to achieve this is:

+
  <!-- android/src/main/AndroidManifest.xml -->
+
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:tools="http://schemas.android.com/tools"
+      package="com.company.myapp">
+      <application android:theme="@style/AppTheme">
+          <!-- ... -->
+    
+          <activity
+              android:name="com.auth0.android.provider.AuthenticationActivity"
+              tools:node="remove"/>
+          <!-- Optional: Remove RedirectActivity -->
+          <activity
+              android:name="com.auth0.android.provider.RedirectActivity"
+              tools:node="remove"/>
+    
+          <!-- ... -->
+      </application>
+  </manifest>
+
+

iOS configuration: custom URL scheme

+

Open the ios/Runner/Info.plist file and add the following snippet inside the top-level <dict> tag. This registers your iOS Bundle Identifier as a custom URL scheme, so the callback and logout URLs can reach your app.

+
<!-- ios/Runner/Info.plist -->
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+<!-- ... -->
+
+    <key>CFBundleURLTypes</key>
+    <array>
+        <dict>
+            <key>CFBundleTypeRole</key>
+            <string>None</string>
+            <key>CFBundleURLName</key>
+            <string>auth0</string>
+            <key>CFBundleURLSchemes</key>
+            <array>
+                <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+            </array>
+        </dict>
+    </array>
+  
+<!-- ... -->
+</dict>
+</plist>
+
+
+

๐Ÿ’ก If you're opening the Info.plist file in Xcode and it is not being shown in this format, you can Right Click on Info.plist in the Xcode project navigator and then select Open As > Source Code.

+
+

Web Auth Login

+

Import auth0_flutter in the file where you want to present the login page.

+
import 'package:auth0_flutter/auth0_flutter.dart';
+
+

Then, present the Universal Login page in the onPressed callback of your Login button.

+
final result = await auth0.webAuthentication.login();
+
+ Add an audience value +

Specify an audience to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the API Identifier of your Auth0 API, e.g. https://example.com/api.

+
  final result = await auth0.webAuthentication
+      .login(audience: 'YOUR_AUTH0_API_IDENTIFIER');
+
+ Add scope values +

Specify scopes to request permission to access protected resources, like the user profile. The default scope values are openid, profile and email. Regardless of the values specified, openid is always included.

+
  final result = await auth0.webAuthentication
+      .login(scopes: {'profile', 'email', 'offline_access', 'read:todos'});
+
+ Add a custom scheme value (Android-only) +

On Android, auth0_flutter uses https by default as the callback URL scheme. This works best for Android API 23+ if you're using Android App Links, but in previous Android versions this may show the intent chooser dialog prompting the user to choose either your app or the browser. You can change this behavior by using a custom unique scheme so that Android opens the link directly with your app. Note that schemes can only have lowercase letters.

+
    +
  1. Update the auth0Scheme manifest placeholder on the android/build.gradle file.
  2. +
  3. Update the Allowed Callback URLs in the settings page of your Auth0 application.
  4. +
  5. Pass the scheme value to the login() method.
  6. +
+
  final result = await auth0.webAuthentication.login(scheme: {'demo'});
+
+

Web Auth Logout

+

Logging the user out involves clearing the Universal Login session cookie and then deleting the user's credentials from your app.

+

Call the logout() method in the in the onPressed callback of your Logout button. Once the session cookie has been cleared, delete the user's credentials.<!-- link to the section on deleting the stored credentials -->

+
await auth0.webAuthentication.logout();
+
+

SSO Alert Box (iOS)

+

ios-sso-alert

+

Check the FAQ for more information about the alert box that pops up by default when using Web Auth on iOS.

+
+

๐Ÿ’ก See also this blog post for a detailed overview of Single Sign-On (SSO) on iOS.

+
+

Go up โคด

+

Next Steps

+

Web Auth

+ +

Web Auth signup

+

You can make users land directly on the Signup page instead of the Login page by specifying the 'screen_hint': 'signup' parameter. Note that this can be combined with 'prompt': 'login', which indicates whether you want to always show the authentication page or you want to skip if there's an existing session.

+
ParametersNo existing sessionExisting session
No extra parametersShows the login pageRedirects to the callback url
'screen_hint': 'signup'Shows the signup pageRedirects to the callback url
'prompt': 'login'Shows the login pageShows the login page
'prompt': 'login', 'screen_hint': 'signup'Shows the signup pageShows the signup page
+
final result = await auth0.webAuthentication
+    .login(parameters: {'screen_hint': 'signup'});
+
+
+

โš ๏ธ The screen_hint parameter will work with the New Universal Login Experience without any further configuration. If you are using the Classic Universal Login Experience, you need to customize the login template to look for this parameter and set the initialScreen option of the Auth0Lock constructor.

+
+

ID Token validation

+

auth0_flutter automatically validates the ID Token obtained from Web Auth login, following the OpenID Connect specification. This ensures the contents of the ID Token have not been tampered with and can be safely used.

+
Custom Domains
+

Users of Auth0 Private Cloud with Custom Domains still on the legacy behavior need to specify a custom issuer to match the Auth0 Domain when performing Web Auth login. Otherwise, the ID Token validation will fail.

+
final config = IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/');
+final result =
+    await auth0.webAuthentication.login(idTokenValidationConfig: config);
+
+

Web Auth errors

+

Web Auth will only throw WebAuthException exceptions.<!-- Check the API documentation link to API documentation to learn more about the available WebAuthException properties. -->

+
try {
+  final result = await auth0.webAuthentication.login();
+  // ...
+} on WebAuthException catch (e) {
+  print(e.toString())
+}
+
+

API

+ +

The Authentication API exposes the AuthN/AuthZ functionality of Auth0, as well as the supported identity protocols like OpenID Connect, OAuth 2.0, and SAML. +We recommend using Universal Login, but if you prefer to build your own UI you can use our API endpoints to do so. However, some Auth flows (grant types) are disabled by default so you must enable them in the settings page of your Auth0 application, as explained in Update Grant Types.

+

For login or signup with username/password, the Password grant type needs to be enabled in your app. If you set the grants via the Management API you should activate both http://auth0.com/oauth/grant-type/password-realm and Password. Otherwise, the Auth0 Dashboard will take care of activating both when enabling Password.

+
+

๐Ÿ’ก If your Auth0 account has the Bot Detection feature enabled, your requests might be flagged for verification. Check how to handle this scenario in the Bot Detection section.

+
+
+

โš ๏ธ The ID Tokens obtained from Web Auth login are automatically validated by auth0_flutter, ensuring their contents have not been tampered with. This is not the case for the ID Tokens obtained from the Authentication API client. You must validate any ID Tokens received from the Authentication API client before using the information they contain.

+
+

Login with database connection

+
final result = await auth0.api.login(
+    usernameOrEmail: 'jane.smith@example.com',
+    password: 'secret-password',
+    connectionOrRealm: 'Username-Password-Authentication');
+
+ Add an audience value +

Specify an audience to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the API Identifier of your Auth0 API, e.g. https://example.com/api.

+
  final result = await auth0.api.login(
+      usernameOrEmail: 'jane.smith@example.com',
+      password: 'secret-password',
+      connectionOrRealm: 'Username-Password-Authentication',
+      audience: 'YOUR_AUTH0_API_IDENTIFIER');
+
+ Add scope values +

Specify scopes to request permission to access protected resources, like the user profile. The default scope values are openid, profile and email. Regardless of the values specified, openid is always included.

+
  final result = await auth0.api.login(
+      usernameOrEmail: 'jane.smith@example.com',
+      password: 'secret-password',
+      connectionOrRealm: 'Username-Password-Authentication',
+      scopes: {'profile', 'email', 'offline_access', 'read:todos'});
+
+

Sign up with database connection

+
final user = await auth0.api.signup(
+    email: 'jane.smith@example.com',
+    password: 'secret-password',
+    connection: 'Username-Password-Authentication',
+    userMetadata: {'first_name': 'Jane', 'last_name': 'Smith'});
+
+
+

๐Ÿ’ก You might want to log the user in after signup. See Login with database connection above for an example.

+
+

Retrieve user information

+

Fetch the latest user information from the /userinfo endpoint.

+

This method will yield a UserProfile instance.<!--Check the API documentation link to API documentation to learn more about its available properties. -->

+
final userProfile = await auth0.api.userInfo(accessToken: accessToken);
+
+

Renew credentials

+

Use a Refresh Token to renew the user's credentials. It's recommended that you read and understand the Refresh Token process beforehand.

+
final result = await auth0.api.renewCredentials(refreshToken: refreshToken);
+
+
+

๐Ÿ’ก To obtain a Refresh Token, make sure your Auth0 application has the Refresh Token grant enabled. If you are also specifying an audience value, make sure that the corresponding Auth0 API has the Allow Offline Access setting enabled.

+
+

API client errors

+

The Authentication API client will only throw ApiException exceptions. You can find more information in the details property of the exception.<!--Check the API documentation link to API documentation to learn more about the available ApiException properties. -->

+
try {
+  final result = await auth0.api.login(
+    usernameOrEmail: email,
+    password: password,
+    connectionOrRealm: connection);
+  // ...
+} on ApiException catch (e) {
+  print(e.toString())
+}
+
+

Go up โคด

+

Advanced Features

+

Organizations

+

Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.

+

Using Organizations, you can:

+
    +
  • Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations.
  • +
  • Manage their membership in a variety of ways, including user invitation.
  • +
  • Configure branded, federated login flows for each organization.
  • +
  • Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations.
  • +
  • Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations.
  • +
+
+

๐Ÿ’ก Organizations is currently only available to customers on our Enterprise and Startup subscription plans.

+
+

Log in to an organization

+
final result = await auth0.webAuthentication
+    .login(organizationId: 'YOUR_AUTH0_ORGANIZATION_ID');
+
+

Accept user invitations

+

To accept organization invitations your app needs to support deep linking, as invitation links are HTTPS-only. Tapping on the invitation link should open your app.

+

When your app gets opened by an invitation link, grab the invitation URL and pass it to the login() method.

+
final result = await auth0.webAuthentication.login(invitationUrl: url);
+
+

Bot Detection

+

If you are performing database login/signup via the Authentication API and would like to use the Bot Detection feature, you need to handle the isVerificationRequired error. It indicates that the request was flagged as suspicious and an additional verification step is necessary to log the user in. That verification step is web-based, so you need to use Web Auth to complete it.

+
try {
+  final result = await auth0.api.login(
+      usernameOrEmail: email,
+      password: password,
+      connectionOrRealm: connection,
+      scopes: scopes);
+  // ...
+} on ApiException catch (e) {
+  if (e.isVerificationRequired) {
+    final result = await auth0.webAuthentication.login(
+        scopes: scopes,
+        useEphemeralSession: true, // Otherwise a session cookie will remain (iOS-only)
+        parameters: {
+          'connection': connection,
+          'login_hint': email // So the user doesn't have to type it again
+        });
+    // ...
+  }
+}
+
+

Issue Reporting

+

For general support or usage questions, use the Auth0 Community forums or raise a support ticket. Only raise an issue if you have found a bug or want to request a feature.

+

Do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

+

What is Auth0?

+

Auth0 helps you to:

+
    +
  • Add authentication with multiple sources, either social identity providers such as Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce (amongst others), or enterprise identity systems like Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider.
  • +
  • Add authentication through more traditional username/password databases.
  • +
  • Add support for linking different user accounts with the same user.
  • +
  • Support for generating signed JSON Web Tokens to call your APIs and flow the user identity securely.
  • +
  • Analytics of how, when, and where users are logging in.
  • +
  • Pull data from other sources and add it to the user profile through JavaScript Actions.
  • +
+

Why Auth0? Because you should save time, be happy, and focus on what really matters: building your product.

+

License

+

This project is licensed under the MIT license. See the LICENSE file for more information.

+
+

Go up โคด

+
+ + +
+

Libraries

+
+
+ auth0_flutter + +
+
+
+ +
+
+ +
+ + + + + +
+ +
+ + auth0_flutter + 1.0.0-beta.0 + + + +
+ + + + + + + + + + + + diff --git a/auth0_flutter/doc/api/index.json b/auth0_flutter/doc/api/index.json new file mode 100644 index 00000000..98e3f3f4 --- /dev/null +++ b/auth0_flutter/doc/api/index.json @@ -0,0 +1 @@ +[{"name":"auth0_flutter","qualifiedName":"auth0_flutter","href":"auth0_flutter/auth0_flutter-library.html","type":"library","overriddenDepth":0,"packageName":"auth0_flutter"},{"name":"ApiException","qualifiedName":"auth0_flutter.ApiException","href":"auth0_flutter/ApiException-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"ApiException","qualifiedName":"auth0_flutter.ApiException.ApiException","href":"auth0_flutter/ApiException/ApiException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"code","qualifiedName":"auth0_flutter.ApiException.code","href":"auth0_flutter/ApiException/code.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"details","qualifiedName":"auth0_flutter.ApiException.details","href":"auth0_flutter/ApiException/details.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"ApiException.fromPlatformException","qualifiedName":"auth0_flutter.ApiException.fromPlatformException","href":"auth0_flutter/ApiException/ApiException.fromPlatformException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isAccessDenied","qualifiedName":"auth0_flutter.ApiException.isAccessDenied","href":"auth0_flutter/ApiException/isAccessDenied.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isBrowserAppNotAvailable","qualifiedName":"auth0_flutter.ApiException.isBrowserAppNotAvailable","href":"auth0_flutter/ApiException/isBrowserAppNotAvailable.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isCanceled","qualifiedName":"auth0_flutter.ApiException.isCanceled","href":"auth0_flutter/ApiException/isCanceled.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidAuthorizeURL","qualifiedName":"auth0_flutter.ApiException.isInvalidAuthorizeURL","href":"auth0_flutter/ApiException/isInvalidAuthorizeURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidConfiguration","qualifiedName":"auth0_flutter.ApiException.isInvalidConfiguration","href":"auth0_flutter/ApiException/isInvalidConfiguration.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidCredentials","qualifiedName":"auth0_flutter.ApiException.isInvalidCredentials","href":"auth0_flutter/ApiException/isInvalidCredentials.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isLoginRequired","qualifiedName":"auth0_flutter.ApiException.isLoginRequired","href":"auth0_flutter/ApiException/isLoginRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorCodeInvalid","qualifiedName":"auth0_flutter.ApiException.isMultifactorCodeInvalid","href":"auth0_flutter/ApiException/isMultifactorCodeInvalid.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorEnrollRequired","qualifiedName":"auth0_flutter.ApiException.isMultifactorEnrollRequired","href":"auth0_flutter/ApiException/isMultifactorEnrollRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorRequired","qualifiedName":"auth0_flutter.ApiException.isMultifactorRequired","href":"auth0_flutter/ApiException/isMultifactorRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorTokenInvalid","qualifiedName":"auth0_flutter.ApiException.isMultifactorTokenInvalid","href":"auth0_flutter/ApiException/isMultifactorTokenInvalid.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isNetworkError","qualifiedName":"auth0_flutter.ApiException.isNetworkError","href":"auth0_flutter/ApiException/isNetworkError.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPKCENotAvailable","qualifiedName":"auth0_flutter.ApiException.isPKCENotAvailable","href":"auth0_flutter/ApiException/isPKCENotAvailable.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordAlreadyUsed","qualifiedName":"auth0_flutter.ApiException.isPasswordAlreadyUsed","href":"auth0_flutter/ApiException/isPasswordAlreadyUsed.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordLeaked","qualifiedName":"auth0_flutter.ApiException.isPasswordLeaked","href":"auth0_flutter/ApiException/isPasswordLeaked.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordNotStrongEnough","qualifiedName":"auth0_flutter.ApiException.isPasswordNotStrongEnough","href":"auth0_flutter/ApiException/isPasswordNotStrongEnough.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isRefreshTokenDeleted","qualifiedName":"auth0_flutter.ApiException.isRefreshTokenDeleted","href":"auth0_flutter/ApiException/isRefreshTokenDeleted.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isRuleError","qualifiedName":"auth0_flutter.ApiException.isRuleError","href":"auth0_flutter/ApiException/isRuleError.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isTooManyAttempts","qualifiedName":"auth0_flutter.ApiException.isTooManyAttempts","href":"auth0_flutter/ApiException/isTooManyAttempts.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isVerificationRequired","qualifiedName":"auth0_flutter.ApiException.isVerificationRequired","href":"auth0_flutter/ApiException/isVerificationRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"message","qualifiedName":"auth0_flutter.ApiException.message","href":"auth0_flutter/ApiException/message.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"statusCode","qualifiedName":"auth0_flutter.ApiException.statusCode","href":"auth0_flutter/ApiException/statusCode.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"toString","qualifiedName":"auth0_flutter.ApiException.toString","href":"auth0_flutter/ApiException/toString.html","type":"method","overriddenDepth":1,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"ApiException.unknown","qualifiedName":"auth0_flutter.ApiException.unknown","href":"auth0_flutter/ApiException/ApiException.unknown.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"Auth0","qualifiedName":"auth0_flutter.Auth0","href":"auth0_flutter/Auth0-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"Auth0","qualifiedName":"auth0_flutter.Auth0.Auth0","href":"auth0_flutter/Auth0/Auth0.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"api","qualifiedName":"auth0_flutter.Auth0.api","href":"auth0_flutter/Auth0/api.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"webAuthentication","qualifiedName":"auth0_flutter.Auth0.webAuthentication","href":"auth0_flutter/Auth0/webAuthentication.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"AuthenticationApi","qualifiedName":"auth0_flutter.AuthenticationApi","href":"auth0_flutter/AuthenticationApi-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"AuthenticationApi","qualifiedName":"auth0_flutter.AuthenticationApi.AuthenticationApi","href":"auth0_flutter/AuthenticationApi/AuthenticationApi.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"login","qualifiedName":"auth0_flutter.AuthenticationApi.login","href":"auth0_flutter/AuthenticationApi/login.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"renewCredentials","qualifiedName":"auth0_flutter.AuthenticationApi.renewCredentials","href":"auth0_flutter/AuthenticationApi/renewCredentials.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"resetPassword","qualifiedName":"auth0_flutter.AuthenticationApi.resetPassword","href":"auth0_flutter/AuthenticationApi/resetPassword.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"signup","qualifiedName":"auth0_flutter.AuthenticationApi.signup","href":"auth0_flutter/AuthenticationApi/signup.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"userProfile","qualifiedName":"auth0_flutter.AuthenticationApi.userProfile","href":"auth0_flutter/AuthenticationApi/userProfile.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"Credentials","qualifiedName":"auth0_flutter.Credentials","href":"auth0_flutter/Credentials-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"Credentials","qualifiedName":"auth0_flutter.Credentials.Credentials","href":"auth0_flutter/Credentials/Credentials.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"accessToken","qualifiedName":"auth0_flutter.Credentials.accessToken","href":"auth0_flutter/Credentials/accessToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"expiresAt","qualifiedName":"auth0_flutter.Credentials.expiresAt","href":"auth0_flutter/Credentials/expiresAt.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"Credentials.fromMap","qualifiedName":"auth0_flutter.Credentials.fromMap","href":"auth0_flutter/Credentials/Credentials.fromMap.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"idToken","qualifiedName":"auth0_flutter.Credentials.idToken","href":"auth0_flutter/Credentials/idToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"refreshToken","qualifiedName":"auth0_flutter.Credentials.refreshToken","href":"auth0_flutter/Credentials/refreshToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"scopes","qualifiedName":"auth0_flutter.Credentials.scopes","href":"auth0_flutter/Credentials/scopes.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"userProfile","qualifiedName":"auth0_flutter.Credentials.userProfile","href":"auth0_flutter/Credentials/userProfile.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"IdTokenValidationConfig","qualifiedName":"auth0_flutter.IdTokenValidationConfig","href":"auth0_flutter/IdTokenValidationConfig-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"IdTokenValidationConfig","qualifiedName":"auth0_flutter.IdTokenValidationConfig.IdTokenValidationConfig","href":"auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"issuer","qualifiedName":"auth0_flutter.IdTokenValidationConfig.issuer","href":"auth0_flutter/IdTokenValidationConfig/issuer.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"leeway","qualifiedName":"auth0_flutter.IdTokenValidationConfig.leeway","href":"auth0_flutter/IdTokenValidationConfig/leeway.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"maxAge","qualifiedName":"auth0_flutter.IdTokenValidationConfig.maxAge","href":"auth0_flutter/IdTokenValidationConfig/maxAge.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"UserProfile","qualifiedName":"auth0_flutter.UserProfile","href":"auth0_flutter/UserProfile-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"UserProfile","qualifiedName":"auth0_flutter.UserProfile.UserProfile","href":"auth0_flutter/UserProfile/UserProfile.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"address","qualifiedName":"auth0_flutter.UserProfile.address","href":"auth0_flutter/UserProfile/address.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"birthdate","qualifiedName":"auth0_flutter.UserProfile.birthdate","href":"auth0_flutter/UserProfile/birthdate.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"customClaims","qualifiedName":"auth0_flutter.UserProfile.customClaims","href":"auth0_flutter/UserProfile/customClaims.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"email","qualifiedName":"auth0_flutter.UserProfile.email","href":"auth0_flutter/UserProfile/email.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"familyName","qualifiedName":"auth0_flutter.UserProfile.familyName","href":"auth0_flutter/UserProfile/familyName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"UserProfile.fromMap","qualifiedName":"auth0_flutter.UserProfile.fromMap","href":"auth0_flutter/UserProfile/UserProfile.fromMap.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"gender","qualifiedName":"auth0_flutter.UserProfile.gender","href":"auth0_flutter/UserProfile/gender.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"givenName","qualifiedName":"auth0_flutter.UserProfile.givenName","href":"auth0_flutter/UserProfile/givenName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"isEmailVerified","qualifiedName":"auth0_flutter.UserProfile.isEmailVerified","href":"auth0_flutter/UserProfile/isEmailVerified.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"isPhoneNumberVerified","qualifiedName":"auth0_flutter.UserProfile.isPhoneNumberVerified","href":"auth0_flutter/UserProfile/isPhoneNumberVerified.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"locale","qualifiedName":"auth0_flutter.UserProfile.locale","href":"auth0_flutter/UserProfile/locale.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"middleName","qualifiedName":"auth0_flutter.UserProfile.middleName","href":"auth0_flutter/UserProfile/middleName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"name","qualifiedName":"auth0_flutter.UserProfile.name","href":"auth0_flutter/UserProfile/name.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"nickname","qualifiedName":"auth0_flutter.UserProfile.nickname","href":"auth0_flutter/UserProfile/nickname.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"phoneNumber","qualifiedName":"auth0_flutter.UserProfile.phoneNumber","href":"auth0_flutter/UserProfile/phoneNumber.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"pictureURL","qualifiedName":"auth0_flutter.UserProfile.pictureURL","href":"auth0_flutter/UserProfile/pictureURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"preferredUsername","qualifiedName":"auth0_flutter.UserProfile.preferredUsername","href":"auth0_flutter/UserProfile/preferredUsername.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"profileURL","qualifiedName":"auth0_flutter.UserProfile.profileURL","href":"auth0_flutter/UserProfile/profileURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"sub","qualifiedName":"auth0_flutter.UserProfile.sub","href":"auth0_flutter/UserProfile/sub.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"updatedAt","qualifiedName":"auth0_flutter.UserProfile.updatedAt","href":"auth0_flutter/UserProfile/updatedAt.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"websiteURL","qualifiedName":"auth0_flutter.UserProfile.websiteURL","href":"auth0_flutter/UserProfile/websiteURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"zoneinfo","qualifiedName":"auth0_flutter.UserProfile.zoneinfo","href":"auth0_flutter/UserProfile/zoneinfo.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"WebAuthException","qualifiedName":"auth0_flutter.WebAuthException","href":"auth0_flutter/WebAuthException-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"WebAuthException","qualifiedName":"auth0_flutter.WebAuthException.WebAuthException","href":"auth0_flutter/WebAuthException/WebAuthException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"code","qualifiedName":"auth0_flutter.WebAuthException.code","href":"auth0_flutter/WebAuthException/code.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"details","qualifiedName":"auth0_flutter.WebAuthException.details","href":"auth0_flutter/WebAuthException/details.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthException.fromPlatformException","qualifiedName":"auth0_flutter.WebAuthException.fromPlatformException","href":"auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"message","qualifiedName":"auth0_flutter.WebAuthException.message","href":"auth0_flutter/WebAuthException/message.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"toString","qualifiedName":"auth0_flutter.WebAuthException.toString","href":"auth0_flutter/WebAuthException/toString.html","type":"method","overriddenDepth":1,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthException.unknown","qualifiedName":"auth0_flutter.WebAuthException.unknown","href":"auth0_flutter/WebAuthException/WebAuthException.unknown.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthentication","qualifiedName":"auth0_flutter.WebAuthentication","href":"auth0_flutter/WebAuthentication-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"WebAuthentication","qualifiedName":"auth0_flutter.WebAuthentication.WebAuthentication","href":"auth0_flutter/WebAuthentication/WebAuthentication.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}},{"name":"login","qualifiedName":"auth0_flutter.WebAuthentication.login","href":"auth0_flutter/WebAuthentication/login.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}},{"name":"logout","qualifiedName":"auth0_flutter.WebAuthentication.logout","href":"auth0_flutter/WebAuthentication/logout.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}}] diff --git a/auth0_flutter/doc/api/static-assets/favicon.png b/auth0_flutter/doc/api/static-assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..43d2ffa079ca147a221437817dbc694d66a2a302 GIT binary patch literal 1767 zcmVr1gM)#AhSs$=eK0WK)CF2vH5m*T78Vv7 zOqGGvxA(cvvG46mUuvh$T1!8DmE**HzxO9;TsuQliJN|J!pK@zgpAc6W;K`ZbSrnoP`wF$fl7_5*8Ivypwf=W;~ z;08%MQORYPC_tGHZSh$O#Av43|^d-UX&HM!T~7!)g1(@JfEf{VV=B< z1V2h$vz|_)(42Iv;nMQ6gnaC=x-iE)V9>bg95MTIge3HB2W~Qqm*!+BpztvG$qKPZI96W} zvtB&GrNG5*kOai6|CR7-+*88m$TiE!O#Aqvg{$I60STah90fcj;bJTAHe50;DvqB` zEg>!%3Dgd1>303*qUn95wS&WE(*hLuC37)V?aQjQ(>?on4V>`^}$4&P2qUwF63p3!p z6R>6i5YrB(Dm-K?OMsE#XJVfc&SVMlTc3)@NKU0J3269ELe@xN0Za64hocS>SoY(& zL%m;r$g#En;{)>X$|7Ng63+K0K^DLzXfDCDx@#YPVSI{DxIP(XJHy#-j`B3b#X_yixgMa&bn3s?yPcssC4`0@Pr z>UDqkrA2oMvH(^Il;ArzoKINx_2)YKwKcf{c=joHgRLFHM+xq^ZVMp3+9h+pM_8DNoMAB-dVobWmYAS9rt1as~o-UgNSX!>_*0eKDx64<-L zsr_Sf&ksWK5X_wO=HsvVW@R@4avN{~b`kO)Q2hp=EFi=-pa;L0N~k1s7QiKN5q3y| z{H02#@|Qmd>8SNrVChicf`ASZgo+R(>{|f;A|&P#WC45@h!O<2gp5n*5WLs|%h5Io z&-zA4k|2tpV}-BR_;rW=0{Hbbr8g2rC_$(INdgxkz-9uI;7AhAx(eXe)2I^YTj5fu z07-%@V%uQ+#@-^?#TPmIvVf-~Xcr}rfKnDf$id05c9_^NzK{etcv%3Kz^)CFfYM7u z0sTc>5&YuI)(f)z1qhX(H3Ggi0-)qG;MpQ%*z;uxJkb6E_~m7Pp-})}1w7y{P|87X zMF?8JdR00$fprxiY?Jv$f)^#)PoTa$P7;P^(nEroXQBYUjX$q968u%Jy_6(e-Iwpz z`wQ&juE(vPtb`I*EA&`h0mZHYjw%V!O;ZVLl+daK6k%2i_w{N+cwBf+b515f%gmO% z0;CNdCA9us9ZyP?@Hi6?I4mR~j0z_-S>8&HnB#ImfGojJKnEEBu4V8D90ETn>T?(4 zMG`tr=$)vA?}qayISJ<{js z)mqSPcf)OyC94E3VQ2vf2>>`6^tPFngqTYhz5-+c150@O0%QqqUjRvn1qp9gfGmM1 zUw{G;1RSy*Qj(CpFloi)@B(OKcajFkv|3YK_es*=t)6!)-Mumr002ov JPDHLkV1ksy9Tflo literal 0 HcmV?d00001 diff --git a/auth0_flutter/doc/api/static-assets/github.css b/auth0_flutter/doc/api/static-assets/github.css new file mode 100644 index 00000000..791932b8 --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/github.css @@ -0,0 +1,99 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f8f8f8; +} + +.hljs-comment, +.hljs-quote { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-literal, +.hljs-variable, +.hljs-template-variable, +.hljs-tag .hljs-attr { + color: #008080; +} + +.hljs-string, +.hljs-doctag { + color: #d14; +} + +.hljs-title, +.hljs-section, +.hljs-selector-id { + color: #900; + font-weight: bold; +} + +.hljs-subst { + font-weight: normal; +} + +.hljs-type, +.hljs-class .hljs-title { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: #000080; + font-weight: normal; +} + +.hljs-regexp, +.hljs-link { + color: #009926; +} + +.hljs-symbol, +.hljs-bullet { + color: #990073; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #0086b3; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/auth0_flutter/doc/api/static-assets/highlight.pack.js b/auth0_flutter/doc/api/static-assets/highlight.pack.js new file mode 100644 index 00000000..dabdd3c0 --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/highlight.pack.js @@ -0,0 +1,775 @@ +/*! + Highlight.js v11.0.1 (git: 1cf31f015d) + (c) 2006-2021 Ivan Sagalaev and other contributors + License: BSD-3-Clause + */ +var hljs=function(){"use strict";var e={exports:{}};function t(e){ +return e instanceof Map?e.clear=e.delete=e.set=()=>{ +throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{ +throw Error("set is read-only") +}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((n=>{var i=e[n] +;"object"!=typeof i||Object.isFrozen(i)||t(i)})),e} +e.exports=t,e.exports.default=t;var n=e.exports;class i{constructor(e){ +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} +ignoreMatch(){this.isMatchIgnored=!0}}function r(e){ +return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") +}function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t] +;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const o=e=>!!e.kind +;class a{constructor(e,t){ +this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){ +this.buffer+=r(e)}openNode(e){if(!o(e))return;let t=e.kind +;t=e.sublanguage?"language-"+t:((e,{prefix:t})=>{if(e.includes(".")){ +const n=e.split(".") +;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ") +}return`${t}${e}`})(t,{prefix:this.classPrefix}),this.span(t)}closeNode(e){ +o(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ +this.buffer+=``}}class l{constructor(){this.rootNode={ +children:[]},this.stack=[this.rootNode]}get top(){ +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ +this.top.children.push(e)}openNode(e){const t={kind:e,children:[]} +;this.add(t),this.stack.push(t)}closeNode(){ +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){ +return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t), +t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){ +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ +l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e} +addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())} +addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root +;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){ +return new a(this,this.options).value()}finalize(){return!0}}function g(e){ +return e?"string"==typeof e?e:e.source:null}function d(...e){ +return e.map((e=>g(e))).join("")}function u(...e){return"("+((e=>{ +const t=e[e.length-1] +;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{} +})(e).capture?"":"?:")+e.map((e=>g(e))).join("|")+")"}function h(e){ +return RegExp(e.toString()+"|").exec("").length-1} +const f=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ +;function p(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n +;let i=g(e),r="";for(;i.length>0;){const e=f.exec(i);if(!e){r+=i;break} +r+=i.substring(0,e.index), +i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0], +"("===e[0]&&n++)}return r})).map((e=>`(${e})`)).join(t)} +const b="[a-zA-Z]\\w*",m="[a-zA-Z_]\\w*",E="\\b\\d+(\\.\\d+)?",x="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",y="\\b(0b[01]+)",w={ +begin:"\\\\[\\s\\S]",relevance:0},_={scope:"string",begin:"'",end:"'", +illegal:"\\n",contains:[w]},v={scope:"string",begin:'"',end:'"',illegal:"\\n", +contains:[w]},O=(e,t,n={})=>{const i=s({scope:"comment",begin:e,end:t, +contains:[]},n);i.contains.push({scope:"doctag", +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) +;const r=u("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) +;return i.contains.push({begin:d(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i +},k=O("//","$"),N=O("/\\*","\\*/"),S=O("#","$");var M=Object.freeze({ +__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:b,UNDERSCORE_IDENT_RE:m, +NUMBER_RE:E,C_NUMBER_RE:x,BINARY_NUMBER_RE:y, +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", +SHEBANG:(e={})=>{const t=/^#![ ]*\// +;return e.binary&&(e.begin=d(t,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:t, +end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)}, +BACKSLASH_ESCAPE:w,APOS_STRING_MODE:_,QUOTE_STRING_MODE:v,PHRASAL_WORDS_MODE:{ +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ +},COMMENT:O,C_LINE_COMMENT_MODE:k,C_BLOCK_COMMENT_MODE:N,HASH_COMMENT_MODE:S, +NUMBER_MODE:{scope:"number",begin:E,relevance:0},C_NUMBER_MODE:{scope:"number", +begin:x,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:y,relevance:0}, +REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//, +end:/\/[gimuy]*/,illegal:/\n/,contains:[w,{begin:/\[/,end:/\]/,relevance:0, +contains:[w]}]}]},TITLE_MODE:{scope:"title",begin:b,relevance:0}, +UNDERSCORE_TITLE_MODE:{scope:"title",begin:m,relevance:0},METHOD_GUARD:{ +begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{ +"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{ +t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function R(e,t){ +"."===e.input[e.index-1]&&t.ignoreMatch()}function j(e,t){ +void 0!==e.className&&(e.scope=e.className,delete e.className)}function A(e,t){ +t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", +e.__beforeBegin=R,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, +void 0===e.relevance&&(e.relevance=0))}function I(e,t){ +Array.isArray(e.illegal)&&(e.illegal=u(...e.illegal))}function B(e,t){ +if(e.match){ +if(e.begin||e.end)throw Error("begin & end are not supported with match") +;e.begin=e.match,delete e.match}}function T(e,t){ +void 0===e.relevance&&(e.relevance=1)}const L=(e,t)=>{if(!e.beforeMatch)return +;if(e.starts)throw Error("beforeMatch cannot be used with starts") +;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t] +})),e.keywords=n.keywords, +e.begin=d(n.beforeMatch,d("(?=",n.begin,")")),e.starts={relevance:0, +contains:[Object.assign(n,{endsParent:!0})]},e.relevance=0,delete n.beforeMatch +},D=["of","and","for","in","not","or","if","then","parent","list","value"] +;function P(e,t,n="keyword"){const i=Object.create(null) +;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{ +Object.assign(i,P(e[n],t,n))})),i;function r(e,n){ +t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|") +;i[n[0]]=[e,C(n[0],n[1])]}))}}function C(e,t){ +return t?Number(t):(e=>D.includes(e.toLowerCase()))(e)?0:1}const H={},$=e=>{ +console.error(e)},U=(e,...t)=>{console.log("WARN: "+e,...t)},z=(e,t)=>{ +H[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),H[`${e}/${t}`]=!0) +},K=Error();function W(e,t,{key:n}){let i=0;const r=e[n],s={},o={} +;for(let e=1;e<=t.length;e++)o[e+i]=r[e],s[e+i]=!0,i+=h(t[e-1]) +;e[n]=o,e[n]._emit=s,e[n]._multi=!0}function X(e){(e=>{ +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope +}),(e=>{if(Array.isArray(e.begin)){ +if(e.skip||e.excludeBegin||e.returnBegin)throw $("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), +K +;if("object"!=typeof e.beginScope||null===e.beginScope)throw $("beginScope must be object"), +K;W(e,e.begin,{key:"beginScope"}),e.begin=p(e.begin,{joinWith:""})}})(e),(e=>{ +if(Array.isArray(e.end)){ +if(e.skip||e.excludeEnd||e.returnEnd)throw $("skip, excludeEnd, returnEnd not compatible with endScope: {}"), +K +;if("object"!=typeof e.endScope||null===e.endScope)throw $("endScope must be object"), +K;W(e,e.end,{key:"endScope"}),e.end=p(e.end,{joinWith:""})}})(e)}function G(e){ +function t(t,n){return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(n?"g":""))} +class n{constructor(){ +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} +addRule(e,t){ +t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]), +this.matchAt+=h(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) +;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(p(e,{joinWith:"|" +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex +;const t=this.matcherRe.exec(e);if(!t)return null +;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n] +;return t.splice(0,n),Object.assign(t,i)}}class i{constructor(){ +this.rules=[],this.multiRegexes=[], +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ +if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n +;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))), +t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){ +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){ +this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){ +const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex +;let n=t.exec(e) +;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{ +const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)} +return n&&(this.regexIndex+=n.position+1, +this.regexIndex===this.count&&this.considerAll()),n}} +if(e.compilerExtensions||(e.compilerExtensions=[]), +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") +;return e.classNameAliases=s(e.classNameAliases||{}),function n(r,o){const a=r +;if(r.isCompiled)return a +;[j,B,X,L].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))), +r.__beforeBegin=null,[A,I,T].forEach((e=>e(r,o))),r.isCompiled=!0;let l=null +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), +l=r.keywords.$pattern, +delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=P(r.keywords,e.case_insensitive)), +a.keywordPatternRe=t(l,!0), +o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(r.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), +r.end&&(a.endRe=t(r.end)), +a.terminatorEnd=g(r.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)), +r.illegal&&(a.illegalRe=t(r.illegal)), +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{ +variants:null},t)))),e.cachedVariants?e.cachedVariants:Z(e)?s(e,{ +starts:e.starts?s(e.starts):null +}):Object.isFrozen(e)?s(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a) +})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new i +;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin" +}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end" +}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function Z(e){ +return!!e&&(e.endsWithParent||Z(e.starts))}const F=r,V=s,q=Symbol("nomatch") +;var J=(e=>{const t=Object.create(null),r=Object.create(null),s=[];let o=!0 +;const a="Could not find the language '{}', did you forget to load/include a language module?",l={ +disableAutodetect:!0,name:"Plain text",contains:[]};let g={ +ignoreUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", +cssSelector:"pre code",languages:null,__emitter:c};function d(e){ +return g.noHighlightRe.test(e)}function u(e,t,n,i){let r="",s="" +;"object"==typeof t?(r=e, +n=t.ignoreIllegals,s=t.language,i=void 0):(z("10.7.0","highlight(lang, code, ...args) has been deprecated."), +z("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), +s=e,r=t),void 0===n&&(n=!0);const o={code:r,language:s};w("before:highlight",o) +;const a=o.result?o.result:h(o.language,o.code,n,i) +;return a.code=o.code,w("after:highlight",a),a}function h(e,n,r,s){ +const l=Object.create(null);function c(){if(!k.keywords)return void S.addText(M) +;let e=0;k.keywordPatternRe.lastIndex=0;let t=k.keywordPatternRe.exec(M),n="" +;for(;t;){n+=M.substring(e,t.index) +;const r=_.case_insensitive?t[0].toLowerCase():t[0],s=(i=r,k.keywords[i]);if(s){ +const[e,i]=s +;if(S.addText(n),n="",l[r]=(l[r]||0)+1,l[r]<=7&&(R+=i),e.startsWith("_"))n+=t[0];else{ +const n=_.classNameAliases[e]||e;S.addKeyword(t[0],n)}}else n+=t[0] +;e=k.keywordPatternRe.lastIndex,t=k.keywordPatternRe.exec(M)}var i +;n+=M.substr(e),S.addText(n)}function d(){null!=k.subLanguage?(()=>{ +if(""===M)return;let e=null;if("string"==typeof k.subLanguage){ +if(!t[k.subLanguage])return void S.addText(M) +;e=h(k.subLanguage,M,!0,N[k.subLanguage]),N[k.subLanguage]=e._top +}else e=f(M,k.subLanguage.length?k.subLanguage:null) +;k.relevance>0&&(R+=e.relevance),S.addSublanguage(e._emitter,e.language) +})():c(),M=""}function u(e,t){let n=1;for(;void 0!==t[n];){if(!e._emit[n]){n++ +;continue}const i=_.classNameAliases[e[n]]||e[n],r=t[n] +;i?S.addKeyword(r,i):(M=r,c(),M=""),n++}}function p(e,t){ +return e.scope&&"string"==typeof e.scope&&S.openNode(_.classNameAliases[e.scope]||e.scope), +e.beginScope&&(e.beginScope._wrap?(S.addKeyword(M,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), +M=""):e.beginScope._multi&&(u(e.beginScope,t),M="")),k=Object.create(e,{parent:{ +value:k}}),k}function b(e,t,n){let r=((e,t)=>{const n=e&&e.exec(t) +;return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){const n=new i(e) +;e["on:end"](t,n),n.isMatchIgnored&&(r=!1)}if(r){ +for(;e.endsParent&&e.parent;)e=e.parent;return e}} +if(e.endsWithParent)return b(e.parent,t,n)}function m(e){ +return 0===k.matcher.regexIndex?(M+=e[0],1):(I=!0,0)}function x(e){ +const t=e[0],i=n.substr(e.index),r=b(k,e,i);if(!r)return q;const s=k +;k.endScope&&k.endScope._wrap?(d(), +S.addKeyword(t,k.endScope._wrap)):k.endScope&&k.endScope._multi?(d(), +u(k.endScope,e)):s.skip?M+=t:(s.returnEnd||s.excludeEnd||(M+=t), +d(),s.excludeEnd&&(M=t));do{ +k.scope&&!k.isMultiClass&&S.closeNode(),k.skip||k.subLanguage||(R+=k.relevance), +k=k.parent}while(k!==r.parent) +;return r.starts&&p(r.starts,e),s.returnEnd?0:t.length}let y={};function w(t,s){ +const a=s&&s[0];if(M+=t,null==a)return d(),0 +;if("begin"===y.type&&"end"===s.type&&y.index===s.index&&""===a){ +if(M+=n.slice(s.index,s.index+1),!o){const t=Error(`0 width match regex (${e})`) +;throw t.languageName=e,t.badRule=y.rule,t}return 1} +if(y=s,"begin"===s.type)return(e=>{ +const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]] +;for(const n of s)if(n&&(n(e,r),r.isMatchIgnored))return m(t) +;return n.skip?M+=t:(n.excludeBegin&&(M+=t), +d(),n.returnBegin||n.excludeBegin||(M=t)),p(n,e),n.returnBegin?0:t.length})(s) +;if("illegal"===s.type&&!r){ +const e=Error('Illegal lexeme "'+a+'" for mode "'+(k.scope||"")+'"') +;throw e.mode=k,e}if("end"===s.type){const e=x(s);if(e!==q)return e} +if("illegal"===s.type&&""===a)return 1 +;if(A>1e5&&A>3*s.index)throw Error("potential infinite loop, way more iterations than matches") +;return M+=a,a.length}const _=E(e) +;if(!_)throw $(a.replace("{}",e)),Error('Unknown language: "'+e+'"') +;const v=G(_);let O="",k=s||v;const N={},S=new g.__emitter(g);(()=>{const e=[] +;for(let t=k;t!==_;t=t.parent)t.scope&&e.unshift(t.scope) +;e.forEach((e=>S.openNode(e)))})();let M="",R=0,j=0,A=0,I=!1;try{ +for(k.matcher.considerAll();;){ +A++,I?I=!1:k.matcher.considerAll(),k.matcher.lastIndex=j +;const e=k.matcher.exec(n);if(!e)break;const t=w(n.substring(j,e.index),e) +;j=e.index+t}return w(n.substr(j)),S.closeAllNodes(),S.finalize(),O=S.toHTML(),{ +language:e,value:O,relevance:R,illegal:!1,_emitter:S,_top:k}}catch(t){ +if(t.message&&t.message.includes("Illegal"))return{language:e,value:F(n), +illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j, +context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:O},_emitter:S};if(o)return{ +language:e,value:F(n),illegal:!1,relevance:0,errorRaised:t,_emitter:S,_top:k} +;throw t}}function f(e,n){n=n||g.languages||Object.keys(t);const i=(e=>{ +const t={value:F(e),illegal:!1,relevance:0,_top:l,_emitter:new g.__emitter(g)} +;return t._emitter.addText(e),t})(e),r=n.filter(E).filter(y).map((t=>h(t,e,!1))) +;r.unshift(i);const s=r.sort(((e,t)=>{ +if(e.relevance!==t.relevance)return t.relevance-e.relevance +;if(e.language&&t.language){if(E(e.language).supersetOf===t.language)return 1 +;if(E(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=s,c=o +;return c.secondBest=a,c}function p(e){let t=null;const n=(e=>{ +let t=e.className+" ";t+=e.parentNode?e.parentNode.className:"" +;const n=g.languageDetectRe.exec(t);if(n){const t=E(n[1]) +;return t||(U(a.replace("{}",n[1])), +U("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"} +return t.split(/\s+/).find((e=>d(e)||E(e)))})(e);if(d(n))return +;w("before:highlightElement",{el:e,language:n +}),!g.ignoreUnescapedHTML&&e.children.length>0&&(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), +console.warn("https://github.com/highlightjs/highlight.js/issues/2886"), +console.warn(e)),t=e;const i=t.textContent,s=n?u(i,{language:n,ignoreIllegals:!0 +}):f(i);e.innerHTML=s.value,((e,t,n)=>{const i=t&&r[t]||n +;e.classList.add("hljs"),e.classList.add("language-"+i) +})(e,n,s.language),e.result={language:s.language,re:s.relevance, +relevance:s.relevance},s.secondBest&&(e.secondBest={ +language:s.secondBest.language,relevance:s.secondBest.relevance +}),w("after:highlightElement",{el:e,result:s,text:i})}let b=!1;function m(){ +"loading"!==document.readyState?document.querySelectorAll(g.cssSelector).forEach(p):b=!0 +}function E(e){return e=(e||"").toLowerCase(),t[e]||t[r[e]]} +function x(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ +r[e.toLowerCase()]=t}))}function y(e){const t=E(e) +;return t&&!t.disableAutodetect}function w(e,t){const n=e;s.forEach((e=>{ +e[n]&&e[n](t)}))} +"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ +b&&m()}),!1),Object.assign(e,{highlight:u,highlightAuto:f,highlightAll:m, +highlightElement:p, +highlightBlock:e=>(z("10.7.0","highlightBlock will be removed entirely in v12.0"), +z("10.7.0","Please use highlightElement now."),p(e)),configure:e=>{g=V(g,e)}, +initHighlighting:()=>{ +m(),z("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, +initHighlightingOnLoad:()=>{ +m(),z("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") +},registerLanguage:(n,i)=>{let r=null;try{r=i(e)}catch(e){ +if($("Language definition for '{}' could not be registered.".replace("{}",n)), +!o)throw e;$(e),r=l} +r.name||(r.name=n),t[n]=r,r.rawDefinition=i.bind(null,e),r.aliases&&x(r.aliases,{ +languageName:n})},unregisterLanguage:e=>{delete t[e] +;for(const t of Object.keys(r))r[t]===e&&delete r[t]}, +listLanguages:()=>Object.keys(t),getLanguage:E,registerAliases:x, +autoDetection:y,inherit:V,addPlugin:e=>{(e=>{ +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{ +e["before:highlightBlock"](Object.assign({block:t.el},t)) +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{ +e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)} +}),e.debugMode=()=>{o=!1},e.safeMode=()=>{o=!0},e.versionString="11.0.1" +;for(const e in M)"object"==typeof M[e]&&n(M[e]);return Object.assign(e,M),e +})({}),Y=Object.freeze({__proto__:null});const Q=J +;for(const e of Object.keys(Y)){const t=e.replace("grmr_","") +;Q.registerLanguage(t,Y[e])}return Q}() +;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("xml",(()=>{"use strict";function e(e){ +return e?"string"==typeof e?e:e.source:null}function n(e){return a("(?=",e,")")} +function a(...n){return n.map((n=>e(n))).join("")}function s(...n){ +return"("+((e=>{const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(n).capture?"":"?:")+n.map((n=>e(n))).join("|")+")"}return e=>{ +const t=a(/[A-Z_]/,a("(?:",/[A-Z0-9_.-]*:/,")?"),/[A-Z0-9_.-]*/),i={ +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},c={begin:/\s/, +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] +},r=e.inherit(c,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{ +className:"string"}),g=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),m={ +endsWithParent:!0,illegal:/`]+/}]}]}]};return{ +name:"HTML, XML", +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], +case_insensitive:!0,contains:[{className:"meta",begin://, +relevance:10,contains:[c,g,l,r,{begin:/\[/,end:/\]/,contains:[{className:"meta", +begin://,contains:[c,r,g,l]}]}]},e.COMMENT(//,{ +relevance:10}),{begin://,relevance:10},i,{ +className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"style"},contains:[m],starts:{ +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"script"},contains:[m],starts:{ +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ +className:"tag",begin:/<>|<\/>/},{className:"tag", +begin:a(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name", +begin:t,relevance:0,starts:m}]},{className:"tag",begin:a(/<\//,n(a(t,/>/))), +contains:[{className:"name",begin:t,relevance:0},{begin:/>/,relevance:0, +endsParent:!0}]}]}}})());hljs.registerLanguage("markdown",(()=>{"use strict";function n(...n){ +return n.map((n=>{return(e=n)?"string"==typeof e?e:e.source:null;var e +})).join("")}return e=>{const a={begin:/<\/?[A-Za-z_]/,end:">", +subLanguage:"xml",relevance:0},i={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0 +},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, +relevance:2},{begin:n(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), +relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ +begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{ +className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, +returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", +excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", +end:"\\]",excludeBegin:!0,excludeEnd:!0}]},s={className:"strong",contains:[], +variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},c={ +className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{ +begin:/_(?!_)/,end:/_/,relevance:0}]};s.contains.push(c),c.contains.push(s) +;let t=[a,i] +;return s.contains=s.contains.concat(t),c.contains=c.contains.concat(t), +t=t.concat(s,c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:t},{ +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", +contains:t}]}]},a,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", +end:"\\s+",excludeEnd:!0},s,c,{className:"quote",begin:"^>\\s+",contains:t, +end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ +begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ +begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", +contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ +begin:"^[-\\*]{3,}",end:"$"},i,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}})());hljs.registerLanguage("css",(()=>{"use strict" +;const e=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],t=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],i=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],o=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],r=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse() +;return n=>{const a=(e=>({IMPORTANT:{scope:"meta",begin:"!important"},HEXCOLOR:{ +scope:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"}, +ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", +contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ +scope:"number", +begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", +relevance:0}}))(n),l=[n.APOS_STRING_MODE,n.QUOTE_STRING_MODE];return{name:"CSS", +case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"}, +classNameAliases:{keyframePosition:"selector-tag"}, +contains:[n.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ +},a.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 +},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 +},a.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ +begin:":("+i.join("|")+")"},{begin:"::("+o.join("|")+")"}]},{ +className:"attribute",begin:"\\b("+r.join("|")+")\\b"},{begin:":",end:"[;}]", +contains:[a.HEXCOLOR,a.IMPORTANT,a.CSS_NUMBER_MODE,...l,{ +begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" +},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}] +},{className:"built_in",begin:/[\w-]+(?=\()/}]},{ +begin:(s=/@/,((...e)=>e.map((e=>(e=>e?"string"==typeof e?e:e.source:null)(e))).join(""))("(?=",s,")")), +end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword", +begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0, +relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only", +attribute:t.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute" +},...l,a.CSS_NUMBER_MODE]}]},{className:"selector-tag", +begin:"\\b("+e.join("|")+")\\b"}]};var s}})());hljs.registerLanguage("plaintext",(()=>{"use strict";return t=>({ +name:"Plain text",aliases:["text","txt"],disableAutodetect:!0})})());hljs.registerLanguage("bash",(()=>{"use strict";function e(...e){ +return e.map((e=>{return(s=e)?"string"==typeof s?s:s.source:null;var s +})).join("")}return s=>{const n={},t={begin:/\$\{/,end:/\}/,contains:["self",{ +begin:/:-/,contains:[n]}]};Object.assign(n,{className:"variable",variants:[{ +begin:e(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={ +className:"subst",begin:/\$\(/,end:/\)/,contains:[s.BACKSLASH_ESCAPE]},i={ +begin:/<<-?\s*(?=\w+)/,starts:{contains:[s.END_SAME_AS_BEGIN({begin:/(\w+)/, +end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/, +contains:[s.BACKSLASH_ESCAPE,n,a]};a.contains.push(c);const o={begin:/\$\(\(/, +end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},s.NUMBER_MODE,n] +},r=s.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 +}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, +contains:[s.inherit(s.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ +name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/, +keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"], +literal:["true","false"], +built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp" +},contains:[r,s.SHEBANG(),l,o,s.HASH_COMMENT_MODE,i,c,{className:"",begin:/\\"/ +},{className:"string",begin:/'/,end:/'/},n]}}})());hljs.registerLanguage("kotlin",(()=>{"use strict" +;var e="\\.([0-9](_*[0-9])*)",n="[0-9a-fA-F](_*[0-9a-fA-F])*",a={ +className:"number",variants:[{ +begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{ +begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};return e=>{const n={ +keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", +built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", +literal:"true false null"},i={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" +},s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={ +className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", +variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'", +illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, +contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={ +className:"meta", +begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" +},c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, +end:/\)/,contains:[e.inherit(r,{className:"string"})]}] +},o=a,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={ +variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, +contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d], +{name:"Kotlin",aliases:["kt","kts"],keywords:n, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", +begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword", +begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", +begin:/@\w+/}]}},i,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$", +returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ +begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, +contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, +keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, +endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, +endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0 +},e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{className:"class", +beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, +illegal:"extends implements",contains:[{ +beginKeywords:"public protected internal private constructor" +},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, +excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/, +excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env", +end:"$",illegal:"\n"},o]}}})());hljs.registerLanguage("diff",(()=>{"use strict";function e(...e){ +return"("+((e=>{const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(e).capture?"":"?:")+e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null +;var n})).join("|")+")"}return n=>({name:"Diff",aliases:["patch"],contains:[{ +className:"meta",relevance:10, +match:e(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) +},{className:"comment",variants:[{ +begin:e(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), +end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ +className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, +end:/$/}]})})());hljs.registerLanguage("shell",(()=>{"use strict";return s=>({ +name:"Shell Session",aliases:["console","shellsession"],contains:[{ +className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{ +end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]})})());hljs.registerLanguage("json",(()=>{"use strict";return e=>({name:"JSON", +contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01 +},{match:/[{}[\],:]/,className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{ +beginKeywords:"true false null" +},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}) +})());hljs.registerLanguage("java",(()=>{"use strict" +;var e="\\.([0-9](_*[0-9])*)",a="[0-9a-fA-F](_*[0-9a-fA-F])*",n={ +className:"number",variants:[{ +begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{ +begin:`\\b0[xX]((${a})\\.?|(${a})?\\.(${a}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${a})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};function s(e,a,n){return-1===n?"":e.replace(a,(t=>s(e,a,n-1)))} +return e=>{ +const a="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",t=a+s("(?:<"+a+"~~~(?:\\s*,\\s*"+a+"~~~)*>)?",/~~~/g,2),i={ +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"], +literal:["false","true","null"], +type:["char","boolean","long","float","int","byte","short","double"], +built_in:["super","this"]},r={className:"meta",begin:"@"+a,contains:[{ +begin:/\(/,end:/\)/,contains:["self"]}]},l={className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,a],className:{ +1:"keyword",3:"title.class"}},{begin:[a,/\s+/,a,/\s+/,/=/],className:{1:"type", +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,a],className:{1:"keyword", +3:"title.class"},contains:[l,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"new throw return else",relevance:0},{ +begin:["(?:"+t+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0, +contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,n,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},n,r]}}})());hljs.registerLanguage("objectivec",(()=>{"use strict";return e=>{ +const n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n, +keyword:["@interface","@class","@protocol","@implementation"]};return{ +name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], +keywords:{$pattern:n, +keyword:["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], +literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], +built_in:["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"] +},illegal:"/,end:/$/,illegal:"\\n" +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", +begin:"("+_.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:_, +contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, +relevance:0}]}}})());hljs.registerLanguage("dart",(()=>{"use strict";return e=>{const n={ +className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"}]},a={className:"subst", +variants:[{begin:/\$\{/,end:/\}/}],keywords:"true false null this is new super" +},t={className:"string",variants:[{begin:"r'''",end:"'''"},{begin:'r"""', +end:'"""'},{begin:"r'",end:"'",illegal:"\\n"},{begin:'r"',end:'"',illegal:"\\n" +},{begin:"'''",end:"'''",contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"""', +end:'"""',contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:"'",end:"'",illegal:"\\n", +contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"',end:'"',illegal:"\\n", +contains:[e.BACKSLASH_ESCAPE,n,a]}]};a.contains=[e.C_NUMBER_MODE,t] +;const i=["Comparable","DateTime","Duration","Function","Iterable","Iterator","List","Map","Match","Object","Pattern","RegExp","Set","Stopwatch","String","StringBuffer","StringSink","Symbol","Type","Uri","bool","double","int","num","Element","ElementList"],r=i.map((e=>e+"?")) +;return{name:"Dart",keywords:{ +keyword:["abstract","as","assert","async","await","break","case","catch","class","const","continue","covariant","default","deferred","do","dynamic","else","enum","export","extends","extension","external","factory","false","final","finally","for","Function","get","hide","if","implements","import","in","inferface","is","late","library","mixin","new","null","on","operator","part","required","rethrow","return","set","show","static","super","switch","sync","this","throw","true","try","typedef","var","void","while","with","yield"], +built_in:i.concat(r).concat(["Never","Null","dynamic","print","document","querySelector","querySelectorAll","window"]), +$pattern:/[A-Za-z][A-Za-z0-9_]*\??/}, +contains:[t,e.COMMENT(/\/\*\*(?!\/)/,/\*\//,{subLanguage:"markdown",relevance:0 +}),e.COMMENT(/\/{3,} ?/,/$/,{contains:[{subLanguage:"markdown",begin:".", +end:"$",relevance:0}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{ +className:"class",beginKeywords:"class interface",end:/\{/,excludeEnd:!0, +contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE] +},e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"},{begin:"=>"}]}}})());hljs.registerLanguage("ruby",(()=>{"use strict";function e(e){ +return n("(?=",e,")")}function n(...e){return e.map((e=>{ +return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return a=>{ +const i="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",s={ +keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__", +built_in:"proc lambda",literal:"true false nil"},r={className:"doctag", +begin:"@[A-Za-z]+"},b={begin:"#<",end:">"},c=[a.COMMENT("#","$",{contains:[r] +}),a.COMMENT("^=begin","^=end",{contains:[r],relevance:10 +}),a.COMMENT("^__END__","\\n$")],t={className:"subst",begin:/#\{/,end:/\}/, +keywords:s},g={className:"string",contains:[a.BACKSLASH_ESCAPE,t],variants:[{ +begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/, +end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{ +begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/, +end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{ +begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{ +begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ +begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ +begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ +begin:n(/<<[-~]?'?/,e(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), +contains:[a.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, +contains:[a.BACKSLASH_ESCAPE,t]})]}]},d="[0-9](_?[0-9])*",l={className:"number", +relevance:0,variants:[{ +begin:`\\b([1-9](_?[0-9])*|0)(\\.(${d}))?([eE][+-]?(${d})|r)?i?\\b`},{ +begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" +},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ +begin:"\\b0(_?[0-7])+r?i?\\b"}]},o={className:"params",begin:"\\(",end:"\\)", +endsParent:!0,keywords:s},_=[g,{className:"class",beginKeywords:"class module", +end:"$|;",illegal:/=/,contains:[a.inherit(a.TITLE_MODE,{ +begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{ +begin:"("+a.IDENT_RE+"::)?"+a.IDENT_RE,relevance:0}]}].concat(c)},{ +className:"function",begin:n(/def\s+/,e(i+"\\s*(\\(|;|$)")),relevance:0, +keywords:"def",end:"$|;",contains:[a.inherit(a.TITLE_MODE,{begin:i +}),o].concat(c)},{begin:a.IDENT_RE+"::"},{className:"symbol", +begin:a.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", +begin:":(?!\\s)",contains:[g,{begin:i}],relevance:0},l,{className:"variable", +begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ +className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:s},{ +begin:"("+a.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{ +className:"regexp",contains:[a.BACKSLASH_ESCAPE,t],illegal:/\n/,variants:[{ +begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(", +end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}] +}].concat(b,c),relevance:0}].concat(b,c);t.contains=_,o.contains=_;const E=[{ +begin:/^\s*=>/,starts:{end:"$",contains:_}},{className:"meta", +begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", +starts:{end:"$",contains:_}}];return c.unshift(b),{name:"Ruby", +aliases:["rb","gemspec","podspec","thor","irb"],keywords:s,illegal:/\/\*/, +contains:[a.SHEBANG({binary:"ruby"})].concat(E).concat(c).concat(_)}}})());hljs.registerLanguage("yaml",(()=>{"use strict";return e=>{ +const n="true false yes no null",a="[\\w#;/?:@&=+$,.~*'()[\\]]+",s={ +className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", +variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(s,{ +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={ +end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},t={begin:/\{/, +end:/\}/,contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]", +contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{ +begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ +begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", +relevance:10},{className:"string", +begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ +begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, +relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type", +begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a +},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", +begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", +relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ +className:"number", +begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" +},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},t,g,s],c=[...b] +;return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0, +aliases:["yml"],contains:b}}})());hljs.registerLanguage("javascript",(()=>{"use strict" +;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],s=["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],i=["arguments","this","super","console","window","document","localStorage","module","global"],c=[].concat(r,t,s) +;function o(e){return l("(?=",e,")")}function l(...e){return e.map((e=>{ +return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return b=>{ +const g=e,d={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/, +isTrulyOpeningTag:(e,n)=>{const a=e[0].length+e.index,t=e.input[a] +;"<"!==t?">"===t&&(((e,{after:n})=>{const a="",B={ +match:[/const|var|let/,/\s+/,g,/\s*/,/=\s*/,o(C)],className:{1:"keyword", +3:"title.function"},contains:[w]};return{name:"Javascript", +aliases:["js","jsx","mjs","cjs"],keywords:u,exports:{PARAMS_CONTAINS:S}, +illegal:/#(?![$_A-z])/,contains:[b.SHEBANG({label:"shebang",binary:"node", +relevance:5}),{label:"use_strict",className:"meta",relevance:10, +begin:/^\s*['"]use (strict|asm)['"]/ +},b.APOS_STRING_MODE,b.QUOTE_STRING_MODE,N,f,A,v,y,O,{className:"attr", +begin:g+o(":"),relevance:0},B,{ +begin:"("+b.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", +keywords:"return throw case",relevance:0,contains:[v,b.REGEXP_MODE,{ +className:"function",begin:C,returnBegin:!0,end:"\\s*=>",contains:[{ +className:"params",variants:[{begin:b.UNDERSCORE_IDENT_RE,relevance:0},{ +className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, +excludeEnd:!0,keywords:u,contains:S}]}]},{begin:/,/,relevance:0},{match:/\s+/, +relevance:0},{variants:[{begin:"<>",end:""},{begin:d.begin, +"on:begin":d.isTrulyOpeningTag,end:d.end}],subLanguage:"xml",contains:[{ +begin:d.begin,end:d.end,skip:!0,contains:["self"]}]}]},I,{ +beginKeywords:"while if switch catch for"},{ +begin:"\\b(?!function)"+b.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", +returnBegin:!0,label:"func.def",contains:[w,b.inherit(b.TITLE_MODE,{begin:g, +className:"title.function"})]},{match:/\.\.\./,relevance:0},M,{match:"\\$"+g, +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, +contains:[w]},T,{relevance:0,match:/\b[A-Z][A-Z_]+\b/, +className:"variable.constant"},R,k,{match:/\$[(.]/}]}}})());hljs.registerLanguage("c",(()=>{"use strict";function e(e){ +return((...e)=>e.map((e=>(e=>e?"string"==typeof e?e:e.source:null)(e))).join(""))("(?:",e,")?") +}return n=>{const t=n.COMMENT("//","$",{contains:[{begin:/\\\n/}] +}),s="[a-zA-Z_]\\w*::",r="(decltype\\(auto\\)|"+e(s)+"[a-zA-Z_]\\w*"+e("<[^<>]+>")+")",a={ +className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ +match:/\batomic_[a-z]{3,6}\b/}]},i={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[n.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},n.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},n.inherit(i,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,n.C_BLOCK_COMMENT_MODE]},o={ +className:"title",begin:e(s)+n.IDENT_RE,relevance:0 +},d=e(s)+n.IDENT_RE+"\\s*\\(",u={ +keyword:["asm","auto","break","case","const","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","static","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], +type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","complex","bool","imaginary"], +literal:"true false NULL", +built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" +},g=[c,a,t,n.C_BLOCK_COMMENT_MODE,l,i],m={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:g.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:g.concat(["self"]),relevance:0}]),relevance:0},_={ +begin:"("+r+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)", +keywords:u,relevance:0},{begin:d,returnBegin:!0,contains:[n.inherit(o,{ +className:"title.function"})],relevance:0},{relevance:0,match:/,/},{ +className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, +contains:[t,n.C_BLOCK_COMMENT_MODE,i,l,a,{begin:/\(/,end:/\)/,keywords:u, +relevance:0,contains:["self",t,n.C_BLOCK_COMMENT_MODE,i,l,a]}] +},a,t,n.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, +disableAutodetect:!0,illegal:"=]/,contains:[{ +beginKeywords:"final class struct"},n.TITLE_MODE]}]),exports:{preprocessor:c, +strings:i,keywords:u}}}})());hljs.registerLanguage("swift",(()=>{"use strict";function e(e){ +return e?"string"==typeof e?e:e.source:null}function a(e){return t("(?=",e,")")} +function t(...a){return a.map((a=>e(a))).join("")}function n(...a){ +return"("+((e=>{const a=e[e.length-1] +;return"object"==typeof a&&a.constructor===Object?(e.splice(e.length-1,1),a):{} +})(a).capture?"":"?:")+a.map((a=>e(a))).join("|")+")"} +const i=e=>t(/\b/,e,/\w$/.test(e)?/\b/:/\B/),s=["Protocol","Type"].map(i),u=["init","self"].map(i),c=["Any","Self"],r=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],o=["false","nil","true"],l=["assignment","associativity","higherThan","left","lowerThan","none","right"],m=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],p=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],F=n(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),d=n(F,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),b=t(F,d,"*"),h=n(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),f=n(h,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),w=t(h,f,"*"),y=t(/[A-Z]/,f,"*"),g=["autoclosure",t(/convention\(/,n("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",t(/objc\(/,w,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],E=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] +;return e=>{const F={match:/\s+/,relevance:0},h=e.COMMENT("/\\*","\\*/",{ +contains:["self"]}),v=[e.C_LINE_COMMENT_MODE,h],A={match:[/\./,n(...s,...u)], +className:{2:"keyword"}},N={match:t(/\./,n(...r)),relevance:0 +},C=r.filter((e=>"string"==typeof e)).concat(["_|0"]),D={variants:[{ +className:"keyword", +match:n(...r.filter((e=>"string"!=typeof e)).concat(c).map(i),...u)}]},k={ +$pattern:n(/\b\w+/,/#\w+/),keyword:C.concat(m),literal:o},B=[A,N,D],_=[{ +match:t(/\./,n(...p)),relevance:0},{className:"built_in", +match:t(/\b/,n(...p),/(?=\()/)}],S={match:/->/,relevance:0},M=[S,{ +className:"operator",relevance:0,variants:[{match:b},{match:`\\.(\\.|${d})+`}] +}],x="([0-9a-fA-F]_*)+",I={className:"number",relevance:0,variants:[{ +match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{ +match:`\\b0x(${x})(\\.(${x}))?([pP][+-]?(([0-9]_*)+))?\\b`},{ +match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},L=(e="")=>({ +className:"subst",variants:[{match:t(/\\/,e,/[0\\tnr"']/)},{ +match:t(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),O=(e="")=>({className:"subst", +match:t(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),T=(e="")=>({className:"subst", +label:"interpol",begin:t(/\\/,e,/\(/),end:/\)/}),$=(e="")=>({begin:t(e,/"""/), +end:t(/"""/,e),contains:[L(e),O(e),T(e)]}),j=(e="")=>({begin:t(e,/"/), +end:t(/"/,e),contains:[L(e),T(e)]}),P={className:"string", +variants:[$(),$("#"),$("##"),$("###"),j(),j("#"),j("##"),j("###")]},K={ +match:t(/`/,w,/`/)},z=[K,{className:"variable",match:/\$\d+/},{ +className:"variable",match:`\\$${f}+`}],q=[{match:/(@|#)available/, +className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:E, +contains:[...M,I,P]}]}},{className:"keyword",match:t(/@/,n(...g))},{ +className:"meta",match:t(/@/,w)}],U={match:a(/\b[A-Z]/),relevance:0,contains:[{ +className:"type", +match:t(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,f,"+") +},{className:"type",match:y,relevance:0},{match:/[?!]+/,relevance:0},{ +match:/\.\.\./,relevance:0},{match:t(/\s+&\s+/,a(y)),relevance:0}]},Z={ +begin://,keywords:k,contains:[...v,...B,...q,S,U]};U.contains.push(Z) +;const V={begin:/\(/,end:/\)/,relevance:0,keywords:k,contains:["self",{ +match:t(w,/\s*:/),keywords:"_|0",relevance:0 +},...v,...B,..._,...M,I,P,...z,...q,U]},W={begin://,contains:[...v,U] +},G={begin:/\(/,end:/\)/,keywords:k,contains:[{ +begin:n(a(t(w,/\s*:/)),a(t(w,/\s+/,w,/\s*:/))),end:/:/,relevance:0,contains:[{ +className:"keyword",match:/\b_\b/},{className:"params",match:w}] +},...v,...B,...M,I,P,...q,U,V],endsParent:!0,illegal:/["']/},R={ +match:[/func/,/\s+/,n(K.match,w,b)],className:{1:"keyword",3:"title.function"}, +contains:[W,G,F],illegal:[/\[/,/%/]},X={ +match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, +contains:[W,G,F],illegal:/\[|%/},H={match:[/operator/,/\s+/,b],className:{ +1:"keyword",3:"title"}},J={begin:[/precedencegroup/,/\s+/,y],className:{ +1:"keyword",3:"title"},contains:[U],keywords:[...l,...o],end:/}/} +;for(const e of P.variants){const a=e.contains.find((e=>"interpol"===e.label)) +;a.keywords=k;const t=[...B,..._,...M,I,P,...z];a.contains=[...t,{begin:/\(/, +end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:k, +contains:[...v,R,X,{beginKeywords:"struct protocol class extension enum actor", +end:"\\{",excludeEnd:!0,keywords:k,contains:[e.inherit(e.TITLE_MODE,{ +className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...B] +},H,J,{beginKeywords:"import",end:/$/,contains:[...v],relevance:0 +},...B,..._,...M,I,P,...z,...q,U,V]}}})()); \ No newline at end of file diff --git a/auth0_flutter/doc/api/static-assets/play_button.svg b/auth0_flutter/doc/api/static-assets/play_button.svg new file mode 100644 index 00000000..c39a2f4a --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/play_button.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/auth0_flutter/doc/api/static-assets/readme.md b/auth0_flutter/doc/api/static-assets/readme.md new file mode 100644 index 00000000..357c11ca --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/readme.md @@ -0,0 +1,22 @@ +# highlight.js + +Generated from https://highlightjs.org/download/ on 2021-07-13 + +**Included languages:** + +* bash +* c +* css +* dart +* diff +* html, xml +* java +* javascript +* json +* kotlin +* markdown +* objective-c +* plaintext +* shell +* swift +* yaml diff --git a/auth0_flutter/doc/api/static-assets/script.js b/auth0_flutter/doc/api/static-assets/script.js new file mode 100644 index 00000000..e88f0306 --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/script.js @@ -0,0 +1,501 @@ +/* + * + * Update script.js versions in all lib/templates when modifying this file! + * + */ +function initSideNav() { + const leftNavToggle = document.getElementById('sidenav-left-toggle'); + const leftDrawer = document.querySelector('.sidebar-offcanvas-left'); + const overlay = document.getElementById('overlay-under-drawer'); + + function toggleBoth() { + if (leftDrawer) { + leftDrawer.classList.toggle('active'); + } + + if (overlay) { + overlay.classList.toggle('active'); + } + } + + if (overlay) { + overlay.addEventListener('click', toggleBoth); + } + + if (leftNavToggle) { + leftNavToggle.addEventListener('click', toggleBoth); + } +} + +function saveLeftScroll() { + const leftSidebar = document.getElementById('dartdoc-sidebar-left'); + sessionStorage.setItem('dartdoc-sidebar-left-scrollt' + window.location.pathname, leftSidebar.scrollTop.toString()); + sessionStorage.setItem('dartdoc-sidebar-left-scrolll' + window.location.pathname, leftSidebar.scrollLeft.toString()); +} + +function saveMainContentScroll() { + const mainContent = document.getElementById('dartdoc-main-content'); + sessionStorage.setItem('dartdoc-main-content-scrollt' + window.location.pathname, mainContent.scrollTop.toString()); + sessionStorage.setItem('dartdoc-main-content-scrolll' + window.location.pathname, mainContent.scrollLeft.toString()); +} + +function saveRightScroll() { + const rightSidebar = document.getElementById('dartdoc-sidebar-right'); + sessionStorage.setItem('dartdoc-sidebar-right-scrollt' + window.location.pathname, rightSidebar.scrollTop.toString()); + sessionStorage.setItem('dartdoc-sidebar-right-scrolll' + window.location.pathname, rightSidebar.scrollLeft.toString()); +} + +function restoreScrolls() { + const leftSidebar = document.getElementById('dartdoc-sidebar-left'); + const mainContent = document.getElementById('dartdoc-main-content'); + const rightSidebar = document.getElementById('dartdoc-sidebar-right'); + + try { + const leftSidebarX = sessionStorage.getItem('dartdoc-sidebar-left-scrolll' + window.location.pathname); + const leftSidebarY = sessionStorage.getItem('dartdoc-sidebar-left-scrollt' + window.location.pathname); + + const mainContentX = sessionStorage.getItem('dartdoc-main-content-scrolll' + window.location.pathname); + const mainContentY = sessionStorage.getItem('dartdoc-main-content-scrollt' + window.location.pathname); + + const rightSidebarX = sessionStorage.getItem('dartdoc-sidebar-right-scrolll' + window.location.pathname); + const rightSidebarY = sessionStorage.getItem('dartdoc-sidebar-right-scrollt' + window.location.pathname); + + leftSidebar.scrollTo(parseFloat(leftSidebarX), parseFloat(leftSidebarY)); + mainContent.scrollTo(parseFloat(mainContentX), parseFloat(mainContentY)); + rightSidebar.scrollTo(parseFloat(rightSidebarX), parseFloat(rightSidebarY)); + } finally { + // Set visibility to visible after scroll to prevent the brief appearance of the + // panel in the wrong position. + leftSidebar.style.visibility = 'visible'; + mainContent.style.visibility = 'visible'; + rightSidebar.style.visibility = 'visible'; + } +} + +function initScrollSave() { + const leftSidebar = document.getElementById('dartdoc-sidebar-left'); + const mainContent = document.getElementById('dartdoc-main-content'); + const rightSidebar = document.getElementById('dartdoc-sidebar-right'); + + leftSidebar.addEventListener("scroll", saveLeftScroll, true); + mainContent.addEventListener("scroll", saveMainContentScroll, true); + rightSidebar.addEventListener("scroll", saveRightScroll, true); +} + +const weights = { + 'library' : 2, + 'class' : 2, + 'mixin' : 3, + 'extension' : 3, + 'typedef' : 3, + 'method' : 4, + 'accessor' : 4, + 'operator' : 4, + 'constant' : 4, + 'property' : 4, + 'constructor' : 4 +}; + +function findMatches(index, query) { + if (query === '') { + return []; + } + + const allMatches = []; + + index.forEach(element => { + function score(value) { + value -= element.overriddenDepth * 10; + const weightFactor = weights[element.type] || 4; + allMatches.push({element: element, score: (value / weightFactor) >> 0}); + } + + const name = element.name; + const qualifiedName = element.qualifiedName; + const lowerName = name.toLowerCase(); + const lowerQualifiedName = qualifiedName.toLowerCase(); + const lowerQuery = query.toLowerCase(); + + if (name === query || qualifiedName === query || name === `dart:${query}`) { + score(2000); + } else if (lowerName === `dart:${lowerQuery}`) { + score(1800); + } else if (lowerName === lowerQuery || lowerQualifiedName === lowerQuery) { + score(1700); + } else if (query.length > 1) { + if (name.startsWith(query) || qualifiedName.startsWith(query)) { + score(750); + } else if (lowerName.startsWith(lowerQuery) || lowerQualifiedName.startsWith(lowerQuery)) { + score(650); + } else if (name.includes(query) || qualifiedName.includes(query)) { + score(500); + } else if (lowerName.includes(lowerQuery) || lowerQualifiedName.includes(query)) { + score(400); + } + } + }); + + allMatches.sort((a, b) => { + const x = b.score - a.score; + if (x === 0) { + return a.element.name.length - b.element.name.length; + } + return x; + }); + + const justElements = []; + + for (let i = 0; i < allMatches.length; i++) { + justElements.push(allMatches[i].element); + } + + return justElements; +} + +let baseHref = ''; + +const minLength = 1; +const suggestionLimit = 10; + +function initializeSearch(input, index) { + input.disabled = false; + input.setAttribute('placeholder', 'Search API Docs'); + + // Handle grabbing focus when the users types / outside of the input + document.addEventListener('keypress', (event) => { + if (event.code === 'Slash' && !(document.activeElement instanceof HTMLInputElement)) { + event.preventDefault(); + input.focus(); + } + }); + + // Prepare elements + + const parentForm = input.parentNode; + const wrapper = document.createElement('div'); + wrapper.classList.add('tt-wrapper'); + + parentForm.replaceChild(wrapper, input); + + const inputHint = document.createElement('input'); + inputHint.setAttribute('type', 'text'); + inputHint.setAttribute('autocomplete', 'off'); + inputHint.setAttribute('readonly', 'true'); + inputHint.setAttribute('spellcheck', 'false'); + inputHint.setAttribute('tabindex', '-1'); + inputHint.classList.add('typeahead', 'tt-hint'); + + wrapper.appendChild(inputHint); + + input.setAttribute('autocomplete', 'off'); + input.setAttribute('spellcheck', 'false'); + input.classList.add('tt-input'); + + wrapper.appendChild(input); + + const listBox = document.createElement('div'); + listBox.setAttribute('role', 'listbox'); + listBox.setAttribute('aria-expanded', 'false'); + listBox.style.display = 'none'; + listBox.classList.add('tt-menu'); + + const presentation = document.createElement('div'); + presentation.classList.add('tt-elements'); + + listBox.appendChild(presentation); + + wrapper.appendChild(listBox); + + // Set up various search functionality + + function highlight(text, query) { + query = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return text.replace(new RegExp(query, 'gi'), (matched) => { + return `${matched}`; + }); + } + + function createSuggestion(query, match) { + const suggestion = document.createElement('div'); + suggestion.setAttribute('data-href', match.href); + suggestion.classList.add('tt-suggestion'); + + const suggestionTitle = document.createElement('span'); + suggestionTitle.classList.add('tt-suggestion-title'); + suggestionTitle.innerHTML = highlight(`${match.name} ${match.type.toLowerCase()}`, query); + + suggestion.appendChild(suggestionTitle); + + if (match.enclosedBy) { + const fromLib = document.createElement('div'); + fromLib.classList.add('search-from-lib'); + fromLib.innerHTML = `from ${highlight(match.enclosedBy.name, query)}`; + + suggestion.appendChild(fromLib); + } + + suggestion.addEventListener('mousedown', event => { + event.preventDefault(); + }); + + suggestion.addEventListener('click', event => { + if (match.href) { + window.location = baseHref + match.href; + event.preventDefault(); + } + }); + + return suggestion; + } + + let storedValue = null; + let actualValue = ''; + let hint = null; + + let suggestionElements = []; + let suggestionsInfo = []; + let selectedElement = null; + + function setHint(value) { + hint = value; + inputHint.value = value || ''; + } + + function updateSuggestions(query, suggestions) { + suggestionsInfo = []; + suggestionElements = []; + presentation.textContent = ''; + + if (suggestions.length < minLength) { + setHint(null) + hideSuggestions(); + return; + } + + for (let i = 0; i < suggestions.length; i++) { + const element = createSuggestion(query, suggestions[i]); + suggestionElements.push(element); + presentation.appendChild(element); + } + + suggestionsInfo = suggestions; + + setHint(query + suggestions[0].name.slice(query.length)); + selectedElement = null; + + showSuggestions(); + } + + function handle(newValue, forceUpdate) { + if (actualValue === newValue && !forceUpdate) { + return; + } + + if (newValue === null || newValue.length === 0) { + updateSuggestions('', []); + return; + } + + const suggestions = findMatches(index, newValue).slice(0, suggestionLimit); + actualValue = newValue; + + updateSuggestions(newValue, suggestions); + } + + function showSuggestions() { + if (presentation.hasChildNodes()) { + listBox.style.display = 'block'; + listBox.setAttribute('aria-expanded', 'true'); + } + } + + function hideSuggestions() { + listBox.style.display = 'none'; + listBox.setAttribute('aria-expanded', 'false'); + } + + // Hook up events + + input.addEventListener('focus', () => { + handle(input.value, true); + }); + + input.addEventListener('blur', () => { + selectedElement = null; + if (storedValue !== null) { + input.value = storedValue; + storedValue = null; + } + hideSuggestions(); + setHint(null); + }); + + input.addEventListener('input', event => { + handle(event.target.value); + }); + + input.addEventListener('keydown', event => { + if (suggestionElements.length === 0) { + return; + } + + if (event.code === 'Enter') { + const selectingElement = selectedElement || 0; + const href = suggestionElements[selectingElement].dataset.href; + if (href) { + window.location = baseHref + href; + } + return; + } + + if (event.code === 'Tab') { + if (selectedElement === null) { + // The user wants to fill the field with the hint + if (hint !== null) { + input.value = hint; + handle(hint); + event.preventDefault(); + } + } else { + // The user wants to fill the input field with their currently selected suggestion + handle(suggestionsInfo[selectedElement].name); + storedValue = null; + selectedElement = null; + event.preventDefault(); + } + return; + } + + const lastIndex = suggestionElements.length - 1; + const previousSelectedElement = selectedElement; + + if (event.code === 'ArrowUp') { + if (selectedElement === null) { + selectedElement = lastIndex; + } else if (selectedElement === 0) { + selectedElement = null; + } else { + selectedElement--; + } + } else if (event.code === 'ArrowDown') { + if (selectedElement === null) { + selectedElement = 0; + } else if (selectedElement === lastIndex) { + selectedElement = null; + } else { + selectedElement++; + } + } else { + if (storedValue !== null) { + storedValue = null; + handle(input.value); + } + return; + } + + if (previousSelectedElement !== null) { + suggestionElements[previousSelectedElement].classList.remove('tt-cursor'); + } + + if (selectedElement !== null) { + const selected = suggestionElements[selectedElement]; + selected.classList.add('tt-cursor'); + + // Guarantee the selected element is visible + if (selectedElement === 0) { + listBox.scrollTop = 0; + } else if (selectedElement === lastIndex) { + listBox.scrollTop = listBox.scrollHeight; + } else { + const offsetTop = selected.offsetTop; + const parentOffsetHeight = listBox.offsetHeight; + if (offsetTop < parentOffsetHeight || parentOffsetHeight < (offsetTop + selected.offsetHeight)) { + selected.scrollIntoView({behavior: 'auto', block: 'nearest'}); + } + } + + if (storedValue === null) { + // Store the actual input value to display their currently selected item + storedValue = input.value; + } + input.value = suggestionsInfo[selectedElement].name; + setHint(''); + } else if (storedValue !== null && previousSelectedElement !== null) { + // They are moving back to the input field, so return the stored value + input.value = storedValue; + setHint(storedValue + suggestionsInfo[0].name.slice(storedValue.length)); + storedValue = null; + } + + event.preventDefault(); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + // Place this first so that unexpected exceptions in other JavaScript do not block page visibility. + restoreScrolls(); + hljs.highlightAll(); + initSideNav(); + initScrollSave(); + + const searchBox = document.getElementById('search-box'); + const searchBody = document.getElementById('search-body'); + const searchSidebar = document.getElementById('search-sidebar'); + + if (document.body.getAttribute('data-using-base-href') === 'false') { + // If dartdoc did not add a base-href tag, we will need to add the relative + // path ourselves. + baseHref = document.body.getAttribute('data-base-href'); + } + + function disableSearch() { + console.log('Could not activate search functionality.'); + if (searchBox) { + searchBox.placeholder = 'Failed to initialize search'; + } + + if (searchBody) { + searchBody.placeholder = 'Failed to initialize search'; + } + + if (searchSidebar) { + searchSidebar.placeholder = 'Failed to initialize search'; + } + } + + if ('fetch' in window) { + fetch(baseHref + 'index.json', {method: 'GET'}) + .then(response => response.json()) + .then(index => { + // Handle if the user specified a `search` parameter in the URL + if ('URLSearchParams' in window) { + const search = new URLSearchParams(window.location.search).get('search'); + if (search) { + const matches = findMatches(search); + if (matches.length !== 0) { + window.location = baseHref + matches[0].href; + return; + } + } + } + + // Initialize all three search fields + if (searchBox) { + initializeSearch(searchBox, index); + } + + if (searchBody) { + initializeSearch(searchBody, index); + } + + if (searchSidebar) { + initializeSearch(searchSidebar, index); + } + }) + .catch(() => { + disableSearch(); + }); + } else { + disableSearch(); + } +}); diff --git a/auth0_flutter/doc/api/static-assets/styles.css b/auth0_flutter/doc/api/static-assets/styles.css new file mode 100644 index 00000000..7ea04df3 --- /dev/null +++ b/auth0_flutter/doc/api/static-assets/styles.css @@ -0,0 +1,1022 @@ +/* + * + * Update styles.css versions in all lib/templates when modifying this file! + * + */ + +/* Palette generated by Material Palette - materialpalette.com/blue/cyan */ + +.dark-primary-color { background: #1976D2; } +.default-primary-color { background: #2196F3; } +.light-primary-color { background: #BBDEFB; } +.text-primary-color { color: #FFFFFF; } +.accent-color { background: #00BCD4; } +.primary-text-color { color: #212121; } +.secondary-text-color { color: #727272; } +.divider-color { border-color: #B6B6B6; } + +/* for layout */ +html, +body { + margin: 0; + padding: 0; + height: 100%; + width: 100%; + overflow: hidden; + box-sizing: border-box; +} + +*, *:before, *:after { + box-sizing: inherit; +} + +body { + display: flex; + flex-direction: column; + -webkit-overflow-scrolling: touch; +} + +header { + flex: 0 0 50px; + display: flex; + flex-direction: row; + align-items: center; + padding-left: 30px; +} + +header ol { + list-style: none; + margin: 0; + padding: 0; +} + +header ol li { + display: inline; +} + +header form { + display: flex; + flex: 1; + justify-content: flex-end; + padding-right: 30px; +} + +header#header-search-sidebar { + height: 50px; + margin-bottom: 25px; +} + +footer { + flex: 0 0 16px; + text-align: center; + padding: 16px 20px; +} + +main { + flex: 1; + display: flex; + flex-direction: row; + padding: 20px; + min-height: 0; +} + +.sidebar-offcanvas-left { + flex: 0 1 230px; + order: 1; + overflow-y: scroll; + padding: 20px 0 15px 30px; + margin: 5px 20px 0 0; + visibility: hidden; /* shown by Javascript after scroll position restore */ +} + +::-webkit-scrollbar-button{ display: none; height: 13px; border-radius: 0px; background-color: #AAA; } +::-webkit-scrollbar-button:hover{ background-color: #AAA; } +::-webkit-scrollbar-thumb{ background-color: #CCC; } +::-webkit-scrollbar-thumb:hover{ background-color: #CCC; } +::-webkit-scrollbar{ width: 4px; } + +.main-content::-webkit-scrollbar{ width: 8px; } + +.main-content { + flex: 1; + order: 2; + overflow-y: scroll; + padding: 10px 20px 0 20px; + visibility: hidden; /* shown by Javascript after scroll position restore */ +} + +.sidebar-offcanvas-right { + flex: 0 1 12em; + order: 3; + overflow-y: scroll; + padding: 20px 15px 15px 15px; + margin-top: 5px; + margin-right: 20px; + visibility: hidden; /* shown by Javascript after scroll position restore */ +} +/* end for layout */ + +body { + -webkit-text-size-adjust: 100%; + overflow-x: hidden; + font-family: Roboto, sans-serif; + font-size: 16px; + line-height: 1.42857143; + color: #111111; + background-color: #fff; +} + +/* some of this is to reset bootstrap */ +nav.navbar { + background-color: inherit; + min-height: 50px; + border: 0; +} + +@media (max-width: 768px) { + .hidden-xs { + display: none !important; + } +} + +@media (min-width: 769px) { + .hidden-l { + display: none !important; + } +} + +nav.navbar .row { + padding-top: 8px; +} + +nav .container { + white-space: nowrap; +} + +header { + background-color: #eeeeee; + box-shadow: 0 3px 5px rgba(0,0,0,0.1); +} + +header.header-fixed nav.navbar-fixed-top { + box-shadow: 0 3px 5px rgba(0,0,0,0.1); +} + +header.container-fluid { + padding: 0; +} + +header .masthead { + padding-top: 64px; +} + +header .contents { + padding: 0; +} + +@media screen and (max-width:768px) { + header .contents { + padding-left: 15px; + padding-right: 15px; + } +} + +a { + text-decoration: none; +} + +.body { + margin-top: 90px; +} + +section { + margin-bottom: 36px; +} + +dl { + margin: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: Roboto, sans-serif; + font-weight: 400; + margin-top: 1.5em; + color: #111111; +} + +h1.title { + overflow: hidden; + text-overflow: ellipsis; +} + +h1 { + font-size: 37px; + margin-top: 0; + margin-bottom: 0.67em; +} + +h2 { + font-size: 28px; +} + +h5 { + font-size: 16px; +} + +.subtitle { + font-size: 17px; + min-height: 1.4em; +} + +.title-description .subtitle { + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; +} + +p { + margin-bottom: 1em; + margin-top: 0; +} + +a { + color: #0175C2; +} + +a:hover { + color: #13B9FD; +} + +pre.prettyprint { + font-family: 'Roboto Mono', Menlo, monospace; + color: black; + border-radius: 0; + font-size: 15px; + word-wrap: normal; + line-height: 1.4; + border: 0; + margin: 16px 0 16px 0; + padding: 8px; +} + +pre code { + white-space: pre; + word-wrap: initial; + font-size: 100% +} + +.fixed { + white-space: pre; +} + +pre { + border: 1px solid #ddd; + background-color: #eee; + font-size: 14px; +} + +code { + font-family: 'Roboto Mono', Menlo, monospace; + /* overriding bootstrap */ + color: inherit; + padding: 0.2em 0.4em; + font-size: 85%; + background-color: rgba(27,31,35,0.05); + border-radius: 3px; +} + +@media(max-width: 768px) { + nav .container { + width: 100% + } + + h1 { + font-size: 24px; + } + + pre { + margin: 16px 0; + } +} + +@media (min-width: 768px) { + ul.subnav li { + font-size: 17px; + } +} + +header h1 { + font-weight: 400; + margin-bottom: 16px; +} + +header a, +header p, +header li { + color: #111111; +} + +header a:hover { + color: #0175C2; +} + +header h1 .kind { + color: #555; +} + +dt { + font-weight: normal; +} + +dd { + color: #212121; + margin-bottom: 1em; + margin-left: 0; +} + +dd.callable, dd.constant, dd.property { + margin-bottom: 24px; +} + +dd p { + overflow-x: hidden; + text-overflow: ellipsis; + margin-bottom: 0; +} + +/* Enum values do not have their own pages; their full docs are presented on the + * enum class's page. */ +dt.constant + dd p { + margin-bottom: 1em; +} + +/* indents wrapped lines */ +section.summary dt { + margin-left: 24px; + text-indent: -24px; +} + +.dl-horizontal dd { + margin-left: initial; +} + +dl.dl-horizontal dt { + font-style: normal; + text-align: left; + color: #727272; + margin-right: 20px; + width: initial; +} + +dt .name { + font-weight: 500; +} + +dl dt.callable .name { + float: none; + width: auto; +} + +.parameter { + white-space: nowrap; +} + +.type-parameter { + white-space: nowrap; +} + +.multi-line-signature .type-parameter .parameter { + margin-left: 0px; + display: unset; +} + +.parameter-list { + display: table-cell; + margin-left: 10px; + list-style-type: none; +} + +.signature { + color: #727272; +} + +.signature a { + /* 50% mix of default-primary-color and primary-text-color. */ + color: #4674a2; +} + +.optional { + font-style: italic; +} + +.undocumented { + font-style: italic; +} + +.is-const { + font-style: italic; +} + +.deprecated { + text-decoration: line-through; +} + +.category.linked { + font-weight: bold; + opacity: 1; +} + +/* Colors for category based on categoryOrder in dartdoc_options.config. */ +.category.cp-0 { + background-color: #54b7c4 +} + +.category.cp-1 { + background-color: #54c47f +} + +.category.cp-2 { + background-color: #c4c254 +} + +.category.cp-3 { + background-color: #c49f54 +} + +.category.cp-4 { + background-color: #c45465 +} + +.category.cp-5 { + background-color: #c454c4 +} + +.category a { + color: white; +} + +.category { + padding: 2px 4px; + font-size: 12px; + border-radius: 4px; + background-color: #999; + text-transform: uppercase; + color: white; + opacity: .5; +} + +h1 .category { + vertical-align: middle; +} + +.feature { + display: inline-block; + background: white; + border: 1px solid #0175c2; + border-radius: 20px; + color: #0175c2; + + font-size: 12px; + padding: 1px 6px; + margin: 0 8px 0 0; +} + +a.feature:hover { + border-color: #13B9FD; +} + +h1 .feature { + vertical-align: middle; +} + +.source-link { + padding: 18px 4px; + vertical-align: middle; +} + +.source-link .material-icons { + font-size: 18px; +} + +@media (max-width: 768px) { + .source-link { + padding: 7px 2px; + font-size: 10px; + } +} + +#external-links { + float: right; +} + +.btn-group { + position: relative; + display: inline-flex; + vertical-align: middle; +} + +p.firstline { + font-weight: bold; +} + +footer { + color: #fff; + background-color: #111111; + width: 100%; +} + +footer p { + margin: 0; +} + +footer .no-break { + white-space: nowrap; +} + +footer .container, +footer .container-fluid { + padding-left: 0; + padding-right: 0; +} + +footer a, footer a:hover { + color: #fff; +} + +.markdown.desc { + max-width: 700px; +} + +.markdown h1 { + font-size: 24px; + margin-bottom: 8px; +} + +.markdown h2 { + font-size: 20px; + margin-top: 24px; + margin-bottom: 8px; +} + +.markdown h3 { + font-size: 18px; + margin-bottom: 8px; +} + +.markdown h4 { + font-size: 16px; + margin-bottom: 0; +} + +.markdown li p { + margin: 0; +} + +.gt-separated { + list-style: none; + padding: 0; + margin: 0; +} + +.gt-separated li { + display: inline-block; +} + +.gt-separated li:before { + background-image: url("data:image/svg+xml;utf8,"); + background-position: center; + content: "\00a0"; + margin: 0 6px 0 4px; + padding: 0 3px 0 0; +} + +.gt-separated.dark li:before { + background-image: url("data:image/svg+xml;utf8,"); +} + +.gt-separated li:first-child:before { + background-image: none; + content: ""; + margin: 0; + padding: 0; +} + +/* The slug line under a declaration for things like "const", "read-only", etc. */ +.features { + font-style: italic; + color: #727272; +} + +.multi-line-signature { + font-size: 17px; + color: #727272; +} + +.multi-line-signature .parameter { + margin-left: 24px; + display: block; +} + +.breadcrumbs { + padding: 0; + margin: 8px 0 8px 0; + white-space: nowrap; + line-height: 1; +} + +@media screen and (min-width: 768px) { + nav ol.breadcrumbs { + float: left; + } +} + +@media screen and (max-width: 768px) { + .breadcrumbs { + margin: 0 0 24px 0; + overflow-x: hidden; + } +} + +.self-crumb { + color: #555; +} + +.self-name { + color: #555; + display: none; +} + +.annotation-list { + list-style: none; + padding: 0; + display: inline; +} + +.comma-separated { + list-style: none; + padding: 0; + display: inline; +} + +.comma-separated li { + display: inline; +} + +.comma-separated li:after { + content: ", "; +} + +.comma-separated li:last-child:after { + content: ""; +} + +.end-with-period li:last-child:after { + content: "."; +} + +.container > section:first-child { + border: 0; +} + +.constructor-modifier { + font-style: italic; +} + +section.multi-line-signature div.parameters { + margin-left: 24px; +} + +/* subnav styles */ + +ul.subnav { + overflow: auto; + white-space: nowrap; + padding-left: 0; + min-height: 25px; +} + +ul.subnav::-webkit-scrollbar { + display: none; +} + +ul.subnav li { + display: inline-block; + text-transform: uppercase; +} + +ul.subnav li a { + color: #111; +} + +ul.subnav li { + margin-right: 24px; +} + +ul.subnav li:last-of-type { + margin-right: 0; +} + +@media(max-width: 768px) { + ul.subnav li { + margin-right: 16px; + } +} + +/* sidebar styles */ + +.sidebar ol { + list-style: none; + line-height: 22px; + margin-top: 0; + margin-bottom: 0; + padding: 0 0 15px 0; +} + +.sidebar h5 a, +.sidebar h5 a:hover { + color: #727272; +} + +.sidebar h5, +.sidebar ol li { + text-overflow: ellipsis; + overflow: hidden; + padding: 3px 0 3px 3px; +} + +.sidebar h5 { + color: #727272; + font-size: 18px; + margin: 0 0 22px 0; + padding-top: 0; +} + +.sidebar ol li.section-title { + font-size: 18px; + font-weight: normal; + text-transform: uppercase; + padding-top: 25px; +} + +.sidebar ol li.section-subtitle a { + color: inherit; +} + +.sidebar ol li.section-subtitle { + font-weight: 400; + text-transform: uppercase; +} + +.sidebar ol li.section-subitem { + margin-left: 12px; +} + +.sidebar ol li:first-child { + padding-top: 3px; + margin-top: 0; +} + +button { + padding: 0; +} + +#sidenav-left-toggle { + display: none; + vertical-align: text-bottom; + padding: 0; +} + +/* left-nav disappears, and can transition in from the left */ +@media screen and (max-width:768px) { + #sidenav-left-toggle { + display: inline; + background: no-repeat url("data:image/svg+xml;utf8,"); + background-position: center; + width: 24px; + height: 24px; + border: none; + margin-right: 24px; + } + + #overlay-under-drawer.active { + opacity: 0.4; + height: 100%; + z-index: 1999; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: black; + display: block; + } + + .sidebar-offcanvas-left { + left: -100%; + position: fixed; + -webkit-transition:all .25s ease-out; + -o-transition:all .25s ease-out; + transition:all .25s ease-out; + z-index: 2000; + top: 0; + width: 280px; /* works all the way down to an iphone 4 */ + height: 90%; + background-color: white; + overflow-y: scroll; /* TODO: how to hide scroll bars? */ + padding: 10px; + margin: 10px 10px; + box-shadow: 5px 5px 5px 5px #444444; + visibility: hidden; /* shown by Javascript after scroll position restore */ + } + + ol#sidebar-nav { + font-size: 18px; + white-space: pre-line; + } + + .sidebar-offcanvas-left.active { + left: 0; /* this animates our drawer into the page */ + } + + .self-name { + display: inline-block; + } +} + +.sidebar-offcanvas-left h5 { + margin-bottom: 10px; +} + +.sidebar-offcanvas-left h5:last-of-type { + border: 0; + margin-bottom: 25px; +} + +/* the right nav disappears out of view when the window shrinks */ +@media screen and (max-width: 992px) { + .sidebar-offcanvas-right { + display: none; + } +} + +#overlay-under-drawer { + display: none; +} + +/* find-as-you-type search box */ + +/* override bootstrap defaults */ +.form-control { + border-radius: 0; + border: 0; +} + +@media screen and (max-width: 768px) { + form.search { + display: none; + } +} + +.typeahead, +.tt-query, +.tt-hint { + width: 200px; + height: 20px; + padding: 2px 7px 1px 7px; + line-height: 20px; + outline: none; +} + +.typeahead { + background-color: #fff; + border-radius: 2px; +} + +.tt-wrapper { + position: relative; + display: inline-block; +} + +.tt-input { + position: relative; + vertical-align: top; + background-color: transparent; +} + +.tt-query { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.tt-hint { + position: absolute; + top: 0; + left: 0; + box-shadow: none; + background: none 0 0 / auto repeat scroll padding-box border-box rgb(255, 255, 255); + border-color: transparent; + color: #999; + border-width: 0; +} + +.navbar-right .tt-menu { + right:0; + left: inherit !important; + width: 422px; + max-height: 250px; + overflow-y: scroll; +} + +.tt-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 100; + font-size: 14px; + margin: 0; + padding: 8px 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); + box-shadow: 0 5px 10px rgba(0,0,0,.2); +} + +.tt-suggestion { + padding: 3px 20px; + color: #212121; +} + +.tt-suggestion:hover { + cursor: pointer; + color: #fff; + background-color: #0097cf; +} + +.tt-suggestion:hover .search-from-lib { + color: #ddd; +} + +.tt-suggestion.tt-cursor { + color: #fff; + background-color: #0097cf; +} + +.tt-suggestion.tt-cursor .search-from-lib { + color: #ddd; +} + +.tt-suggestion p { + margin: 0; +} + +.search-from-lib { + font-style: italic; + color: gray; +} + +.search-body { + border: 1px solid #7f7f7f; + max-width: 400px; + box-shadow: 3px 3px 5px rgba(0,0,0,0.1); +} + +section#setter { + border-top: 1px solid #ddd; + padding-top: 36px; +} + +li.inherited a { + opacity: 0.65; + font-style: italic; +} + +#instance-methods dt.inherited .name, +#instance-properties dt.inherited .name, +#operators dt.inherited .name { + font-weight: 300; + font-style: italic; +} + +#instance-methods dt.inherited .signature, +#instance-properties dt.inherited .signature, +#operators dt.inherited .signature { + font-weight: 300; +} + +@media print { + .subnav, .sidebar { + display:none; + } + + a[href]:after { + content:"" !important; + } +} diff --git a/auth0_flutter/lib/auth0_flutter.dart b/auth0_flutter/lib/auth0_flutter.dart index 9e83762a..bd32cd73 100644 --- a/auth0_flutter/lib/auth0_flutter.dart +++ b/auth0_flutter/lib/auth0_flutter.dart @@ -5,18 +5,55 @@ import 'src/version.dart'; import 'src/web_authentication.dart'; export 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart' - show WebAuthException, ApiException, IdTokenValidationConfig; + show + WebAuthException, + ApiException, + IdTokenValidationConfig, + Credentials, + UserProfile; +export 'src/authentication_api.dart'; +export 'src/web_authentication.dart'; + +/// Primary interface for interacting with Auth0 using web authentication, or the authentication API. class Auth0 { final Account _account; + final UserAgent _userAgent = UserAgent(name: 'auth0-flutter', version: version); + /// Creates an intance of an Auth0 client with the provided [domain] and [clientId] properties. + /// + /// [domain] and [clientId] are both values that can be retrieved from the application in your [Auth0 Dashboard](https://manage.auth0.com). Auth0(final String domain, final String clientId) : _account = Account(domain, clientId); + /// An instance of [WebAuthentication], the primary interface for interacting with the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login). + /// + /// Usage example: + /// + /// ```dart + /// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); + /// final result = await auth0.webAuthentication.login(); + /// final accessToken = result.accessToken; + /// ``` WebAuthentication get webAuthentication => WebAuthentication(_account, _userAgent); + /// An instance of [AuthenticationApi], the primary interface for interacting with the Auth0 Authentication API + /// + /// Usage example: + /// + /// ```dart + /// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); + /// + /// final result = await auth0.api.login({ + /// usernameOrEmail: 'my@email.com', + /// password: 'my_password' + /// connectionOrRealm: 'Username-Password-Authentication' + /// }); + /// + /// final accessToken = result.accessToken; + /// ``` AuthenticationApi get api => AuthenticationApi(_account, _userAgent); } diff --git a/auth0_flutter/lib/src/authentication_api.dart b/auth0_flutter/lib/src/authentication_api.dart index bfc15bbd..73efe390 100644 --- a/auth0_flutter/lib/src/authentication_api.dart +++ b/auth0_flutter/lib/src/authentication_api.dart @@ -1,11 +1,55 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; +/// An interface for calling some of the endpoints in [Auth0's Authentication API](https://auth0.com/docs/api/authentication). +/// +/// This class presents building blocks for doing more fine-grained authentication with Auth0 using Username and Password login. Unlike +/// [WebAuthentication], these do **not** use [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) (the recommended way of doing authentication), +/// and thus users are not redirected to Auth0 for authentication. +/// +/// It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as [Auth0.api]. +/// +/// Usage example: +/// +/// ```dart +/// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); +/// +/// final result = await auth0.api.login({ +/// usernameOrEmail: 'my@email.com', +/// password: 'my_password' +/// connectionOrRealm: 'Username-Password-Authentication' +/// }) +/// +/// final accessToken = result.accessToken; +/// ``` class AuthenticationApi { final Account _account; final UserAgent _userAgent; AuthenticationApi(this._account, this._userAgent); + /// Authenticates the user using a [usernameOrEmail] and a [password], with the specified [connectionOrRealm]. If successful, it returns + /// a set of tokens, as well as the user's profile (constructed from ID token claims). + /// + /// If using the default username and password database connection, [connectionOrRealm] should be set to `Username-Password-Authentication`. + /// + /// ## Endpoint docs + /// https://auth0.com/docs/api/authentication#login + /// + /// ## Notes + /// + /// * [audience] relates to the API Identifier you want to reference in your access tokens (see [API settings](https://auth0.com/docs/get-started/apis/api-settings)) + /// * [scopes] defaults to `openid profile email` + /// * [parameters] can be used to sent through custom parameters to the endpoint to be picked up in a Rule or Action. + /// + /// ## Usage example + /// + /// ```dart + /// final result = await auth0.api.login({ + /// usernameOrEmail: 'my@email.com', + /// password: 'my_password' + /// connectionOrRealm: 'Username-Password-Authentication' + /// }); + /// ``` Future login({ required final String usernameOrEmail, required final String password, @@ -24,6 +68,22 @@ class AuthenticationApi { parameters: parameters, ))); + /// Fetches the user's profile from the /userinfo endpoint. An [accessToken] from a successful authentication call must be supplied. + /// + /// ## Endpoint + /// https://auth0.com/docs/api/authentication#user-profile + /// + /// ## Usage example + /// + /// ```dart + /// final result = await auth0.api.login({ + /// usernameOrEmail: 'my@email.com', + /// password: 'my_password' + /// connectionOrRealm: 'Username-Password-Authentication' + /// }); + /// + /// final profile = await auth0.api.userProfile({ accessToken: result.accessToken }); + /// ``` Future userProfile( {required final String accessToken, final Map parameters = const {}}) => @@ -31,6 +91,14 @@ class AuthenticationApi { AuthUserInfoOptions( accessToken: accessToken, parameters: parameters))); + /// Registers a new user with the specified [email] address and [password] in the specified [connection]. + /// + /// Endpoint + /// https://auth0.com/docs/api/authentication#signup + /// + /// ## Notes + /// + /// * [username] is only required if the [connection] you specify requires it Future signup( {required final String email, required final String password, @@ -47,6 +115,32 @@ class AuthenticationApi { userMetadata: userMetadata, parameters: parameters))); + /// Uses a [refreshToken] to get a new access token. + /// + /// ## Endpoint + /// https://auth0.com/docs/api/authentication#refresh-token + /// + /// ## Notes + /// * Refresh tokens can be retrieved by specifying the `offline_access` scope during authentication. + /// * [scopes] can be specified if a reduced set of scopes is desired. + /// + /// ## Further reading + /// [Refresh Tokens on Auth0 docs](https://auth0.com/docs/secure/tokens/refresh-tokens) + /// + /// ## Usage example + /// + /// ```dart + /// final result = await auth0.api.login({ + /// usernameOrEmail: 'my@email.com', + /// password: 'my_password' + /// connectionOrRealm: 'Username-Password-Authentication', + /// scopes: {'openid', 'profile', 'email', 'offline_access'} + /// }); + /// + /// if (result.refreshToken != null) { + /// await auth0.api.renewCredentials(refreshToken: result.refreshToken!); + /// } + /// ``` Future renewCredentials({ required final String refreshToken, final Set scopes = const {}, @@ -58,6 +152,18 @@ class AuthenticationApi { scopes: scopes, parameters: parameters))); + /// Initiates a reset of password of the user with the specific [email] address in the specific [connection]. + /// + /// ## Endpoint + /// https://auth0.com/docs/api/authentication#change-password + /// + /// ## Notes + /// + /// Calling this endpoint does not reset the user's password in itself, but it asks Auth0 to send the user + /// an email with a link they can use to reset their password on the web. + /// + /// Arbitrary [parameters] can be specified and then picked up in a custom Auth0 [Action](https://auth0.com/docs/customize/actions) or + /// [Rule](https://auth0.com/docs/customize/rules). Future resetPassword( {required final String email, required final String connection, diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index 3a33fb9f..277c6f01 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -1,11 +1,43 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; +/// An interface for authenticating users using the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login). +/// +/// Authentication using Universal Login works by redirecting your user to a login page hosted on Auth0's servers. To achieve this on a native device, +/// this class uses the [Auth0.Android](https://github.com/auth0/Auth0.Android) and [Auth0.Swift](https://github.com/auth0/Auth0.swift) SDKs on Android and iOS respectively to +/// perform interactions with Universal Login. +/// +/// It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as [Auth0.webAuthentication]. +/// +/// Usage example: +/// +/// ```dart +/// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); +/// final result = await auth0.webAuthentication.login(); +/// final accessToken = result.accessToken; +/// ``` class WebAuthentication { final Account _account; final UserAgent _userAgent; WebAuthentication(this._account, this._userAgent); + /// Redirects the user to the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login) for authentication. If successful, it returns + /// a set of tokens, as well as the user's profile (constructed from ID token claims). + /// + /// If [redirectUrl] is not specified, a default URL is used that incorporates the `domain` value specified to [Auth0.new], and [scheme] on Android, or the + /// bundle identifier in iOS. [redirectUrl] must appear in your **Allowed Callback URLs** list for the Auth0 app. [Read more about redirecting users](https://auth0.com/docs/authenticate/login/redirect-users-after-login). + /// + /// How the ID token is validated can be configured using [idTokenValidationConfig], but in general the defaults for this are adequate. + /// + /// Additonal notes: + /// + /// * (iOS only): [useEphemeralSession] controls whether shared persistent storage is used for cookies. [Read more on the effects this setting has](https://github.com/auth0/Auth0.swift/blob/master/FAQ.md#1-how-can-i-disable-the-login-alert-box) + /// * (Android only): specify [scheme] if you're using a custom URL scheme for your app. This value must match the value used to configure the `auth0Scheme` manifest placeholder, for the Redirect intent filter to work + /// * [audience] relates to the API Identifier you want to reference in your access tokens (see [API settings](https://auth0.com/docs/get-started/apis/api-settings)) + /// * [scopes] defaults to `openid profile email`. You can override these scopes, but `openid` is always requested regardless of this setting. + /// * Arbitrary [parameters] can be specified and then picked up in a custom Auth0 [Action](https://auth0.com/docs/customize/actions) or [Rule](https://auth0.com/docs/customize/rules). + /// * If you want to log into a specific organization, provide the [organizationId]. Provide [invitationUrl] if a user has been invited to + /// join an organization. Future login({ final String? audience, final Set scopes = const {}, @@ -30,6 +62,13 @@ class WebAuthentication { scheme: scheme, useEphemeralSession: useEphemeralSession))); + /// Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application + /// once logout is complete. + /// + /// If [returnTo] is not specified, a default URL is used that incorporates the `domain` value specified to [Auth0.new], and [scheme] on Android, or the + /// bundle identifier in iOS. [returnTo] must appear in your **Allowed Logout URLs** list for the Auth0 app. [Read more about redirecting users after logout](https://auth0.com/docs/authenticate/login/logout#redirect-users-after-logout). + /// + /// (Android only): [scheme] must match the scheme that was used to configure the `auth0Scheme` manifest placeholder Future logout({final String? returnTo, final String? scheme}) => Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest( WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme), diff --git a/auth0_flutter_platform_interface/lib/src/credentials.dart b/auth0_flutter_platform_interface/lib/src/credentials.dart index 7b908985..1813cb12 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials.dart @@ -1,11 +1,42 @@ import '../auth0_flutter_platform_interface.dart'; +/// A collection of authentication artifacts obtained from Auth0 when a user logs in. class Credentials { + /// A [JSON Web Token](https://jwt.io/introduction) that contains the user information. + /// + /// **Important**: The [ID tokens](https://auth0.com/docs/security/tokens/id-tokens) obtained from Web Auth login are automatically validated by the underlying native SDK, ensuring their + /// contents have not been tampered with. + /// + /// **This is not the case for the ID tokens obtained when using the authentication API directly.** + /// + /// You must [validate ID tokens](https://auth0.com/docs/security/tokens/id-tokens/validate-id-tokens) received from the Authentication API client before using the information they contain. final String idToken; + + /// Token that can be used to make authenticated requests to the specified API (the **audience** value used on login). + /// + /// ## Futher reading + /// - [Access tokens](https://auth0.com/docs/security/tokens/access-tokens) + /// - [Audience](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience) final String accessToken; + + /// Token that can be used to request a new access token. + /// + /// The scope `offline_access` must have been requested on login for a refresh token to be returned. + /// + /// [Read more about refresh tokens](https://auth0.com/docs/secure/tokens/refresh-tokens). final String? refreshToken; + + /// The absolute date and time of when the access token expires. final DateTime expiresAt; + + /// The scopes that have been granted by Auth0. + /// + /// [Read more about scopes](https://auth0.com/docs/get-started/apis/scopes). final Set scopes; + + /// Properties and attributes relating to the authenticated user. + /// + /// [Read more about Auth0 User Profiles](https://auth0.com/docs/manage-users/user-accounts/user-profiles) final UserProfile userProfile; Credentials({ diff --git a/auth0_flutter_platform_interface/lib/src/user_profile.dart b/auth0_flutter_platform_interface/lib/src/user_profile.dart index 6cd8c486..7641b245 100644 --- a/auth0_flutter_platform_interface/lib/src/user_profile.dart +++ b/auth0_flutter_platform_interface/lib/src/user_profile.dart @@ -1,24 +1,104 @@ +/// A collection of properties that represents the authenticated user, extracted from ID token claims. class UserProfile { + /// The Auth0 user identifier. final String sub; + + /// The nickname of the user. + /// + /// Requires the `profile` scope. final String? nickname; + + /// The email of the user. + /// + /// Requires the `email` scope. final String? email; + + /// The last name of the user. + /// + /// Requires the `profile` scope. final String? familyName; + + /// The first name of the user. + /// + /// Requires the `profile` scope. final String? givenName; + + /// The date and time the user's information was last updated. + /// + /// Requires the `profile` scope. final DateTime? updatedAt; + + /// If the user's email is verified. + /// + /// Requires the `email` scope. final bool? isEmailVerified; + + /// The name of the user. + /// + /// Requires the `profile` scope. final String? name; + + /// The URL of the user's profile page. + /// + /// Requires the `profile` scope. final Uri? profileURL; + + /// The URL of the user's picture. + /// + /// Requires the `profile` scope. final Uri? pictureURL; + + /// The URL of the user's website. + /// + /// Requires the `profile` scope. final Uri? websiteURL; + + /// The middle name of the user. + /// + /// Requires the `profile` scope. final String? middleName; + + /// The preferred username of the user. + /// + /// Requires the `profile` scope. final String? preferredUsername; + + /// The gender of the user. + /// + /// Requires the `profile` scope. final String? gender; + + /// The birthdate of the user. + /// + /// Requires the `profile` scope. final String? birthdate; + + /// The time zone of the user. + /// + /// Requires the `profile` scope. final String? zoneinfo; + + /// The locale of the user. + /// + /// Requires the `profile` scope. final String? locale; + + /// The phone number of the user. + /// + /// Requires the `phone` scope. final String? phoneNumber; + + /// If the user's phone number is verified. + /// + /// Requires the `phone` scope. final bool? isPhoneNumberVerified; + + /// The address of the user. + /// + /// Requires the `address` scope. final Map? address; + + /// Any custom claims final Map? customClaims; const UserProfile({ @@ -53,9 +133,15 @@ class UserProfile { middleName: result['middle_name'] as String?, nickname: result['nickname'] as String?, preferredUsername: result['preferred_username'] as String?, - profileURL: result['profile'] != null ? Uri.parse(result['profile'] as String) : null, - pictureURL: result['picture'] != null ? Uri.parse(result['picture'] as String) : null, - websiteURL: result['website'] != null ? Uri.parse(result['website'] as String) : null, + profileURL: result['profile'] != null + ? Uri.parse(result['profile'] as String) + : null, + pictureURL: result['picture'] != null + ? Uri.parse(result['picture'] as String) + : null, + websiteURL: result['website'] != null + ? Uri.parse(result['website'] as String) + : null, email: result['email'] as String?, isEmailVerified: result['email_verified'] as bool?, gender: result['gender'] as String?, diff --git a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart index a4eced59..9c244f71 100644 --- a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart +++ b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart @@ -1,6 +1,12 @@ +/// Configuration settings for ID token validation. class IdTokenValidationConfig { + /// The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms. final int? leeway; + + /// The issuer to be used for validation of JWTs. Defaults to the domain used to when calling [Auth0.new]. final String? issuer; + + /// Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0. final int? maxAge; const IdTokenValidationConfig({this.leeway, this.issuer, this.maxAge}); From c5cc0c830cf9c03ea960a72316f636ec71cedbce Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 30 Jun 2022 09:11:41 -0300 Subject: [PATCH 04/38] Rename `userProfile` to `user` (#105) --- auth0_flutter_platform_interface/lib/src/credentials.dart | 6 +++--- .../test/method_channel_auth0_flutter_auth_test.dart | 4 ++-- .../test/method_channel_auth0_flutter_web_auth_test.dart | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/auth0_flutter_platform_interface/lib/src/credentials.dart b/auth0_flutter_platform_interface/lib/src/credentials.dart index 1813cb12..f90acc96 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials.dart @@ -37,7 +37,7 @@ class Credentials { /// Properties and attributes relating to the authenticated user. /// /// [Read more about Auth0 User Profiles](https://auth0.com/docs/manage-users/user-accounts/user-profiles) - final UserProfile userProfile; + final UserProfile user; Credentials({ required this.idToken, @@ -45,7 +45,7 @@ class Credentials { this.refreshToken, required this.expiresAt, this.scopes = const {}, - required this.userProfile, + required this.user, }); factory Credentials.fromMap(final Map result) => @@ -55,7 +55,7 @@ class Credentials { refreshToken: result['refreshToken'] as String?, expiresAt: DateTime.parse(result['expiresAt'] as String), scopes: Set.from(result['scopes'] as List), - userProfile: UserProfile.fromMap(Map.from( + user: UserProfile.fromMap(Map.from( result['userProfile'] as Map)), ); } diff --git a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart index edd34c05..572558de 100644 --- a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart @@ -335,7 +335,7 @@ void main() { expect(result.scopes, MethodCallHandler.loginResult['scopes']); expect( result.refreshToken, MethodCallHandler.loginResult['refreshToken']); - expect(result.userProfile.name, + expect(result.user.name, MethodCallHandler.loginResult['userProfile']['name']); }); @@ -558,7 +558,7 @@ void main() { result.expiresAt, DateTime.parse( MethodCallHandler.renewResult['expiresAt'] as String)); - expect(result.userProfile.name, + expect(result.user.name, MethodCallHandler.renewResult['userProfile']['name']); }); diff --git a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart index 382ca199..66d013c7 100644 --- a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart @@ -148,7 +148,7 @@ void main() { expect(result.scopes, MethodCallHandler.loginResult['scopes']); expect( result.refreshToken, MethodCallHandler.loginResult['refreshToken']); - expect(result.userProfile.name, + expect(result.user.name, MethodCallHandler.loginResult['userProfile']['name']); }); From 9128f9cb4790da411b6570701cfc1594601a7d74 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Thu, 30 Jun 2022 22:36:18 +0200 Subject: [PATCH 05/38] [SDK-3440] Credentials Manager (#99) * Add initial version of the Android Credential Manager * Clean up * Clean up CredentialManagaer RequestHandlers * Update options for Credential Manager * Fix broken tests * Update Request type * Add unit tests for the dart code * Add kotlin tests for CredentialManager * Rename credential manager methods * Avoid using ApiException in CredentialsManager * Add CredentialsManager to WebAuth * Login type from all requests that return credentials * Fix tests * Update tests * Fix example app * Opt out of Credentials Manager in Example App to fix SmokeTests * Revert using Singleton for Auth0 API and CredentialsManager * Add Dummy Swift implementation * Fix compilation error * Try fix compilation error * Change error message when unable to call getCredentials * Use IllegalArgumentException like we do already * Rename type to tokenType * Return tokenType from swift method channel * Fix compile issue * Fix dart tests * Fix kotlin tests * Update incorrect MARTK in CredentialsManagerHandler * Add API documentation comments * Address review comments * Fix analyze issue * Apply suggestions from code review Co-authored-by: Steve Hobbs Co-authored-by: Rita Zerrizuela * Use SecureCredentialsManager instead of CredentialsManager * fix build * Fx android tests * Opt out of credentialsManager in example app * Move credentialsManager() inside WebAuthentication * Add LocalAuthenticationOptions * Address review comments * opt out of credentials manager in example app * Fix android tests * Address review comments * fix tests Co-authored-by: Steve Hobbs Co-authored-by: Rita Zerrizuela --- .../auth0/auth0_flutter/Auth0FlutterPlugin.kt | 13 + .../CredentialsManagerMethodCallHandler.kt | 40 ++ .../api/LoginApiRequestHandler.kt | 3 +- .../api/RenewApiRequestHandler.kt | 3 +- .../ClearCredentialsRequestHandler.kt | 20 + .../CredentialsManagerRequestHandler.kt | 12 + .../GetCredentialsRequestHandler.kt | 64 +++ .../HasValidCredentialsRequestHandler.kt | 23 + .../SaveCredentialsRequestHandler.kt | 47 ++ .../web_auth/LoginWebAuthRequestHandler.kt | 3 +- .../utils/assertHasProperties.kt | 6 +- ...CredentialsManagerMethodCallHandlerTest.kt | 85 ++++ .../ClearCredentialsRequestHandlerTest.kt | 67 +++ .../GetCredentialsRequestHandlerTest.kt | 383 ++++++++++++++ .../HasValidCredentialsRequestHandlerTest.kt | 85 ++++ .../SaveCredentialsRequestHandlerTest.kt | 262 ++++++++++ auth0_flutter/example/lib/example_app.dart | 6 +- ...CredentialsManagerClearMethodHandler.swift | 10 + .../CredentialsManagerHandler.swift | 49 ++ auth0_flutter/ios/Classes/Enums.swift | 1 + auth0_flutter/ios/Classes/Extensions.swift | 3 +- .../ios/Classes/SwiftAuth0FlutterPlugin.swift | 2 +- auth0_flutter/lib/auth0_flutter.dart | 50 +- .../lib/src/credentials_manager.dart | 82 +++ auth0_flutter/lib/src/web_authentication.dart | 65 ++- .../test/authentication_api_test.dart | 6 +- .../test/authentication_api_test.mocks.dart | 49 +- .../test/credentials_manager_test.dart | 164 ++++++ .../test/credentials_manager_test.mocks.dart | 56 ++ .../test/web_authentication_test.dart | 306 +++++++++-- .../test/web_authentication_test.mocks.dart | 74 ++- .../lib/auth0_flutter_platform_interface.dart | 7 + .../lib/src/auth/api_exception.dart | 5 +- .../credentials_manager_exception.dart | 23 + .../credentials_manager_platform.dart | 54 ++ .../method_channel_credentials_manager.dart | 99 ++++ .../options/get_credentials_options.dart | 23 + .../has_valid_credentials_options.dart | 12 + .../options/local_authentication_options.dart | 6 + .../options/save_credentials_options.dart | 13 + .../lib/src/credentials.dart | 12 + .../lib/src/request/request.dart | 36 +- .../credential_manager_exception_test.dart | 21 + ...ethod_channel_auth0_flutter_auth_test.dart | 6 +- ...d_channel_auth0_flutter_web_auth_test.dart | 9 +- ...thod_channel_credentials_manager_test.dart | 479 ++++++++++++++++++ ...hannel_credentials_manager_test.mocks.dart | 26 + 47 files changed, 2736 insertions(+), 134 deletions(-) create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/CredentialsManagerRequestHandler.kt create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift create mode 100644 auth0_flutter/lib/src/credentials_manager.dart create mode 100644 auth0_flutter/test/credentials_manager_test.dart create mode 100644 auth0_flutter/test/credentials_manager_test.mocks.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_exception.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/options/get_credentials_options.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/options/has_valid_credentials_options.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart create mode 100644 auth0_flutter_platform_interface/lib/src/credentials-manager/options/save_credentials_options.dart create mode 100644 auth0_flutter_platform_interface/test/credential_manager_exception_test.dart create mode 100644 auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart create mode 100644 auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.mocks.dart diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt index 7b2e5bb0..a45ca096 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt @@ -4,6 +4,7 @@ import androidx.annotation.NonNull import com.auth0.android.provider.WebAuthProvider import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import com.auth0.auth0_flutter.request_handlers.api.* +import com.auth0.auth0_flutter.request_handlers.credentials_manager.* import com.auth0.auth0_flutter.request_handlers.web_auth.LoginWebAuthRequestHandler import com.auth0.auth0_flutter.request_handlers.web_auth.LogoutWebAuthRequestHandler import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -22,6 +23,7 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { /// when the Flutter Engine is detached from the Activity private lateinit var webAuthMethodChannel : MethodChannel private lateinit var authMethodChannel : MethodChannel + private lateinit var credentialsManagerMethodChannel : MethodChannel private val webAuthCallHandler = Auth0FlutterWebAuthMethodCallHandler(listOf( LoginWebAuthRequestHandler { request: MethodCallRequest -> WebAuthProvider.login(request.account) }, LogoutWebAuthRequestHandler { request: MethodCallRequest -> WebAuthProvider.logout(request.account) }, @@ -33,6 +35,12 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { RenewApiRequestHandler(), ResetPasswordApiRequestHandler() )) + private val credentialsManagerCallHandler = CredentialsManagerMethodCallHandler(listOf( + GetCredentialsRequestHandler(), + SaveCredentialsRequestHandler(), + HasValidCredentialsRequestHandler(), + ClearCredentialsRequestHandler() + )) override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { webAuthMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "auth0.com/auth0_flutter/web_auth") @@ -40,6 +48,9 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { authMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "auth0.com/auth0_flutter/auth") authMethodChannel.setMethodCallHandler(authCallHandler) + + credentialsManagerMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "auth0.com/auth0_flutter/credentials_manager") + credentialsManagerMethodChannel.setMethodCallHandler(credentialsManagerCallHandler) } override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {} @@ -47,11 +58,13 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { webAuthMethodChannel.setMethodCallHandler(null) authMethodChannel.setMethodCallHandler(null) + credentialsManagerMethodChannel.setMethodCallHandler(null) } override fun onAttachedToActivity(binding: ActivityPluginBinding) { webAuthCallHandler.context = binding.activity authCallHandler.context = binding.activity + credentialsManagerCallHandler.context = binding.activity } override fun onDetachedFromActivityForConfigChanges() { diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt new file mode 100644 index 00000000..d61c2c33 --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt @@ -0,0 +1,40 @@ +package com.auth0.auth0_flutter + +import android.app.Activity +import android.content.Context +import androidx.annotation.NonNull +import com.auth0.android.authentication.AuthenticationAPIClient +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.android.authentication.storage.SharedPreferencesStorage +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import com.auth0.auth0_flutter.request_handlers.credentials_manager.CredentialsManagerRequestHandler +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result + +class CredentialsManagerMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { + lateinit var context: Context + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + var requestHandler = requestHandlers.find { it.method == call.method }; + + if (requestHandler != null) { + val request = MethodCallRequest.fromCall(call); + + val api = AuthenticationAPIClient(request.account); + val storage = SharedPreferencesStorage(context); + val credentialsManager = SecureCredentialsManager(context, api, storage); + + var localAuthentication = request.data.get("localAuthentication") as Map?; + + if (localAuthentication != null) { + val title = localAuthentication["title"] as String?; + val description = localAuthentication["description"] as String?; + // credentialsManager.requireAuthentication(context as Activity, 111, title, description); + } + requestHandler.handle(credentialsManager, context, request, result); + } else { + result.notImplemented() + } + } +} diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt index 67cc8e08..ae510287 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt @@ -73,7 +73,8 @@ class LoginApiRequestHandler : ApiRequestHandler { "refreshToken" to credentials.refreshToken, "userProfile" to userProfile.toMap(), "expiresAt" to formattedDate, - "scopes" to scope + "scopes" to scope, + "type" to credentials.type ) ) } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt index 358e7e21..571c6ce1 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt @@ -62,7 +62,8 @@ class RenewApiRequestHandler : ApiRequestHandler { "refreshToken" to credentials.refreshToken, "userProfile" to userProfile.toMap(), "expiresAt" to formattedDate, - "scopes" to scope + "scopes" to scope, + "type" to credentials.type ) ) } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt new file mode 100644 index 00000000..1b7c97b5 --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt @@ -0,0 +1,20 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel + +class ClearCredentialsRequestHandler : CredentialsManagerRequestHandler { + override val method: String = "credentialsManager#clearCredentials"; + + override fun handle( + credentialsManager: SecureCredentialsManager, + context: Context, + request: MethodCallRequest, + result: MethodChannel.Result + ) { + credentialsManager.clearCredentials(); + result.success(true); + } +} diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/CredentialsManagerRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/CredentialsManagerRequestHandler.kt new file mode 100644 index 00000000..dcdc2f1e --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/CredentialsManagerRequestHandler.kt @@ -0,0 +1,12 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel + +interface CredentialsManagerRequestHandler { + val method: String + fun handle(credentialsManager: SecureCredentialsManager, context: Context, request: MethodCallRequest, result: MethodChannel.Result) +} + diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt new file mode 100644 index 00000000..5d75436d --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt @@ -0,0 +1,64 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.CredentialsManagerException +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.android.callback.Callback +import com.auth0.android.jwt.JWT +import com.auth0.android.result.Credentials +import com.auth0.auth0_flutter.createUserProfileFromClaims +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import com.auth0.auth0_flutter.toMap +import io.flutter.plugin.common.MethodChannel +import java.text.SimpleDateFormat +import java.util.* + +class GetCredentialsRequestHandler : CredentialsManagerRequestHandler { + override val method: String = "credentialsManager#getCredentials"; + + override fun handle( + credentialsManager: SecureCredentialsManager, + context: Context, + request: MethodCallRequest, + result: MethodChannel.Result + ) { + var scope: String? = null; + + val scopes = request.data.getOrDefault("scopes", arrayListOf()) as ArrayList<*> + if (scopes.isNotEmpty()) { + scope = scopes.joinToString(separator = " "); + } + + var minTtl = request.data.get("minTtl") as Int? ?: 0; + var parameters = request.data.get("parameters") as Map? ?: mapOf(); + + credentialsManager.getCredentials(scope, minTtl, parameters, object: + Callback { + override fun onFailure(exception: CredentialsManagerException) { + result.error(exception.message ?: "UNKNOWN ERROR", exception.message, exception); + } + + override fun onSuccess(credentials: Credentials) { + val scopes = credentials.scope?.split(" ") ?: listOf() + val jwt = JWT(credentials.idToken) + val userProfile = createUserProfileFromClaims(jwt.claims) + val sdf = + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()) + + val formattedDate = sdf.format(credentials.expiresAt) + + result.success( + mapOf( + "accessToken" to credentials.accessToken, + "idToken" to credentials.idToken, + "refreshToken" to credentials.refreshToken, + "userProfile" to userProfile.toMap(), + "expiresAt" to formattedDate, + "scopes" to scopes, + "tokenType" to credentials.type + ) + ) + } + }); + } +} diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt new file mode 100644 index 00000000..2204236f --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt @@ -0,0 +1,23 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel +import java.util.ArrayList + +class HasValidCredentialsRequestHandler : CredentialsManagerRequestHandler { + override val method: String = "credentialsManager#hasValidCredentials"; + + override fun handle( + credentialsManager: SecureCredentialsManager, + context: Context, + request: MethodCallRequest, + result: MethodChannel.Result + ) { + var minTtl = request.data.get("minTtl") as Long? ?: 0; + + result.success(credentialsManager.hasValidCredentials(minTtl)); + } + +} diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt new file mode 100644 index 00000000..ffd3c57b --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt @@ -0,0 +1,47 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.android.result.Credentials +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import com.auth0.auth0_flutter.utils.assertHasProperties +import io.flutter.plugin.common.MethodChannel +import java.text.SimpleDateFormat +import java.util.* + + +class SaveCredentialsRequestHandler : CredentialsManagerRequestHandler { + override val method: String = "credentialsManager#saveCredentials"; + + override fun handle( + credentialsManager: SecureCredentialsManager, + context: Context, + request: MethodCallRequest, + result: MethodChannel.Result + ) { + assertHasProperties(listOf("credentials"), request.data); + + val credentials = request.data.get("credentials") as HashMap<*, *>; + + assertHasProperties(listOf("accessToken", "idToken" , "tokenType", "expiresAt"), credentials, "credentials"); + + var scope: String? = null; + val scopes = credentials.getOrDefault("scopes", arrayListOf()) as ArrayList<*> + if (scopes.isNotEmpty()) { + scope = scopes.joinToString(separator = " "); + } + + val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()); + var date = format.parse(credentials.get("expiresAt") as String); + + credentialsManager.saveCredentials(Credentials( + credentials.get("idToken") as String, + credentials.get("accessToken") as String, + credentials.get("tokenType") as String, + credentials.get("refreshToken") as String?, + date, + scope, + )); + result.success(true); + } +} diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt index 2c93f50e..51588191 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt @@ -89,7 +89,8 @@ class LoginWebAuthRequestHandler(private val builderResolver: (MethodCallRequest "refreshToken" to credentials.refreshToken, "userProfile" to userProfile.toMap(), "expiresAt" to formattedDate, - "scopes" to scopes + "scopes" to scopes, + "tokenType" to credentials.type ) ) } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt index 8eee6000..b76790ad 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt @@ -8,12 +8,14 @@ fun tryGetByKey(data: Any?, key: String): Any? { return null; } -fun assertHasProperties(requiredProperties: List, data: Map<*, *>) { +fun assertHasProperties(requiredProperties: List, data: Map<*, *>, prefix: String? = null) { var missingProperties = requiredProperties.filter { it.split('.') .fold(data) { acc: Any?, key: String -> tryGetByKey(acc, key) } == null }; - missingProperties.forEach { throw IllegalArgumentException("Required property '$it' is not provided.") } + missingProperties + .map { if (prefix != null) "$prefix.$it" else it } + .forEach { throw IllegalArgumentException("Required property '$it' is not provided.") } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt new file mode 100644 index 00000000..89e8bf40 --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt @@ -0,0 +1,85 @@ +package com.auth0.auth0_flutter + +import android.content.Context +import android.content.SharedPreferences +import com.auth0.auth0_flutter.request_handlers.api.ApiRequestHandler +import com.auth0.auth0_flutter.request_handlers.api.LoginApiRequestHandler +import com.auth0.auth0_flutter.request_handlers.api.SignupApiRequestHandler +import com.auth0.auth0_flutter.request_handlers.credentials_manager.ClearCredentialsRequestHandler +import com.auth0.auth0_flutter.request_handlers.credentials_manager.CredentialsManagerRequestHandler +import com.auth0.auth0_flutter.request_handlers.credentials_manager.HasValidCredentialsRequestHandler +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel.Result +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.`when` +import org.mockito.kotlin.* +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class CredentialsManagerMethodCallHandlerTest { + private val defaultArguments = hashMapOf( + "_account" to mapOf( + "domain" to "test.auth0.com", + "clientId" to "test-client", + ), + "_userAgent" to mapOf( + "name" to "auth0-flutter", + "version" to "1.0.0" + ) + ) + + private fun runCallHandler( + method: String, + arguments: HashMap = defaultArguments, + requestHandlers: List, + context: Context? = null, + onResult: (Result) -> Unit, + ) { + val handler = CredentialsManagerMethodCallHandler(requestHandlers) + val mockResult = mock() + + handler.context = if (context === null) mock() else context; + + handler.onMethodCall(MethodCall(method, arguments), mockResult) + onResult(mockResult) + } + + @Test + fun `handler should result in 'notImplemented' if no handlers`() { + runCallHandler("credentialsManager#clearCredentials", requestHandlers = listOf()) { result -> + verify(result).notImplemented() + } + } + + @Test + fun `handler should result in 'notImplemented' if no matching handler`() { + val clearCredentialsHandler = mock(); + + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + + runCallHandler("credentialsManager#saveCredentials", requestHandlers = listOf(clearCredentialsHandler)) { result -> + verify(result).notImplemented() + } + } + + @Test + fun `handler should only run the correct handler`() { + val clearCredentialsHandler = mock(); + val hasValidCredentialsHandler = mock(); + + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + `when`(hasValidCredentialsHandler.method).thenReturn("credentialsManager#hasValidCredentials"); + + val context: Context = mock(); + val mockPrefs: SharedPreferences = mock() + + `when`(context.getSharedPreferences(any(), any())) + .thenReturn(mockPrefs); + + runCallHandler(clearCredentialsHandler.method, context = context, requestHandlers = listOf(clearCredentialsHandler, hasValidCredentialsHandler)) { _ -> + verify(clearCredentialsHandler).handle(any(), eq(context), any(), any()) + verify(hasValidCredentialsHandler, times(0)).handle(any(), eq(context), any(), any()) + } + } +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt new file mode 100644 index 00000000..f9129c61 --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt @@ -0,0 +1,67 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import com.auth0.android.Auth0 +import com.auth0.android.authentication.AuthenticationAPIClient +import com.auth0.android.authentication.AuthenticationException +import com.auth0.android.authentication.storage.SecureCredentialsManager; +import com.auth0.android.callback.Callback +import com.auth0.android.request.AuthenticationRequest +import com.auth0.android.result.Credentials +import com.auth0.auth0_flutter.JwtTestUtils + +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel.Result +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.* +import org.mockito.stubbing.Answer +import org.robolectric.RobolectricTestRunner +import java.text.SimpleDateFormat +import java.util.* + +@RunWith(RobolectricTestRunner::class) +class ClearCredentialsRequestHandlerTest { + + @Test + fun `should call clearCredentials with the correct parameters`() { + val handler = ClearCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, mock()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).clearCredentials(); + } + + @Test + fun `should call result success on success`() { + val handler = ClearCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, mock()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + val captor = argumentCaptor() + verify(mockResult).success(captor.capture()) + + assert(captor.firstValue) + + } +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt new file mode 100644 index 00000000..16b03620 --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt @@ -0,0 +1,383 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import com.auth0.android.Auth0 +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.android.authentication.storage.CredentialsManagerException +import com.auth0.android.callback.Callback +import com.auth0.android.result.Credentials +import com.auth0.auth0_flutter.JwtTestUtils +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel.Result +import org.hamcrest.CoreMatchers +import org.hamcrest.MatcherAssert +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyMap +import org.mockito.Mockito.`when` +import org.mockito.kotlin.* +import org.robolectric.RobolectricTestRunner +import java.text.SimpleDateFormat +import java.util.* + +@RunWith(RobolectricTestRunner::class) +class GetCredentialsRequestHandlerTest { + + @Test + fun `should call getCredentials without providing options`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf() + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + isNull(), + eq(0), + anyMap(), + any() + ); + } + + @Test + fun `should use default value for minTtl and parameters when only providing scope`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "scopes" to arrayListOf("test-scope1", "test-scope2"), + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + eq("test-scope1 test-scope2"), + eq(0), + anyMap(), + any() + ); + } + + @Test + fun `should use default value for parameters when only providing minTtl`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "minTtl" to 30, + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + isNull(), + eq(30), + anyMap(), + any() + ); + } + + @Test + fun `should use default value for minTtl when only providing parameters`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "parameters" to mapOf("test" to "test-value", "test2" to "test-value") + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + isNull(), + eq(0), + eq(mapOf("test" to "test-value", "test2" to "test-value")), + any() + ); + } + + @Test + fun `should use default value for parameters when providing scope and minTtl`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "minTtl" to 30, + "scopes" to arrayListOf("test-scope1", "test-scope2"), + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + eq("test-scope1 test-scope2"), + eq(30), + anyMap(), + any() + ); + } + + @Test + fun `should use default value for minTtl when only providing scope and parameters`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "scopes" to arrayListOf("test-scope1", "test-scope2"), + "parameters" to mapOf("test" to "test-value", "test2" to "test-value") + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + eq("test-scope1 test-scope2"), + eq(0), + eq(mapOf("test" to "test-value", "test2" to "test-value")), + any() + ); + } + + @Test + fun `should call getCredentials when providing minTtl and parameters`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "minTtl" to 30, + "parameters" to mapOf("test" to "test-value", "test2" to "test-value") + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + isNull(), + eq(30), + eq(mapOf("test" to "test-value", "test2" to "test-value")), + any() + ); + } + + @Test + fun `should call getCredentials when providing all options`() { + val handler = GetCredentialsRequestHandler(); + var options = hashMapOf( + "minTtl" to 30, + "scopes" to arrayListOf("test-scope1", "test-scope2"), + "parameters" to mapOf("test" to "test-value", "test2" to "test-value") + ) + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).getCredentials( + eq("test-scope1 test-scope2"), + eq(30), + eq(mapOf("test" to "test-value", "test2" to "test-value")), + any() + ); + } + + @Test + fun `should call result error on failure`() { + val options = hashMapOf(); + val handler = GetCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = mock(); + + `when`(exception.message).thenReturn("test-message") + + doAnswer { + val ob = it.getArgument>(3); + ob.onFailure(exception); + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockResult).error(eq("test-message"), eq("test-message"), any()); + } + + @Test + fun `should fallback to UNKNOWN ERROR on failure without a message`() { + val options = hashMapOf(); + val handler = GetCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = mock(); + + `when`(exception.message).thenReturn(null) + + doAnswer { + val ob = it.getArgument>(3); + ob.onFailure(exception); + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockResult).error(eq("UNKNOWN ERROR"), isNull(), any()); + } + + @Test + fun `should call result success on success`() { + val options = hashMapOf(); + val handler = GetCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + val credentials = Credentials(idToken, "test", "", null, Date(), "scope1 scope2") + + doAnswer { + val ob = it.getArgument>(3); + ob.onSuccess(credentials); + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + val captor = argumentCaptor<() -> Map>() + verify(mockResult).success(captor.capture()) + + val sdf = + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()) + + val formattedDate = sdf.format(credentials.expiresAt) + + MatcherAssert.assertThat( + (captor.firstValue as Map)["accessToken"], + CoreMatchers.equalTo(credentials.accessToken) + ) + MatcherAssert.assertThat( + (captor.firstValue as Map)["idToken"], + CoreMatchers.equalTo(credentials.idToken) + ) + MatcherAssert.assertThat( + (captor.firstValue as Map)["refreshToken"], + CoreMatchers.equalTo(credentials.refreshToken) + ) + MatcherAssert.assertThat( + (captor.firstValue as Map)["expiresAt"] as String, + CoreMatchers.equalTo(formattedDate) + ) + MatcherAssert.assertThat( + (captor.firstValue as Map)["scopes"], + CoreMatchers.equalTo(listOf("scope1", "scope2")) + ) + MatcherAssert.assertThat( + ((captor.firstValue as Map)["userProfile"] as Map)["name"], + CoreMatchers.equalTo("John Doe") + ) + } + + @Test + fun `should call result success on success without scopes`() { + val options = hashMapOf(); + val handler = GetCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + val credentials = Credentials(idToken, "test", "", null, Date(), scope = null) + + doAnswer { + val ob = it.getArgument>(3); + ob.onSuccess(credentials); + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + val captor = argumentCaptor<() -> Map>(); + + verify(mockResult).success(captor.capture()); + + MatcherAssert.assertThat( + (captor.firstValue as Map)["scopes"], + CoreMatchers.equalTo(listOf()) + ) + } +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt new file mode 100644 index 00000000..1f0c639e --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt @@ -0,0 +1,85 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import com.auth0.android.Auth0 +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel.Result +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.* +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class HasValidCredentialsRequestHandlerTest { + + @Test + fun `should call hasValidCredentials with the correct parameters`() { + val handler = HasValidCredentialsRequestHandler(); + var minTtl: Long = 30; + val options = hashMapOf( + "minTtl" to minTtl, + ); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).hasValidCredentials(minTtl); + } + + @Test + fun `should call hasValidCredentials with minTtl set to the default value`() { + val handler = HasValidCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, mock()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + verify(mockCredentialsManager).hasValidCredentials(0); + } + + @Test + fun `should call result success on success`() { + val handler = HasValidCredentialsRequestHandler(); + var minTtl: Long = 30; + val options = hashMapOf( + "minTtl" to minTtl, + ); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + + doReturn(true).`when`(mockCredentialsManager).hasValidCredentials(any()); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + val captor = argumentCaptor<() -> Map>() + verify(mockResult).success(captor.capture()) + + assertThat(captor.firstValue, equalTo(true)) + + } +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt new file mode 100644 index 00000000..e84a8a0c --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt @@ -0,0 +1,262 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import com.auth0.android.Auth0 +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.android.result.Credentials +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel.Result +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.robolectric.RobolectricTestRunner +import java.text.SimpleDateFormat +import java.util.* + +@RunWith(RobolectricTestRunner::class) +class SaveCredentialsRequestHandlerTest { + + @Test + fun `should throw when missing credentials`() { + val options = + hashMapOf(); + val handler = SaveCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = Assert.assertThrows(IllegalArgumentException::class.java) { + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + } + + assertThat( + exception.message, + equalTo("Required property 'credentials' is not provided.") + ); + } + + @Test + fun `should throw when missing credentials accessToken`() { + val options = + hashMapOf("credentials" to hashMapOf( + "idToken" to "test-id-token", + "tokenType" to "Bearer", + "expiresAt" to "2022-01-01" + )); + val handler = SaveCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = Assert.assertThrows(IllegalArgumentException::class.java) { + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + } + + assertThat( + exception.message, + equalTo("Required property 'credentials.accessToken' is not provided.") + ); + } + + @Test + fun `should throw when missing credentials idToken`() { + val options = + hashMapOf("credentials" to hashMapOf( + "accessToken" to "test-access-token", + "tokenType" to "Bearer", + "expiresAt" to "2022-01-01" + )); + val handler = SaveCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = Assert.assertThrows(IllegalArgumentException::class.java) { + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + } + + assertThat( + exception.message, + equalTo("Required property 'credentials.idToken' is not provided.") + ); + } + + @Test + fun `should throw when missing credentials type`() { + val options = + hashMapOf("credentials" to hashMapOf( + "accessToken" to "test-access-token", + "idToken" to "test-id-token", + "expiresAt" to "2022-01-01" + )); + val handler = SaveCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = Assert.assertThrows(IllegalArgumentException::class.java) { + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + } + + assertThat( + exception.message, + equalTo("Required property 'credentials.tokenType' is not provided.") + ); + } + + @Test + fun `should throw when missing credentials expiresAt`() { + val options = + hashMapOf("credentials" to hashMapOf( + "accessToken" to "test-access-token", + "idToken" to "test-id-token", + "tokenType" to "Bearer", + )); + val handler = SaveCredentialsRequestHandler(); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + val exception = Assert.assertThrows(IllegalArgumentException::class.java) { + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + } + + assertThat( + exception.message, + equalTo("Required property 'credentials.expiresAt' is not provided.") + ); + } + + @Test + fun `should call saveCredentials with the correct parameters`() { + val handler = SaveCredentialsRequestHandler(); + var credentialsMap = hashMapOf( + "accessToken" to "test-access-token", + "idToken" to "test-access-token", + "tokenType" to "Bearer", + "expiresAt" to "2022-01-01T00:00:00.000Z", + "scopes" to arrayListOf("a", "b") + ); + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + var date = format.parse(credentialsMap.get("expiresAt") as String); + var scope: String? = null; + val scopes = credentialsMap.getOrDefault("scopes", arrayListOf()) as ArrayList<*> + if (scopes.isNotEmpty()) { + scope = scopes.joinToString(separator = " "); + } + + + var credentials = Credentials( + credentialsMap.get("idToken") as String, + credentialsMap.get("accessToken") as String, + credentialsMap.get("tokenType") as String, + credentialsMap.get("refreshToken") as String?, + date, + scope, + ) + val options = hashMapOf( + "credentials" to credentialsMap, + ); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + + val captor = argumentCaptor() + verify(mockCredentialsManager).saveCredentials(captor.capture()); + + assertThat((captor.firstValue as Credentials).accessToken, equalTo(credentials.accessToken)) + + } + + @Test + fun `should call saveCredentials with the correct parameters without scopes`() { + val handler = SaveCredentialsRequestHandler(); + var credentialsMap = hashMapOf( + "accessToken" to "test-access-token", + "idToken" to "test-access-token", + "tokenType" to "Bearer", + "expiresAt" to "2022-01-01T00:00:00.000Z" + ); + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + var date = format.parse(credentialsMap.get("expiresAt") as String); + var scope: String? = null; + val scopes = credentialsMap.getOrDefault("scopes", arrayListOf()) as ArrayList<*> + if (scopes.isNotEmpty()) { + scope = scopes.joinToString(separator = " "); + } + + + var credentials = Credentials( + credentialsMap.get("idToken") as String, + credentialsMap.get("accessToken") as String, + credentialsMap.get("tokenType") as String, + credentialsMap.get("refreshToken"), + date, + scope, + ) + val options = hashMapOf( + "credentials" to credentialsMap, + ); + val mockResult = mock(); + val mockAccount = mock(); + var mockCredentialsManager = mock(); + val request = MethodCallRequest(account = mockAccount, options); + + handler.handle( + mockCredentialsManager, + mock(), + request, + mockResult + ); + + + val captor = argumentCaptor() + verify(mockCredentialsManager).saveCredentials(captor.capture()); + + assertThat((captor.firstValue as Credentials).accessToken, equalTo(credentials.accessToken)) + + } +} diff --git a/auth0_flutter/example/lib/example_app.dart b/auth0_flutter/example/lib/example_app.dart index 26b54bcf..835c813d 100644 --- a/auth0_flutter/example/lib/example_app.dart +++ b/auth0_flutter/example/lib/example_app.dart @@ -20,11 +20,13 @@ class _ExampleAppState extends State { String _output = ''; late Auth0 auth0; + late WebAuthentication webAuth; @override void initState() { super.initState(); auth0 = Auth0(dotenv.env['AUTH0_DOMAIN']!, dotenv.env['AUTH0_CLIENT_ID']!); + webAuth = auth0.webAuthentication(useCredentialsManager: false); } Future webAuthLogin() async { @@ -33,7 +35,7 @@ class _ExampleAppState extends State { // Platform messages may fail, so we use a try/catch PlatformException. // We also handle the message potentially returning null. try { - final result = await auth0.webAuthentication + final result = await webAuth .login(scheme: dotenv.env['AUTH0_CUSTOM_SCHEME']); output = result.idToken; @@ -60,7 +62,7 @@ class _ExampleAppState extends State { // Platform messages may fail, so we use a try/catch PlatformException. // We also handle the message potentially returning null. try { - await auth0.webAuthentication + await webAuth .logout(scheme: dotenv.env['AUTH0_CUSTOM_SCHEME']); output = 'Logged out.'; diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift new file mode 100644 index 00000000..45c8dc1b --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift @@ -0,0 +1,10 @@ +import Foundation +import Flutter +import Auth0 + +struct CredentialsManagerClearMethodHandler: MethodHandler { + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + callback(nil) + } +} diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift new file mode 100644 index 00000000..39df93f0 --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift @@ -0,0 +1,49 @@ +import Flutter +import Auth0 + +// MARK: - Providers + +typealias CredentialsManagerMethodHandlerProvider = (_ method: CredentialsManagerHandler.Method) -> MethodHandler + +// MARK: - Credentials Manager Handler + +public class CredentialsManagerHandler: NSObject, FlutterPlugin { + enum Method: String, CaseIterable { + case clear = "credentialsManager#clearCredentials" + } + private static let channelName = "auth0.com/auth0_flutter/credentials_manager" + + public static func register(with registrar: FlutterPluginRegistrar) { + let handler = CredentialsManagerHandler() + let channel = FlutterMethodChannel(name: CredentialsManagerHandler.channelName, + binaryMessenger: registrar.messenger()) + registrar.addMethodCallDelegate(handler, channel: channel) + } + + var methodHandlerProvider: CredentialsManagerMethodHandlerProvider = { method in + switch method { + case .clear: return CredentialsManagerClearMethodHandler() + } + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + guard let arguments = call.arguments as? [String: Any] else { + return result(FlutterError(from: .argumentsMissing)) + } + guard let accountDictionary = arguments[Account.key] as? [String: String], + let account = Account(from: accountDictionary) else { + return result(FlutterError(from: .accountMissing)) + } + guard let userAgentDictionary = arguments[UserAgent.key] as? [String: String], + let userAgent = UserAgent(from: userAgentDictionary) else { + return result(FlutterError(from: .userAgentMissing)) + } + guard let method = Method(rawValue: call.method) else { + return result(FlutterMethodNotImplemented) + } + + let methodHandler = methodHandlerProvider(method) + + methodHandler.handle(with: arguments, callback: result) + } +} diff --git a/auth0_flutter/ios/Classes/Enums.swift b/auth0_flutter/ios/Classes/Enums.swift index 9f2503ee..1d5931ea 100644 --- a/auth0_flutter/ios/Classes/Enums.swift +++ b/auth0_flutter/ios/Classes/Enums.swift @@ -5,6 +5,7 @@ enum CredentialsProperty: String, CaseIterable { case refreshToken case expiresAt case scopes + case tokenType } enum UserInfoProperty: String, CaseIterable { diff --git a/auth0_flutter/ios/Classes/Extensions.swift b/auth0_flutter/ios/Classes/Extensions.swift index e082b536..a5d672fa 100644 --- a/auth0_flutter/ios/Classes/Extensions.swift +++ b/auth0_flutter/ios/Classes/Extensions.swift @@ -71,7 +71,8 @@ extension Credentials { CredentialsProperty.idToken.rawValue: idToken, CredentialsProperty.expiresAt.rawValue: expiresIn.asISO8601String, CredentialsProperty.scopes.rawValue: scope?.split(separator: " ").map(String.init) ?? [], - CredentialsProperty.userProfile.rawValue: UserInfo(json: jwt.body)?.asDictionary() ?? [:] + CredentialsProperty.userProfile.rawValue: UserInfo(json: jwt.body)?.asDictionary() ?? [:], + CredentialsProperty.tokenType.rawValue: tokenType, ] data[CredentialsProperty.refreshToken] = refreshToken return data diff --git a/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift b/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift index b2b1f5b4..8591acbd 100644 --- a/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift +++ b/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift @@ -1,7 +1,7 @@ import Flutter public class SwiftAuth0FlutterPlugin: NSObject, FlutterPlugin { - static var handlers: [FlutterPlugin.Type] = [WebAuthHandler.self, AuthAPIHandler.self] + static var handlers: [FlutterPlugin.Type] = [WebAuthHandler.self, AuthAPIHandler.self, CredentialsManagerHandler.self] public static func register(with registrar: FlutterPluginRegistrar) { handlers.forEach { $0.register(with: registrar) } diff --git a/auth0_flutter/lib/auth0_flutter.dart b/auth0_flutter/lib/auth0_flutter.dart index bd32cd73..7c2192f8 100644 --- a/auth0_flutter/lib/auth0_flutter.dart +++ b/auth0_flutter/lib/auth0_flutter.dart @@ -1,6 +1,7 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; import 'src/authentication_api.dart'; +import 'src/credentials_manager.dart'; import 'src/version.dart'; import 'src/web_authentication.dart'; @@ -10,9 +11,12 @@ export 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interfac ApiException, IdTokenValidationConfig, Credentials, - UserProfile; + UserProfile, + CredentialsManagerException, + LocalAuthenticationOptions; export 'src/authentication_api.dart'; +export 'src/credentials_manager.dart'; export 'src/web_authentication.dart'; /// Primary interface for interacting with Auth0 using web authentication, or the authentication API. @@ -28,18 +32,6 @@ class Auth0 { Auth0(final String domain, final String clientId) : _account = Account(domain, clientId); - /// An instance of [WebAuthentication], the primary interface for interacting with the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login). - /// - /// Usage example: - /// - /// ```dart - /// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); - /// final result = await auth0.webAuthentication.login(); - /// final accessToken = result.accessToken; - /// ``` - WebAuthentication get webAuthentication => - WebAuthentication(_account, _userAgent); - /// An instance of [AuthenticationApi], the primary interface for interacting with the Auth0 Authentication API /// /// Usage example: @@ -55,5 +47,37 @@ class Auth0 { /// /// final accessToken = result.accessToken; /// ``` + AuthenticationApi get api => AuthenticationApi(_account, _userAgent); + + /// Creates an instance of [WebAuthentication], the primary interface for interacting with the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login). + /// + /// Usage example: + /// + /// ```dart + /// final auth0 = Auth0('DOMAIN', 'CLIENT_ID'); + /// final result = await auth0.webAuthentication().login(); + /// final accessToken = result.accessToken; + /// ``` + /// + /// Uses the [DefaultCredentialsManager] by default. If you want to use your own implementation to handle credential storage, provide your own [CredentialsManager] implementation + /// by setting [customCredentialsManager]. + /// In case you want to opt-out of using any [CredentialsManager] alltogether, set [useCredentialsManager] to `false`. + /// If you want to use biometrics or pass-phrase when using the [DefaultCredentialsManager], set [localAuthentication]` to an instance of [LocalAuthenticationOptions]. + /// Note however that this settings has no effect when specifying a [customCredentialsManager] + WebAuthentication webAuthentication({ + final bool useCredentialsManager = true, + final LocalAuthenticationOptions? localAuthentication, + final CredentialsManager? customCredentialsManager, + }) { + final credentialsManager = useCredentialsManager + ? (customCredentialsManager ?? + (DefaultCredentialsManager( + _account, + _userAgent, + localAuthentication: localAuthentication, + ))) + : null; + return WebAuthentication(_account, _userAgent, credentialsManager); + } } diff --git a/auth0_flutter/lib/src/credentials_manager.dart b/auth0_flutter/lib/src/credentials_manager.dart new file mode 100644 index 00000000..1745ad12 --- /dev/null +++ b/auth0_flutter/lib/src/credentials_manager.dart @@ -0,0 +1,82 @@ +import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; + +/// Abstract CredentialsManager that can be used to provide a custom CredentialManager. +abstract class CredentialsManager { + Future get({ + final int minTtl = 0, + final Set scopes = const {}, + final Map parameters = const {}, + }); + + Future set(final Credentials credentials); + + Future hasValidCredentials({ + final int minTtl = 0, + }); + + Future clear(); +} + +/// Default [CredentialsManager] implementation that passes calls to +/// the Native CredentialManagers provided by Auth0.Android or Auth0.Swift, depending on the platform. +class DefaultCredentialsManager extends CredentialsManager { + final Account _account; + final UserAgent _userAgent; + late LocalAuthenticationOptions? _localAuthentication; + + DefaultCredentialsManager( + this._account, + this._userAgent, { + final LocalAuthenticationOptions? localAuthentication + }) { + _localAuthentication = localAuthentication; + } + + /// Retrieves the credentials from the storage and refreshes them if they have already expired. + /// + /// Change the minimum time in seconds that the access token should last before expiration by setting the [minTtl]. + /// Use the [scopes] parameter to set the scope to request for the access token. If `null` is passed, the previous scope will be kept. + /// Use the [parameters] parameter to send additional parameters in the request to refresh expired credentials. + @override + Future get({ + final int minTtl = 0, + final Set scopes = const {}, + final Map parameters = const {}, + }) => + CredentialsManagerPlatform.instance + .getCredentials(_createApiRequest(GetCredentialsOptions( + minTtl: minTtl, + scopes: scopes, + parameters: parameters, + ))); + + /// Stores the given credentials in the storage. Must have an `access_token` or `id_token` and a `expires_in` value. + @override + Future set(final Credentials credentials) => + CredentialsManagerPlatform.instance.saveCredentials( + _createApiRequest(SaveCredentialsOptions(credentials: credentials))); + + /// Checks if a non-expired pair of credentials can be obtained from this manager. + /// + /// Change the minimum time in seconds that the access token should last before expiration by setting the [minTtl]. + @override + Future hasValidCredentials({ + final int minTtl = 0, + }) => + CredentialsManagerPlatform.instance.hasValidCredentials( + _createApiRequest(HasValidCredentialsOptions(minTtl: minTtl))); + + /// Removes the credentials from the storage if present. + @override + Future clear() => CredentialsManagerPlatform.instance + .clearCredentials(_createApiRequest(null)); + + CredentialsManagerRequest + _createApiRequest( + final TOptions? options) => + CredentialsManagerRequest( + account: _account, + options: options, + userAgent: _userAgent, + localAuthentication: _localAuthentication); +} diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index 277c6f01..6a8dff26 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -1,5 +1,7 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; +import '../auth0_flutter.dart'; + /// An interface for authenticating users using the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login). /// /// Authentication using Universal Login works by redirecting your user to a login page hosted on Auth0's servers. To achieve this on a native device, @@ -18,8 +20,11 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interfac class WebAuthentication { final Account _account; final UserAgent _userAgent; + final CredentialsManager? _credentialsManager; + + CredentialsManager? credentialsManager() => _credentialsManager; - WebAuthentication(this._account, this._userAgent); + WebAuthentication(this._account, this._userAgent, this._credentialsManager); /// Redirects the user to the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login) for authentication. If successful, it returns /// a set of tokens, as well as the user's profile (constructed from ID token claims). @@ -49,18 +54,23 @@ class WebAuthentication { final Map parameters = const {}, final IdTokenValidationConfig idTokenValidationConfig = const IdTokenValidationConfig(), - }) => - Auth0FlutterWebAuthPlatform.instance.login(_createWebAuthRequest( - WebAuthLoginOptions( - audience: audience, - scopes: scopes, - redirectUrl: redirectUrl, - organizationId: organizationId, - invitationUrl: invitationUrl, - parameters: parameters, - idTokenValidationConfig: idTokenValidationConfig, - scheme: scheme, - useEphemeralSession: useEphemeralSession))); + }) async { + final credentials = await Auth0FlutterWebAuthPlatform.instance.login( + _createWebAuthRequest(WebAuthLoginOptions( + audience: audience, + scopes: scopes, + redirectUrl: redirectUrl, + organizationId: organizationId, + invitationUrl: invitationUrl, + parameters: parameters, + idTokenValidationConfig: idTokenValidationConfig, + scheme: scheme, + useEphemeralSession: useEphemeralSession))); + + await _credentialsManager?.set(credentials); + + return credentials; + } /// Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application /// once logout is complete. @@ -69,10 +79,31 @@ class WebAuthentication { /// bundle identifier in iOS. [returnTo] must appear in your **Allowed Logout URLs** list for the Auth0 app. [Read more about redirecting users after logout](https://auth0.com/docs/authenticate/login/logout#redirect-users-after-logout). /// /// (Android only): [scheme] must match the scheme that was used to configure the `auth0Scheme` manifest placeholder - Future logout({final String? returnTo, final String? scheme}) => - Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest( - WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme), - )); + Future logout({final String? returnTo, final String? scheme}) async { + await Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest( + WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme), + )); + await _credentialsManager?.clear(); + } + + /// Retrieves the Credentials for the current user. Calls the [CredentialsManager] when available, returns `null` if not. + /// + /// Change the minimum time in seconds that the access token should last before expiration by setting the [minTtl]. + /// Use the [scopes] parameter to set the scope to request for the access token. If `null` is passed, the previous scope will be kept. + /// Use the [parameters] parameter to send additional parameters in the request to refresh expired credentials. + Future credentials({ + final int minTtl = 0, + final Set scopes = const {}, + final Map parameters = const {}, + }) async { + final credentials = await _credentialsManager?.get( + minTtl: minTtl, + scopes: scopes, + parameters: parameters, + ); + + return credentials; + } WebAuthRequest _createWebAuthRequest( diff --git a/auth0_flutter/test/authentication_api_test.dart b/auth0_flutter/test/authentication_api_test.dart index 02ce17a7..753010b2 100644 --- a/auth0_flutter/test/authentication_api_test.dart +++ b/auth0_flutter/test/authentication_api_test.dart @@ -22,7 +22,8 @@ class TestPlatform extends Mock 'refreshToken': 'refreshToken', 'expiresAt': DateTime.now().toIso8601String(), 'scopes': ['a'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }); static Credentials renewResult = Credentials.fromMap({ @@ -31,7 +32,8 @@ class TestPlatform extends Mock 'refreshToken': 'refreshToken', 'expiresAt': DateTime.now().toIso8601String(), 'scopes': ['a'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }); } diff --git a/auth0_flutter/test/authentication_api_test.mocks.dart b/auth0_flutter/test/authentication_api_test.mocks.dart index aa83bf26..2a0ee5ad 100644 --- a/auth0_flutter/test/authentication_api_test.mocks.dart +++ b/auth0_flutter/test/authentication_api_test.mocks.dart @@ -1,14 +1,15 @@ // Mocks generated by Mockito 5.1.0 from annotations -// in auth0_flutter/test/authentication_api_test.dart. +// in auth0_flutter/example/ios/.symlinks/plugins/auth0_flutter/test/authentication_api_test.dart. // Do not manually edit this file. -import 'dart:async' as _i4; +import 'dart:async' as _i5; +import 'package:auth0_flutter/auth0_flutter.dart' as _i2; import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart' - as _i2; + as _i3; import 'package:mockito/mockito.dart' as _i1; -import 'authentication_api_test.dart' as _i3; +import 'authentication_api_test.dart' as _i4; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -22,47 +23,47 @@ import 'authentication_api_test.dart' as _i3; class _FakeCredentials_0 extends _i1.Fake implements _i2.Credentials {} -class _FakeUserProfile_1 extends _i1.Fake implements _i2.UserProfile {} +class _FakeUserProfile_1 extends _i1.Fake implements _i3.UserProfile {} -class _FakeDatabaseUser_2 extends _i1.Fake implements _i2.DatabaseUser {} +class _FakeDatabaseUser_2 extends _i1.Fake implements _i3.DatabaseUser {} /// A class which mocks [TestPlatform]. /// /// See the documentation for Mockito's code generation for more information. -class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform { +class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform { MockTestPlatform() { _i1.throwOnMissingStub(this); } @override - _i4.Future<_i2.Credentials> login( - _i2.ApiRequest<_i2.AuthLoginOptions>? request) => + _i5.Future<_i2.Credentials> login( + _i3.ApiRequest<_i3.AuthLoginOptions>? request) => (super.noSuchMethod(Invocation.method(#login, [request]), returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) - as _i4.Future<_i2.Credentials>); + as _i5.Future<_i2.Credentials>); @override - _i4.Future<_i2.UserProfile> userInfo( - _i2.ApiRequest<_i2.AuthUserInfoOptions>? request) => + _i5.Future<_i3.UserProfile> userInfo( + _i3.ApiRequest<_i3.AuthUserInfoOptions>? request) => (super.noSuchMethod(Invocation.method(#userInfo, [request]), - returnValue: Future<_i2.UserProfile>.value(_FakeUserProfile_1())) - as _i4.Future<_i2.UserProfile>); + returnValue: Future<_i3.UserProfile>.value(_FakeUserProfile_1())) + as _i5.Future<_i3.UserProfile>); @override - _i4.Future<_i2.DatabaseUser> signup( - _i2.ApiRequest<_i2.AuthSignupOptions>? request) => + _i5.Future<_i3.DatabaseUser> signup( + _i3.ApiRequest<_i3.AuthSignupOptions>? request) => (super.noSuchMethod(Invocation.method(#signup, [request]), returnValue: - Future<_i2.DatabaseUser>.value(_FakeDatabaseUser_2())) - as _i4.Future<_i2.DatabaseUser>); + Future<_i3.DatabaseUser>.value(_FakeDatabaseUser_2())) + as _i5.Future<_i3.DatabaseUser>); @override - _i4.Future<_i2.Credentials> renew( - _i2.ApiRequest<_i2.AuthRenewOptions>? request) => + _i5.Future<_i2.Credentials> renew( + _i3.ApiRequest<_i3.AuthRenewOptions>? request) => (super.noSuchMethod(Invocation.method(#renew, [request]), returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) - as _i4.Future<_i2.Credentials>); + as _i5.Future<_i2.Credentials>); @override - _i4.Future resetPassword( - _i2.ApiRequest<_i2.AuthResetPasswordOptions>? request) => + _i5.Future resetPassword( + _i3.ApiRequest<_i3.AuthResetPasswordOptions>? request) => (super.noSuchMethod(Invocation.method(#resetPassword, [request]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i4.Future); + returnValueForMissingStub: Future.value()) as _i5.Future); } diff --git a/auth0_flutter/test/credentials_manager_test.dart b/auth0_flutter/test/credentials_manager_test.dart new file mode 100644 index 00000000..c94dbca8 --- /dev/null +++ b/auth0_flutter/test/credentials_manager_test.dart @@ -0,0 +1,164 @@ +import 'package:auth0_flutter/auth0_flutter.dart'; +import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'credentials_manager_test.mocks.dart'; + +class TestPlatform extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements + CredentialsManagerPlatform { + static Credentials credentials = Credentials.fromMap({ + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'refreshToken': 'refreshToken', + 'expiresAt': DateTime.now().toIso8601String(), + 'scopes': ['a'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' + }); +} + +@GenerateMocks([TestPlatform]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final mockedPlatform = MockTestPlatform(); + const account = Account('test-domain', 'test-clientId'); + final userAgent = UserAgent(name: 'test', version: '0.0.1'); + + setUp(() { + CredentialsManagerPlatform.instance = mockedPlatform; + reset(mockedPlatform); + }); + + group('get', () { + test('passes through properties to the platform', () async { + when(mockedPlatform.getCredentials(any)) + .thenAnswer((final _) async => TestPlatform.credentials); + + await DefaultCredentialsManager(account, userAgent) + .get(minTtl: 30, scopes: {'a', 'b'}, parameters: {'a': 'b'}); + + final verificationResult = + verify(mockedPlatform.getCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.minTtl, 30); + expect(verificationResult.options?.scopes, {'a', 'b'}); + expect(verificationResult.options?.parameters, {'a': 'b'}); + }); + + test('set minTtl, scope and parameters to default value when omitted', + () async { + when(mockedPlatform.getCredentials(any)) + .thenAnswer((final _) async => TestPlatform.credentials); + + await DefaultCredentialsManager(account, userAgent).get(); + + final verificationResult = + verify(mockedPlatform.getCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.options?.minTtl, 0); + // ignore: inference_failure_on_collection_literal + expect(verificationResult.options?.scopes, isEmpty); + expect(verificationResult.options?.parameters, isEmpty); + }); + }); + + group('set', () { + test('passes through properties to the platform', () async { + when(mockedPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + await DefaultCredentialsManager(account, userAgent).set(TestPlatform.credentials); + + final verificationResult = + verify(mockedPlatform.saveCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.credentials.accessToken, + TestPlatform.credentials.accessToken); + expect(verificationResult.options?.credentials.idToken, + TestPlatform.credentials.idToken); + expect(verificationResult.options?.credentials.refreshToken, + TestPlatform.credentials.refreshToken); + expect(verificationResult.options?.credentials.expiresAt, + TestPlatform.credentials.expiresAt); + expect(verificationResult.options?.credentials.scopes, + TestPlatform.credentials.scopes); + expect(verificationResult.options?.credentials.tokenType, + TestPlatform.credentials.tokenType); + }); + }); + + group('hasValidCredentials', () { + test('passes through properties to the platform', () async { + when(mockedPlatform.hasValidCredentials(any)) + .thenAnswer((final _) async => true); + + await DefaultCredentialsManager(account, userAgent).hasValidCredentials(minTtl: 30); + + final verificationResult = + verify(mockedPlatform.hasValidCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.minTtl, 30); + }); + + test('uses a default value for minTtl when omitted', () async { + when(mockedPlatform.hasValidCredentials(any)) + .thenAnswer((final _) async => true); + + await DefaultCredentialsManager(account, userAgent).hasValidCredentials(); + + final verificationResult = + verify(mockedPlatform.hasValidCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.minTtl, 0); + }); + + test('returns the value from the platform when true', () async { + when(mockedPlatform.hasValidCredentials(any)) + .thenAnswer((final _) async => true); + + final result = await DefaultCredentialsManager(account, userAgent).hasValidCredentials(); + + expect(result, true); + }); + + test('returns the value from the platform when false', () async { + when(mockedPlatform.hasValidCredentials(any)) + .thenAnswer((final _) async => false); + + final result = await DefaultCredentialsManager(account, userAgent).hasValidCredentials(); + + expect(result, false); + }); + }); + + group('clear', () { + test('calls the platform', () async { + when(mockedPlatform.clearCredentials(any)) + .thenAnswer((final _) async => true); + + await DefaultCredentialsManager(account, userAgent).clear(); + + final verificationResult = + verify(mockedPlatform.clearCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + }); + }); +} diff --git a/auth0_flutter/test/credentials_manager_test.mocks.dart b/auth0_flutter/test/credentials_manager_test.mocks.dart new file mode 100644 index 00000000..78b41c80 --- /dev/null +++ b/auth0_flutter/test/credentials_manager_test.mocks.dart @@ -0,0 +1,56 @@ +// Mocks generated by Mockito 5.1.0 from annotations +// in auth0_flutter/test/credentials_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i4; + +import 'package:auth0_flutter/auth0_flutter.dart' as _i2; +import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart' + as _i5; +import 'package:mockito/mockito.dart' as _i1; + +import 'credentials_manager_test.dart' as _i3; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeCredentials_0 extends _i1.Fake implements _i2.Credentials {} + +/// A class which mocks [TestPlatform]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform { + MockTestPlatform() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future<_i2.Credentials> getCredentials( + _i5.CredentialsManagerRequest<_i5.GetCredentialsOptions>? request) => + (super.noSuchMethod(Invocation.method(#getCredentials, [request]), + returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) + as _i4.Future<_i2.Credentials>); + @override + _i4.Future clearCredentials( + _i5.CredentialsManagerRequest<_i5.RequestOptions?>? request) => + (super.noSuchMethod(Invocation.method(#clearCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future saveCredentials( + _i5.CredentialsManagerRequest<_i5.SaveCredentialsOptions>? request) => + (super.noSuchMethod(Invocation.method(#saveCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future hasValidCredentials( + _i5.CredentialsManagerRequest<_i5.HasValidCredentialsOptions>? + request) => + (super.noSuchMethod(Invocation.method(#hasValidCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); +} diff --git a/auth0_flutter/test/web_authentication_test.dart b/auth0_flutter/test/web_authentication_test.dart index 55938d79..30c50f87 100644 --- a/auth0_flutter/test/web_authentication_test.dart +++ b/auth0_flutter/test/web_authentication_test.dart @@ -19,77 +19,281 @@ class TestPlatform extends Mock 'refreshToken': 'refreshToken', 'expiresAt': DateTime.now().toIso8601String(), 'scopes': ['a', 'b'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }); } -@GenerateMocks([TestPlatform]) +class TestCMPlatform extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements + CredentialsManagerPlatform {} + +@GenerateMocks([TestPlatform, TestCMPlatform, CredentialsManager]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); final mockedPlatform = MockTestPlatform(); + final mockedCMPlatform = MockTestCMPlatform(); setUp(() { Auth0FlutterWebAuthPlatform.instance = mockedPlatform; + CredentialsManagerPlatform.instance = mockedCMPlatform; reset(mockedPlatform); + reset(mockedCMPlatform); }); - test('login', () async { - when(mockedPlatform.login(any)) - .thenAnswer((final _) async => TestPlatform.loginResult); - - final result = await Auth0('test-domain', 'test-clientId') - .webAuthentication - .login( - audience: 'test-audience', - scopes: {'a', 'b'}, - invitationUrl: 'invitation_url', - organizationId: 'org_123', - redirectUrl: 'redirect_url', - useEphemeralSession: true); - - final verificationResult = verify(mockedPlatform.login(captureAny)) - .captured - .single as WebAuthRequest; - expect(verificationResult.account.domain, 'test-domain'); - expect(verificationResult.account.clientId, 'test-clientId'); - expect(verificationResult.options.audience, 'test-audience'); - expect(verificationResult.options.scopes, {'a', 'b'}); - expect(verificationResult.options.invitationUrl, 'invitation_url'); - expect(verificationResult.options.organizationId, 'org_123'); - expect(verificationResult.options.redirectUrl, 'redirect_url'); - expect(verificationResult.options.useEphemeralSession, true); - expect(result, TestPlatform.loginResult); + group('login', () { + test('calls the platform to login', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + final result = await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .login( + audience: 'test-audience', + scopes: {'a', 'b'}, + invitationUrl: 'invitation_url', + organizationId: 'org_123', + redirectUrl: 'redirect_url', + useEphemeralSession: true); + + final verificationResult = verify(mockedPlatform.login(captureAny)) + .captured + .single as WebAuthRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options.audience, 'test-audience'); + expect(verificationResult.options.scopes, {'a', 'b'}); + expect(verificationResult.options.invitationUrl, 'invitation_url'); + expect(verificationResult.options.organizationId, 'org_123'); + expect(verificationResult.options.redirectUrl, 'redirect_url'); + expect(verificationResult.options.useEphemeralSession, true); + expect(result, TestPlatform.loginResult); + }); + + test('saves the credentials on success', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId').webAuthentication().login( + audience: 'test-audience', + scopes: {'a', 'b'}, + invitationUrl: 'invitation_url', + organizationId: 'org_123', + redirectUrl: 'redirect_url', + useEphemeralSession: true); + + final verificationResult = + verify(mockedCMPlatform.saveCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.credentials.accessToken, + TestPlatform.loginResult.accessToken); + }); + + test('does not save the credentials on success when opted out', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication(useCredentialsManager: false) + .login( + audience: 'test-audience', + scopes: {'a', 'b'}, + invitationUrl: 'invitation_url', + organizationId: 'org_123', + redirectUrl: 'redirect_url', + useEphemeralSession: true); + + verifyNever(mockedCMPlatform.saveCredentials(any)); + }); + + test('uses custom Credentials Manager on success', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + final mockCm = MockCredentialsManager(); + + when(mockCm.set(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication(customCredentialsManager: mockCm) + .login( + audience: 'test-audience', + scopes: {'a', 'b'}, + invitationUrl: 'invitation_url', + organizationId: 'org_123', + redirectUrl: 'redirect_url', + useEphemeralSession: true); + + // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager + verifyNever(mockedCMPlatform.saveCredentials(any)); + + final verificationResult = + verify(mockCm.set(captureAny)).captured.single as Credentials; + + expect( + verificationResult.accessToken, TestPlatform.loginResult.accessToken); + }); + + test('does not use EphemeralSession by default', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + final result = await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .login(audience: 'test-audience', scopes: {'a', 'b'}); + + final verificationResult = verify(mockedPlatform.login(captureAny)) + .captured + .single as WebAuthRequest; + expect(verificationResult.options.useEphemeralSession, false); + expect(result, TestPlatform.loginResult); + }); }); - test('login - does not use EphemeralSession by default', () async { - when(mockedPlatform.login(any)) - .thenAnswer((final _) async => TestPlatform.loginResult); + group('credentials', () { + test('calls the credentials manager', () async { + when(mockedCMPlatform.getCredentials(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .credentials( + minTtl: 30, + scopes: {'a', 'b'}, + parameters: {'test': 'test-value'}); + + final verificationResult = + verify(mockedCMPlatform.getCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options?.minTtl, 30); + expect(verificationResult.options?.scopes, {'a', 'b'}); + expect(verificationResult.options?.parameters['test'], 'test-value'); + }); + + test('returns null when opted out of credential manager', () async { + when(mockedCMPlatform.getCredentials(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); - final result = await Auth0('test-domain', 'test-clientId') - .webAuthentication - .login(audience: 'test-audience', scopes: {'a', 'b'}); + final result = await Auth0('test-domain', 'test-clientId') + .webAuthentication(useCredentialsManager: false) + .credentials( + minTtl: 30, + scopes: {'a', 'b'}, + parameters: {'test': 'test-value'}); - final verificationResult = verify(mockedPlatform.login(captureAny)) - .captured - .single as WebAuthRequest; - expect(verificationResult.options.useEphemeralSession, false); - expect(result, TestPlatform.loginResult); + expect(result, null); + }); + + test('uses custom Credential Manager on success', () async { + when(mockedCMPlatform.getCredentials(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + final mockCm = MockCredentialsManager(); + when(mockCm.get( + minTtl: anyNamed('minTtl'), + scopes: anyNamed('scopes'), + parameters: anyNamed('parameters'))) + .thenAnswer((final _) async => TestPlatform.loginResult); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication(customCredentialsManager: mockCm) + .credentials( + minTtl: 30, + scopes: {'a', 'b'}, + parameters: {'test': 'test-value'}); + + // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager + verifyNever(mockedCMPlatform.getCredentials(any)); + + verify(mockCm.get( + minTtl: anyNamed('minTtl'), + scopes: anyNamed('scopes'), + parameters: anyNamed('parameters'))) + .called(1); + }); }); - test('logout', () async { - when(mockedPlatform.logout(any)).thenAnswer((final _) async => {}); + group('logout', () { + test('calls the platform to logout', () async { + when(mockedPlatform.logout(any)).thenAnswer((final _) async => {}); + when(mockedCMPlatform.clearCredentials(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .logout(returnTo: 'abc'); + + final verificationResult = verify(mockedPlatform.logout(captureAny)) + .captured + .single as WebAuthRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + expect(verificationResult.options.returnTo, 'abc'); + }); + + test('clears the credentials on success', () async { + when(mockedPlatform.logout(any)).thenAnswer((final _) async => {}); + when(mockedCMPlatform.clearCredentials(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .logout(returnTo: 'abc'); + + final verificationResult = + verify(mockedCMPlatform.clearCredentials(captureAny)).captured.single + as CredentialsManagerRequest; + expect(verificationResult.account.domain, 'test-domain'); + expect(verificationResult.account.clientId, 'test-clientId'); + }); + + test('does not clear the credentials on success when opted out', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.clearCredentials(any)) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication(useCredentialsManager: false) + .logout(returnTo: 'abc'); + + verifyNever(mockedCMPlatform.clearCredentials(any)); + }); + + test('uses custom Credentials Manager on success', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.clearCredentials(any)) + .thenAnswer((final _) async => true); + final mockCm = MockCredentialsManager(); + when(mockCm.clear()) + .thenAnswer((final _) async => true); + + await Auth0('test-domain', 'test-clientId') + .webAuthentication(customCredentialsManager: mockCm) + .logout(returnTo: 'abc'); - await Auth0('test-domain', 'test-clientId') - .webAuthentication - .logout(returnTo: 'abc'); + // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager + verifyNever(mockedCMPlatform.clearCredentials(any)); - final verificationResult = - verify(mockedPlatform.logout(captureAny)) - .captured - .single as WebAuthRequest; - expect(verificationResult.account.domain, 'test-domain'); - expect(verificationResult.account.clientId, 'test-clientId'); - expect(verificationResult.options.returnTo, 'abc'); + verify(mockCm.clear()).called(1); + }); }); } diff --git a/auth0_flutter/test/web_authentication_test.mocks.dart b/auth0_flutter/test/web_authentication_test.mocks.dart index dd8ea59b..295ca9df 100644 --- a/auth0_flutter/test/web_authentication_test.mocks.dart +++ b/auth0_flutter/test/web_authentication_test.mocks.dart @@ -4,8 +4,9 @@ import 'dart:async' as _i4; +import 'package:auth0_flutter/auth0_flutter.dart' as _i2; import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart' - as _i2; + as _i5; import 'package:mockito/mockito.dart' as _i1; import 'web_authentication_test.dart' as _i3; @@ -32,14 +33,81 @@ class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform { @override _i4.Future<_i2.Credentials> login( - _i2.WebAuthRequest<_i2.WebAuthLoginOptions>? request) => + _i5.WebAuthRequest<_i5.WebAuthLoginOptions>? request) => (super.noSuchMethod(Invocation.method(#login, [request]), returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) as _i4.Future<_i2.Credentials>); @override _i4.Future logout( - _i2.WebAuthRequest<_i2.WebAuthLogoutOptions>? request) => + _i5.WebAuthRequest<_i5.WebAuthLogoutOptions>? request) => (super.noSuchMethod(Invocation.method(#logout, [request]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); } + +/// A class which mocks [TestCMPlatform]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestCMPlatform extends _i1.Mock implements _i3.TestCMPlatform { + MockTestCMPlatform() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future<_i2.Credentials> getCredentials( + _i5.CredentialsManagerRequest<_i5.GetCredentialsOptions>? request) => + (super.noSuchMethod(Invocation.method(#getCredentials, [request]), + returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) + as _i4.Future<_i2.Credentials>); + @override + _i4.Future clearCredentials( + _i5.CredentialsManagerRequest<_i5.RequestOptions?>? request) => + (super.noSuchMethod(Invocation.method(#clearCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future saveCredentials( + _i5.CredentialsManagerRequest<_i5.SaveCredentialsOptions>? request) => + (super.noSuchMethod(Invocation.method(#saveCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future hasValidCredentials( + _i5.CredentialsManagerRequest<_i5.HasValidCredentialsOptions>? + request) => + (super.noSuchMethod(Invocation.method(#hasValidCredentials, [request]), + returnValue: Future.value(false)) as _i4.Future); +} + +/// A class which mocks [CredentialsManager]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCredentialsManager extends _i1.Mock + implements _i2.CredentialsManager { + MockCredentialsManager() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future<_i2.Credentials> get( + {int? minTtl = 0, + Set? scopes = const {}, + Map? parameters = const {}}) => + (super.noSuchMethod( + Invocation.method(#get, [], + {#minTtl: minTtl, #scopes: scopes, #parameters: parameters}), + returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) + as _i4.Future<_i2.Credentials>); + @override + _i4.Future set(_i2.Credentials? credentials) => + (super.noSuchMethod(Invocation.method(#set, [credentials]), + returnValue: Future.value(true), + returnValueForMissingStub: Future.value()) as _i4.Future); + @override + _i4.Future hasValidCredentials({int? minTtl = 0}) => + (super.noSuchMethod( + Invocation.method(#hasValidCredentials, [], {#minTtl: minTtl}), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future clear() => (super.noSuchMethod(Invocation.method(#clear, []), + returnValue: Future.value(true), + returnValueForMissingStub: Future.value()) as _i4.Future); +} diff --git a/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart b/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart index d41f124c..e733aa0d 100644 --- a/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart +++ b/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart @@ -8,6 +8,13 @@ export 'src/auth/auth_user_info_options.dart'; export 'src/auth0_exception.dart'; export 'src/auth0_flutter_auth_platform.dart'; export 'src/auth0_flutter_web_auth_platform.dart'; +export 'src/credentials-manager/credentials_manager_exception.dart'; +export 'src/credentials-manager/credentials_manager_platform.dart'; +export 'src/credentials-manager/method_channel_credentials_manager.dart'; +export 'src/credentials-manager/options/get_credentials_options.dart'; +export 'src/credentials-manager/options/has_valid_credentials_options.dart'; +export 'src/credentials-manager/options/local_authentication_options.dart'; +export 'src/credentials-manager/options/save_credentials_options.dart'; export 'src/credentials.dart'; export 'src/database_user.dart'; export 'src/method_channel_auth0_flutter_auth.dart'; diff --git a/auth0_flutter_platform_interface/lib/src/auth/api_exception.dart b/auth0_flutter_platform_interface/lib/src/auth/api_exception.dart index 98e12dc2..76f848d1 100644 --- a/auth0_flutter_platform_interface/lib/src/auth/api_exception.dart +++ b/auth0_flutter_platform_interface/lib/src/auth/api_exception.dart @@ -18,12 +18,11 @@ class ApiException extends Auth0Exception { const ApiException.unknown(final String message) : _errorFlags = const {}, statusCode = 0, - super.unknown(message); + super.unknown(message); // coverage:ignore-line factory ApiException.fromPlatformException(final PlatformException e) { final Map errorDetails = e.detailsMap; - final statusCode = - errorDetails.getOrDefault(_statusCodeKey, 0); + final statusCode = errorDetails.getOrDefault(_statusCodeKey, 0); final errorFlags = errorDetails.getOrDefault(_errorFlagsKey, {}); diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_exception.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_exception.dart new file mode 100644 index 00000000..7ca18680 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_exception.dart @@ -0,0 +1,23 @@ +import 'package:flutter/services.dart'; + +import '../auth0_exception.dart'; +import '../extensions/exception_extensions.dart'; + +// ignore: comment_references +/// Exception thrown by [MethodChannelCredentialsManager] when something goes wrong. +class CredentialsManagerException extends Auth0Exception { + const CredentialsManagerException(final String code, final String message, + final Map details) + : super(code, message, details); + + const CredentialsManagerException.unknown(final String message) + : super.unknown(message); // coverage:ignore-line + + /// Fectory method that transforms a [PlatformException] to a [CredentialsManagerException]. + factory CredentialsManagerException.fromPlatformException( + final PlatformException e) { + final Map errorDetails = e.detailsMap; + + return CredentialsManagerException(e.code, e.messageString, errorDetails); + } +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart new file mode 100644 index 00000000..d442c3ea --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart @@ -0,0 +1,54 @@ +// coverage:ignore-file +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import '../credentials.dart'; +import '../request/request.dart'; +import 'method_channel_credentials_manager.dart'; +import 'options/get_credentials_options.dart'; +import 'options/has_valid_credentials_options.dart'; +import 'options/save_credentials_options.dart'; + +/// The interface that implementations of CredentialsManager must implement. +abstract class CredentialsManagerPlatform extends PlatformInterface { + CredentialsManagerPlatform() : super(token: _token); + + static CredentialsManagerPlatform get instance => _instance; + + static final Object _token = Object(); + + /// The default instance of [CredentialsManagerPlatform] to use. + /// + /// Defaults to [MethodChannelCredentialsManager]. + static CredentialsManagerPlatform _instance = + MethodChannelCredentialsManager(); + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [CredentialsManagerPlatform] when they register themselves. + static set instance(final CredentialsManagerPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + /// Retrieves the credentials from the native storage. + Future getCredentials( + final CredentialsManagerRequest request) { + throw UnimplementedError('getCredentials() has not been implemented'); + } + + /// Removes the credentials from the native storage if present. + Future clearCredentials(final CredentialsManagerRequest request) { + throw UnimplementedError('clearCredentials() has not been implemented'); + } + + /// Stores the given credentials in the native storage. Must have an access_token or id_token and a expires_in value. + Future saveCredentials( + final CredentialsManagerRequest request) { + throw UnimplementedError('saveCredentials() has not been implemented'); + } + + /// Checks if a non-expired pair of credentials can be obtained from the native storage. + Future hasValidCredentials( + final CredentialsManagerRequest request) { + throw UnimplementedError('hasValidCredentials() has not been implemented'); + } +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart new file mode 100644 index 00000000..fe0c6149 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart @@ -0,0 +1,99 @@ +import 'package:flutter/services.dart'; + +import '../auth/api_exception.dart'; +import '../credentials.dart'; +import '../request/request.dart'; +import '../request/request_options.dart'; +import 'credentials_manager_exception.dart'; +import 'credentials_manager_platform.dart'; +import 'options/get_credentials_options.dart'; +import 'options/has_valid_credentials_options.dart'; +import 'options/save_credentials_options.dart'; + +const MethodChannel _channel = MethodChannel('auth0.com/auth0_flutter/credentials_manager'); +const String credentialsManagerSaveCredentialsMethod = 'credentialsManager#saveCredentials'; +const String credentialsManagerGetCredentialsMethod = 'credentialsManager#getCredentials'; +const String credentialsManagerClearCredentialsMethod = 'credentialsManager#clearCredentials'; +const String credentialsManagerHasValidCredentialsMethod = 'credentialsManager#hasValidCredentials'; + +/// Method Channel implementation to communicate with the Native CredentialsManager +class MethodChannelCredentialsManager extends CredentialsManagerPlatform { + /// Retrieves the credentials from the native storage and refresh them if they have already expired. + /// + /// Uses the [MethodChannel] to communicate with the Native platforms. + @override + Future getCredentials(final CredentialsManagerRequest request) async { + final Map result = + await _invokeMapRequest(method: credentialsManagerGetCredentialsMethod, request: request); + + return Credentials.fromMap(result); + } + + /// Stores the given credentials in the native storage. Must have an access_token or id_token and a expires_in value. + /// + /// Uses the [MethodChannel] to communicate with the Native platforms. + @override + Future saveCredentials(final CredentialsManagerRequest request) async { + final bool? result = await _invokeRequest(method: credentialsManagerSaveCredentialsMethod, request: request); + return result ?? true; + } + + /// Removes the credentials from the native storage if present. + /// + /// Uses the [MethodChannel] to communicate with the Native platforms. + @override + Future clearCredentials(final CredentialsManagerRequest request) async { + final bool? result = await _invokeRequest(method: credentialsManagerClearCredentialsMethod, request: request); + return result ?? true; + } + + /// Checks if a non-expired pair of credentials can be obtained from the native storage. + /// + /// Uses the [MethodChannel] to communicate with the Native platforms. + @override + Future hasValidCredentials(final CredentialsManagerRequest request) async { + final bool? result = + await _invokeRequest(method: credentialsManagerHasValidCredentialsMethod, request: request); + + return result ?? false; + } + + Future _invokeRequest({ + required final String method, + required final CredentialsManagerRequest request, + final bool throwOnNull = true, + }) async { + final TResult? result; + try { + result = await _channel.invokeMethod(method, request.toMap()); + + } on PlatformException catch (e) { + throw CredentialsManagerException.fromPlatformException(e); + } + + if (result == null && throwOnNull == true) { + throw const CredentialsManagerException.unknown('Channel returned null.'); + } + + return result; + } + + Future> _invokeMapRequest({ + required final String method, + required final CredentialsManagerRequest request, + final bool throwOnNull = true, + }) async { + final Map? result; + try { + result = await _channel.invokeMapMethod(method, request.toMap()); + } on PlatformException catch (e) { + throw CredentialsManagerException.fromPlatformException(e); + } + + if (result == null && throwOnNull == true) { + throw const CredentialsManagerException.unknown('Channel returned null.'); + } + + return result ?? {}; + } +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/get_credentials_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/get_credentials_options.dart new file mode 100644 index 00000000..664fded9 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/get_credentials_options.dart @@ -0,0 +1,23 @@ +import '../../request/request_options.dart'; + + +// ignore: comment_references +/// Options used to retrieve [Credentials] using the [CredentialsManagerPlatform]. +class GetCredentialsOptions implements RequestOptions { + final int minTtl; + final Set scopes; + final Map parameters; + + GetCredentialsOptions({ + this.minTtl = 0, + this.scopes = const {}, + this.parameters = const {}, + }); + + @override + Map toMap() => { + 'minTtl': minTtl, + 'scopes': scopes.toList(), + 'parameters': parameters, + }; +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/has_valid_credentials_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/has_valid_credentials_options.dart new file mode 100644 index 00000000..d34d04d6 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/has_valid_credentials_options.dart @@ -0,0 +1,12 @@ +import '../../request/request_options.dart'; + +// ignore: comment_references +/// Options used to check if a non-expired pair of [Credentials] can be obtained using the [CredentialsManagerPlatform]. +class HasValidCredentialsOptions implements RequestOptions { + final int minTtl; + + HasValidCredentialsOptions({this.minTtl = 0}); + + @override + Map toMap() => {'minTtl': minTtl}; +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart new file mode 100644 index 00000000..143fd973 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart @@ -0,0 +1,6 @@ +class LocalAuthenticationOptions { + String? title; + String? description; + + LocalAuthenticationOptions({this.title, this.description}); +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/save_credentials_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/save_credentials_options.dart new file mode 100644 index 00000000..383d97d6 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/save_credentials_options.dart @@ -0,0 +1,13 @@ +import '../../credentials.dart'; +import '../../request/request_options.dart'; + +// ignore: comment_references +/// Options used to save [Credentials] using the [CredentialsManagerPlatform]. +class SaveCredentialsOptions implements RequestOptions { + final Credentials credentials; + + SaveCredentialsOptions({required this.credentials}); + + @override + Map toMap() => {'credentials': credentials.toMap()}; +} diff --git a/auth0_flutter_platform_interface/lib/src/credentials.dart b/auth0_flutter_platform_interface/lib/src/credentials.dart index f90acc96..10194979 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials.dart @@ -38,6 +38,7 @@ class Credentials { /// /// [Read more about Auth0 User Profiles](https://auth0.com/docs/manage-users/user-accounts/user-profiles) final UserProfile user; + final String tokenType; Credentials({ required this.idToken, @@ -46,6 +47,7 @@ class Credentials { required this.expiresAt, this.scopes = const {}, required this.user, + required this.tokenType, }); factory Credentials.fromMap(final Map result) => @@ -57,5 +59,15 @@ class Credentials { scopes: Set.from(result['scopes'] as List), user: UserProfile.fromMap(Map.from( result['userProfile'] as Map)), + tokenType: result['tokenType'] as String, ); + + Map toMap() => { + 'idToken': idToken, + 'accessToken': accessToken, + 'refreshToken': refreshToken, + 'expiresAt': expiresAt.toIso8601String(), + 'scopes': scopes.toList(), + 'tokenType': tokenType, + }; } diff --git a/auth0_flutter_platform_interface/lib/src/request/request.dart b/auth0_flutter_platform_interface/lib/src/request/request.dart index 4e62c9d0..53472c5c 100644 --- a/auth0_flutter_platform_interface/lib/src/request/request.dart +++ b/auth0_flutter_platform_interface/lib/src/request/request.dart @@ -1,10 +1,8 @@ -import '../account.dart'; -import '../user_agent.dart'; -import 'request_options.dart'; +import '../../auth0_flutter_platform_interface.dart'; -abstract class BaseRequest { - final TOptions options; +abstract class BaseRequest { final Account account; + final TOptions options; final UserAgent userAgent; BaseRequest({ @@ -13,11 +11,37 @@ abstract class BaseRequest { required this.userAgent, }); - Map toMap() => options.toMap() + Map toMap() => (options?.toMap() ?? {}) ..addAll({'_account': account.toMap()}) ..addAll({'_userAgent': userAgent.toMap()}); } +class CredentialsManagerRequest + extends BaseRequest { + late LocalAuthenticationOptions? localAuthentication; + CredentialsManagerRequest({ + required final Account account, + final TOptions? options, + required final UserAgent userAgent, + final this.localAuthentication, + }) : super(account: account, options: options, userAgent: userAgent); + + @override + Map toMap() { + if (localAuthentication != null) { + return (super.toMap()) + ..addAll({ + 'localAuthentication': { + 'title': localAuthentication?.title, + 'description': localAuthentication?.description + } + }); + } else { + return super.toMap(); + } + } +} + class ApiRequest extends BaseRequest { ApiRequest({ diff --git a/auth0_flutter_platform_interface/test/credential_manager_exception_test.dart b/auth0_flutter_platform_interface/test/credential_manager_exception_test.dart new file mode 100644 index 00000000..a1e79d36 --- /dev/null +++ b/auth0_flutter_platform_interface/test/credential_manager_exception_test.dart @@ -0,0 +1,21 @@ +import 'package:auth0_flutter_platform_interface/src/credentials-manager/credentials_manager_exception.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('CredentialsManagerException', () { + test('correctly maps from a PlatformException', () async { + final details = {'details-prop': 'details-value'}; + final platformException = PlatformException( + code: 'test-code', message: 'test-message', details: details); + + final exception = CredentialsManagerException.fromPlatformException(platformException); + + expect(exception.code, 'test-code'); + expect(exception.message, 'test-message'); + expect(exception.details['details-prop'], 'details-value'); + }); + }); +} diff --git a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart index 572558de..dccdc384 100644 --- a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart @@ -12,7 +12,8 @@ class MethodCallHandler { 'idToken': 'idToken', 'expiresAt': '2022-01-01', 'scopes': ['a', 'b'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }; static const Map loginResult = { @@ -36,7 +37,8 @@ class MethodCallHandler { 'refreshToken': 'refreshToken', 'expiresAt': '2022-01-01', 'scopes': ['a', 'b'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }; Future? methodCallHandler(final MethodCall? methodCall) async {} diff --git a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart index 66d013c7..7b93232d 100644 --- a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_web_auth_test.dart @@ -12,7 +12,8 @@ class MethodCallHandler { 'idToken': 'idToken', 'expiresAt': '2022-01-01', 'scopes': ['a', 'b'], - 'userProfile': {'sub': '123', 'name': 'John Doe'} + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' }; static const Map loginResult = { @@ -128,7 +129,7 @@ void main() { expect(verificationResult.arguments['useEphemeralSession'], false); expect(verificationResult.arguments['idTokenValidationConfig'], isNull); }); - + test('correctly returns the response from the Method Channel', () async { when(mocked.methodCallHandler(any)) .thenAnswer((final _) async => MethodCallHandler.loginResult); @@ -151,7 +152,7 @@ void main() { expect(result.user.name, MethodCallHandler.loginResult['userProfile']['name']); }); - + test( 'correctly returns the response from the Method Channel when properties missing', () async { @@ -261,7 +262,7 @@ void main() { expect(verificationResult.arguments['returnTo'], isNull); expect(verificationResult.arguments['scheme'], isNull); }); - + test( 'throws an WebAuthException when method channel throws a PlatformException', () async { diff --git a/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart new file mode 100644 index 00000000..88e19d44 --- /dev/null +++ b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart @@ -0,0 +1,479 @@ +import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; +import 'package:auth0_flutter_platform_interface/src/credentials-manager/credentials_manager_exception.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'method_channel_credentials_manager_test.mocks.dart'; + +class MethodCallHandler { + static const Map credentials = { + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'expiresAt': '2022-01-01', + 'scopes': ['a', 'b'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer' + }; + + Future? methodCallHandler(final MethodCall? methodCall) async {} +} + +@GenerateMocks([MethodCallHandler]) +void main() { + const MethodChannel channel = + MethodChannel('auth0.com/auth0_flutter/credentials_manager'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + final mocked = MockMethodCallHandler(); + + setUp(() { + channel.setMockMethodCallHandler(mocked.methodCallHandler); + reset(mocked); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); + + group('getCredentials', () { + test('calls the correct MethodChannel method', () async { + when(mocked.methodCallHandler(any)) + .thenAnswer((final _) async => MethodCallHandler.credentials); + + await MethodChannelCredentialsManager().getCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: GetCredentialsOptions())); + + expect( + verify(mocked.methodCallHandler(captureAny)).captured.single.method, + 'credentialsManager#getCredentials'); + }); + + test('correctly maps all properties', () async { + when(mocked.methodCallHandler(any)) + .thenAnswer((final _) async => MethodCallHandler.credentials); + + await MethodChannelCredentialsManager() + .getCredentials(CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: GetCredentialsOptions( + minTtl: 30, + scopes: {'test-scope1', 'test-scope2'}, + parameters: {'test': 'test-123'}, + ))); + + final verificationResult = + verify(mocked.methodCallHandler(captureAny)).captured.single; + expect(verificationResult.arguments['_account']['domain'], 'test-domain'); + expect(verificationResult.arguments['_account']['clientId'], + 'test-clientId'); + expect(verificationResult.arguments['_userAgent']['name'], 'test-name'); + expect(verificationResult.arguments['_userAgent']['version'], + 'test-version'); + expect(verificationResult.arguments['minTtl'], 30); + expect(verificationResult.arguments['scopes'], + ['test-scope1', 'test-scope2']); + expect(verificationResult.arguments['parameters']['test'], 'test-123'); + }); + + test( + 'correctly assigns default values to all non-required properties when missing', + () async { + when(mocked.methodCallHandler(any)) + .thenAnswer((final _) async => MethodCallHandler.credentials); + + await MethodChannelCredentialsManager().getCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: UserAgent(name: '', version: ''), + options: GetCredentialsOptions())); + + final verificationResult = + verify(mocked.methodCallHandler(captureAny)).captured.single; + expect(verificationResult.arguments['minTtl'], 0); + expect(verificationResult.arguments['scopes'], isEmpty); + expect(verificationResult.arguments['parameters'], isEmpty); + }); + + test('correctly returns the response from the Method Channel', () async { + when(mocked.methodCallHandler(any)) + .thenAnswer((final _) async => MethodCallHandler.credentials); + + final result = await MethodChannelCredentialsManager() + .getCredentials(CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: GetCredentialsOptions( + minTtl: 30, + scopes: {'test-scope1', 'test-scope2'}, + parameters: {'test': 'test-123'}, + ))); + + verify(mocked.methodCallHandler(captureAny)); + + expect(result.accessToken, MethodCallHandler.credentials['accessToken']); + expect(result.idToken, MethodCallHandler.credentials['idToken']); + expect( + result.refreshToken, MethodCallHandler.credentials['refreshToken']); + expect(result.scopes, MethodCallHandler.credentials['scopes']); + expect(result.expiresAt, + DateTime.parse(MethodCallHandler.credentials['expiresAt'] as String)); + expect(result.tokenType, MethodCallHandler.credentials['tokenType']); + }); + + test( + 'throws a CredentialsManagerException when method channel returns null', + () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => null); + + Future actual() async { + final result = await MethodChannelCredentialsManager().getCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: GetCredentialsOptions())); + + return result; + } + + expectLater( + actual, + throwsA(predicate((e) => + e is CredentialsManagerException && + e.message == 'Channel returned null.'))); + }); + + test( + 'throws an ApiException when method channel throws a PlatformException', + () async { + when(mocked.methodCallHandler(any)) + .thenThrow(PlatformException(code: '123')); + + Future actual() async { + final result = await MethodChannelCredentialsManager().getCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: GetCredentialsOptions())); + + return result; + } + + await expectLater(actual, throwsA(isA())); + }); + }); + + group('saveCredentials', () { + test('calls the correct MethodChannel method', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + final credentials = Credentials.fromMap({ + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'refreshToken': 'refreshToken', + 'expiresAt': DateTime.now().toIso8601String(), + 'scopes': ['a'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer', + }); + + await MethodChannelCredentialsManager().saveCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: SaveCredentialsOptions(credentials: credentials))); + + expect( + verify(mocked.methodCallHandler(captureAny)).captured.single.method, + 'credentialsManager#saveCredentials'); + }); + + test('correctly maps all properties', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + final credentials = Credentials.fromMap({ + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'refreshToken': 'refreshToken', + 'expiresAt': DateTime.now().toIso8601String(), + 'scopes': ['a'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer', + }); + + await MethodChannelCredentialsManager().saveCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: SaveCredentialsOptions(credentials: credentials))); + + final verificationResult = + verify(mocked.methodCallHandler(captureAny)).captured.single; + expect(verificationResult.arguments['_account']['domain'], 'test-domain'); + expect(verificationResult.arguments['_account']['clientId'], + 'test-clientId'); + expect(verificationResult.arguments['_userAgent']['name'], 'test-name'); + expect(verificationResult.arguments['_userAgent']['version'], + 'test-version'); + expect(verificationResult.arguments['credentials'], isNotNull); + expect(verificationResult.arguments['credentials']['accessToken'], + credentials.accessToken); + expect(verificationResult.arguments['credentials']['idToken'], + credentials.idToken); + expect(verificationResult.arguments['credentials']['refreshToken'], + credentials.refreshToken); + expect(verificationResult.arguments['credentials']['expiresAt'], + credentials.expiresAt.toIso8601String()); + expect(verificationResult.arguments['credentials']['scopes'], ['a']); + expect( + verificationResult.arguments['credentials']['tokenType'], 'Bearer'); + expect( + verificationResult.arguments['credentials']['userProfile'], isNull); + }); + + test( + 'throws a CredentialsManagerException when method channel throws a PlatformException', + () async { + when(mocked.methodCallHandler(any)) + .thenThrow(PlatformException(code: '123')); + + final credentials = Credentials.fromMap({ + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'refreshToken': 'refreshToken', + 'expiresAt': DateTime.now().toIso8601String(), + 'scopes': ['a'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer', + }); + + Future actual() async { + final result = await MethodChannelCredentialsManager().saveCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: SaveCredentialsOptions(credentials: credentials))); + + return result; + } + + await expectLater(actual, throwsA(isA())); + }); + + test( + 'throws a CredentialsManagerException when method channel returns null', + () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => null); + + final credentials = Credentials.fromMap({ + 'accessToken': 'accessToken', + 'idToken': 'idToken', + 'refreshToken': 'refreshToken', + 'expiresAt': DateTime.now().toIso8601String(), + 'scopes': ['a'], + 'userProfile': {'sub': '123', 'name': 'John Doe'}, + 'tokenType': 'Bearer', + }); + + Future actual() async { + final result = await MethodChannelCredentialsManager().saveCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: SaveCredentialsOptions(credentials: credentials))); + + return result; + } + + expectLater( + actual, + throwsA(predicate((e) => + e is CredentialsManagerException && + e.message == 'Channel returned null.'))); + }); + }); + + group('hasValidCredentials', () { + test('calls the correct MethodChannel method', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + await MethodChannelCredentialsManager().hasValidCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: HasValidCredentialsOptions())); + + expect( + verify(mocked.methodCallHandler(captureAny)).captured.single.method, + 'credentialsManager#hasValidCredentials'); + }); + + test('correctly maps all properties', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + await MethodChannelCredentialsManager().hasValidCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: UserAgent(name: 'test-name', version: 'test-version'), + options: HasValidCredentialsOptions(minTtl: 30))); + + final verificationResult = + verify(mocked.methodCallHandler(captureAny)).captured.single; + + expect(verificationResult.arguments['_account']['domain'], 'test-domain'); + expect(verificationResult.arguments['_account']['clientId'], + 'test-clientId'); + expect(verificationResult.arguments['_userAgent']['name'], 'test-name'); + expect(verificationResult.arguments['_userAgent']['version'], + 'test-version'); + expect(verificationResult.arguments['minTtl'], 30); + }); + + test('correctly returns the response from the Method Channel', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => false); + + final result = await MethodChannelCredentialsManager() + .hasValidCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: HasValidCredentialsOptions())); + + verify(mocked.methodCallHandler(captureAny)); + + expect(result, false); + }); + + test( + 'throws a CredentialsManagerException when method channel throws a PlatformException', + () async { + when(mocked.methodCallHandler(any)) + .thenThrow(PlatformException(code: '123')); + + Future actual() async { + final result = await MethodChannelCredentialsManager() + .hasValidCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: HasValidCredentialsOptions())); + + return result; + } + + await expectLater(actual, throwsA(isA())); + }); + + test( + 'throws a CredentialsManagerException when method channel returns null', + () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => null); + + Future actual() async { + final result = await MethodChannelCredentialsManager() + .hasValidCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'), + options: HasValidCredentialsOptions())); + + return result; + } + + expectLater( + actual, + throwsA(predicate((e) => + e is CredentialsManagerException && + e.message == 'Channel returned null.'))); + }); + }); + + group('clearCredentials', () { + test('calls the correct MethodChannel method', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + await MethodChannelCredentialsManager().clearCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'))); + + expect( + verify(mocked.methodCallHandler(captureAny)).captured.single.method, + 'credentialsManager#clearCredentials'); + }); + + test('correctly maps all properties', () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => true); + + await MethodChannelCredentialsManager().clearCredentials( + CredentialsManagerRequest( + account: const Account('test-domain', 'test-clientId'), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'))); + + final verificationResult = + verify(mocked.methodCallHandler(captureAny)).captured.single; + expect(verificationResult.arguments['_account']['domain'], 'test-domain'); + expect(verificationResult.arguments['_account']['clientId'], + 'test-clientId'); + expect(verificationResult.arguments['_userAgent']['name'], 'test-name'); + expect(verificationResult.arguments['_userAgent']['version'], + 'test-version'); + }); + + test( + 'throws a CredentialsManagerException when method channel throws a PlatformException', + () async { + when(mocked.methodCallHandler(any)) + .thenThrow(PlatformException(code: '123')); + + Future actual() async { + final result = await MethodChannelCredentialsManager().clearCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'))); + + return result; + } + + await expectLater(actual, throwsA(isA())); + }); + + test( + 'throws a CredentialsManagerException when method channel returns null', + () async { + when(mocked.methodCallHandler(any)).thenAnswer((final _) async => null); + + Future actual() async { + final result = await MethodChannelCredentialsManager().clearCredentials( + CredentialsManagerRequest( + account: const Account('', ''), + userAgent: + UserAgent(name: 'test-name', version: 'test-version'))); + + return result; + } + + expectLater( + actual, + throwsA(predicate((e) => + e is CredentialsManagerException && + e.message == 'Channel returned null.'))); + }); + }); +} diff --git a/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.mocks.dart b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.mocks.dart new file mode 100644 index 00000000..9a5ba03f --- /dev/null +++ b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.mocks.dart @@ -0,0 +1,26 @@ +// Mocks generated by Mockito 5.1.0 from annotations +// in auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart. +// Do not manually edit this file. + +import 'package:mockito/mockito.dart' as _i1; + +import 'method_channel_credentials_manager_test.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +/// A class which mocks [MethodCallHandler]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMethodCallHandler extends _i1.Mock implements _i2.MethodCallHandler { + MockMethodCallHandler() { + _i1.throwOnMissingStub(this); + } +} From b934e7f64aaf29923f99382e79eb094dc9985ae6 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 6 Jul 2022 08:01:41 -0300 Subject: [PATCH 06/38] Add iOS Credentials Manager implementation [SDK-3460] (#104) --- .../ios/Runner.xcodeproj/project.pbxproj | 48 +++++- .../Tests/AuthAPI/AuthAPIHandlerTests.swift | 14 +- ...ginUsernameOrEmailMethodHandlerTests.swift | 4 +- .../AuthAPIRenewMethodHandlerTests.swift | 4 +- ...thAPIResetPasswordMethodHandlerTests.swift | 3 +- .../AuthAPISignupMethodHandlerTests.swift | 3 +- .../AuthAPIUserInfoMethodHandlerTests.swift | 3 +- ...ntialsManagerClearMethodHandlerTests.swift | 44 +++++ ...dentialsManagerGetMethodHandlerTests.swift | 82 +++++++++ .../CredentialsManagerHandlerTests.swift | 162 ++++++++++++++++++ ...alsManagerHasValidMethodHandlerTests.swift | 70 ++++++++ ...entialsManagerSaveMethodHandlerTests.swift | 76 ++++++++ .../CredentialsManagerSpies.swift | 29 ++++ .../example/ios/Tests/ExtensionsTests.swift | 89 +++++++++- .../Tests/WebAuth/WebAuthHandlerTests.swift | 14 +- ...t => WebAuthLoginMethodHandlerTests.swift} | 4 +- ... => WebAuthLogoutMethodHandlerTests.swift} | 9 +- ...CredentialsManagerClearMethodHandler.swift | 4 +- .../CredentialsManagerExtensions.swift | 21 +++ .../CredentialsManagerGetMethodHandler.swift | 33 ++++ .../CredentialsManagerHandler.swift | 31 +++- ...dentialsManagerHasValidMethodHandler.swift | 18 ++ .../CredentialsManagerSaveMethodHandler.swift | 19 ++ auth0_flutter/ios/Classes/Extensions.swift | 29 +++- .../{Enums.swift => HandlerError.swift} | 36 +--- .../Classes/{Account.swift => Models.swift} | 21 +++ auth0_flutter/ios/Classes/Properties.swift | 33 ++++ .../ios/Classes/SwiftAuth0FlutterPlugin.swift | 4 +- auth0_flutter/ios/Classes/UserAgent.swift | 20 --- .../ios/Classes/WebAuth/WebAuthHandler.swift | 1 + 30 files changed, 825 insertions(+), 103 deletions(-) create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift rename auth0_flutter/example/ios/Tests/WebAuth/{WebAuthLoginHandlerTests.swift => WebAuthLoginMethodHandlerTests.swift} (98%) rename auth0_flutter/example/ios/Tests/WebAuth/{WebAuthLogoutHandlerTests.swift => WebAuthLogoutMethodHandlerTests.swift} (88%) create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift rename auth0_flutter/ios/Classes/{Enums.swift => HandlerError.swift} (58%) rename auth0_flutter/ios/Classes/{Account.swift => Models.swift} (51%) create mode 100644 auth0_flutter/ios/Classes/Properties.swift delete mode 100644 auth0_flutter/ios/Classes/UserAgent.swift diff --git a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj index de31fd96..375df610 100644 --- a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -13,12 +13,18 @@ 5C328B4827F7822600451E70 /* WebAuthHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B4727F7822600451E70 /* WebAuthHandlerTests.swift */; }; 5C328B5027F7B0E700451E70 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B4F27F7B0E600451E70 /* Utilities.swift */; }; 5C328B5327F7B12F00451E70 /* WebAuthSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B5227F7B12F00451E70 /* WebAuthSpies.swift */; }; - 5C328B5527F7B1F300451E70 /* WebAuthLoginHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B5427F7B1F300451E70 /* WebAuthLoginHandlerTests.swift */; }; + 5C328B5527F7B1F300451E70 /* WebAuthLoginMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B5427F7B1F300451E70 /* WebAuthLoginMethodHandlerTests.swift */; }; 5C328B5727F7BFEA00451E70 /* Mocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B5627F7BFEA00451E70 /* Mocks.swift */; }; - 5C335E3D27FBBC2300EDDE3A /* WebAuthLogoutHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutHandlerTests.swift */; }; + 5C335E3D27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift */; }; 5C335E3F27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C335E3E27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift */; }; 5C335E4127FBD2FE00EDDE3A /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C335E4027FBD2FE00EDDE3A /* ExtensionsTests.swift */; }; 5C335E4827FE68BC00EDDE3A /* AuthAPISpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C335E4727FE68BC00EDDE3A /* AuthAPISpies.swift */; }; + 5C4E65BF286D151C00141449 /* CredentialsManagerClearMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65BD286D151400141449 /* CredentialsManagerClearMethodHandlerTests.swift */; }; + 5C4E65C1286D15AF00141449 /* CredentialsManagerSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65C0286D15AF00141449 /* CredentialsManagerSpies.swift */; }; + 5C4E65C3286D19DC00141449 /* CredentialsManagerHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65C2286D19DC00141449 /* CredentialsManagerHandlerTests.swift */; }; + 5C4E65C5286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65C4286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift */; }; + 5C4E65C7286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65C6286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift */; }; + 5C4E65C9286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E65C8286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift */; }; 5C59DA6527FFCF0600365CDB /* AuthAPIHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA6427FFCF0600365CDB /* AuthAPIHandlerTests.swift */; }; 5C59DA6727FFE75600365CDB /* AuthAPILoginUsernameOrEmailMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA6627FFE75600365CDB /* AuthAPILoginUsernameOrEmailMethodHandlerTests.swift */; }; 5C59DA6928011D4F00365CDB /* AuthAPISignupMethodHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA6828011D4F00365CDB /* AuthAPISignupMethodHandlerTests.swift */; }; @@ -81,12 +87,18 @@ 5C328B4727F7822600451E70 /* WebAuthHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthHandlerTests.swift; sourceTree = ""; }; 5C328B4F27F7B0E600451E70 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; 5C328B5227F7B12F00451E70 /* WebAuthSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthSpies.swift; sourceTree = ""; }; - 5C328B5427F7B1F300451E70 /* WebAuthLoginHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthLoginHandlerTests.swift; sourceTree = ""; }; + 5C328B5427F7B1F300451E70 /* WebAuthLoginMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthLoginMethodHandlerTests.swift; sourceTree = ""; }; 5C328B5627F7BFEA00451E70 /* Mocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mocks.swift; sourceTree = ""; }; - 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthLogoutHandlerTests.swift; sourceTree = ""; }; + 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthLogoutMethodHandlerTests.swift; sourceTree = ""; }; 5C335E3E27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftAuth0FlutterPluginTests.swift; sourceTree = ""; }; 5C335E4027FBD2FE00EDDE3A /* ExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsTests.swift; sourceTree = ""; }; 5C335E4727FE68BC00EDDE3A /* AuthAPISpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPISpies.swift; sourceTree = ""; }; + 5C4E65BD286D151400141449 /* CredentialsManagerClearMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerClearMethodHandlerTests.swift; sourceTree = ""; }; + 5C4E65C0286D15AF00141449 /* CredentialsManagerSpies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerSpies.swift; sourceTree = ""; }; + 5C4E65C2286D19DC00141449 /* CredentialsManagerHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerHandlerTests.swift; sourceTree = ""; }; + 5C4E65C4286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerHasValidMethodHandlerTests.swift; sourceTree = ""; }; + 5C4E65C6286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerSaveMethodHandlerTests.swift; sourceTree = ""; }; + 5C4E65C8286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerGetMethodHandlerTests.swift; sourceTree = ""; }; 5C59DA6427FFCF0600365CDB /* AuthAPIHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPIHandlerTests.swift; sourceTree = ""; }; 5C59DA6627FFE75600365CDB /* AuthAPILoginUsernameOrEmailMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPILoginUsernameOrEmailMethodHandlerTests.swift; sourceTree = ""; }; 5C59DA6828011D4F00365CDB /* AuthAPISignupMethodHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPISignupMethodHandlerTests.swift; sourceTree = ""; }; @@ -164,6 +176,7 @@ children = ( 5C335E4627FE68A500EDDE3A /* AuthAPI */, 5C328B5127F7B11300451E70 /* WebAuth */, + 5C4E65BC286D022200141449 /* CredentialsManager */, 5C335E3E27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift */, 5CAAA4A1281A0C7D007666F1 /* AccountTests.swift */, 5CAAA4A3281A0E50007666F1 /* UserAgentTests.swift */, @@ -179,8 +192,8 @@ children = ( 5C328B5227F7B12F00451E70 /* WebAuthSpies.swift */, 5C328B4727F7822600451E70 /* WebAuthHandlerTests.swift */, - 5C328B5427F7B1F300451E70 /* WebAuthLoginHandlerTests.swift */, - 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutHandlerTests.swift */, + 5C328B5427F7B1F300451E70 /* WebAuthLoginMethodHandlerTests.swift */, + 5C335E3C27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift */, 5C59DA8C280938BE00365CDB /* WebAuthExtensionsTests.swift */, ); path = WebAuth; @@ -201,6 +214,19 @@ path = AuthAPI; sourceTree = ""; }; + 5C4E65BC286D022200141449 /* CredentialsManager */ = { + isa = PBXGroup; + children = ( + 5C4E65C0286D15AF00141449 /* CredentialsManagerSpies.swift */, + 5C4E65C2286D19DC00141449 /* CredentialsManagerHandlerTests.swift */, + 5C4E65C6286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift */, + 5C4E65C4286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift */, + 5C4E65C8286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift */, + 5C4E65BD286D151400141449 /* CredentialsManagerClearMethodHandlerTests.swift */, + ); + path = CredentialsManager; + sourceTree = ""; + }; 5C59DA95280958FB00365CDB /* UITests */ = { isa = PBXGroup; children = ( @@ -549,25 +575,31 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5C4E65BF286D151C00141449 /* CredentialsManagerClearMethodHandlerTests.swift in Sources */, 5C59DA6928011D4F00365CDB /* AuthAPISignupMethodHandlerTests.swift in Sources */, 5C59DA6727FFE75600365CDB /* AuthAPILoginUsernameOrEmailMethodHandlerTests.swift in Sources */, 5C59DA8B2809386B00365CDB /* AuthAPIExtensionsTests.swift in Sources */, 5C59DA8D280938BE00365CDB /* WebAuthExtensionsTests.swift in Sources */, 5C335E3F27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift in Sources */, + 5C4E65C5286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift in Sources */, 5C328B4827F7822600451E70 /* WebAuthHandlerTests.swift in Sources */, 5C328B5327F7B12F00451E70 /* WebAuthSpies.swift in Sources */, 5CAAA4A2281A0C7D007666F1 /* AccountTests.swift in Sources */, 5C59DA6527FFCF0600365CDB /* AuthAPIHandlerTests.swift in Sources */, + 5C4E65C7286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift in Sources */, 5C59DA712807B19900365CDB /* AuthAPIRenewMethodHandlerTests.swift in Sources */, 5C328B5027F7B0E700451E70 /* Utilities.swift in Sources */, - 5C328B5527F7B1F300451E70 /* WebAuthLoginHandlerTests.swift in Sources */, + 5C328B5527F7B1F300451E70 /* WebAuthLoginMethodHandlerTests.swift in Sources */, + 5C4E65C3286D19DC00141449 /* CredentialsManagerHandlerTests.swift in Sources */, 5C335E4827FE68BC00EDDE3A /* AuthAPISpies.swift in Sources */, + 5C4E65C9286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift in Sources */, 5C328B5727F7BFEA00451E70 /* Mocks.swift in Sources */, - 5C335E3D27FBBC2300EDDE3A /* WebAuthLogoutHandlerTests.swift in Sources */, + 5C335E3D27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift in Sources */, 5C335E4127FBD2FE00EDDE3A /* ExtensionsTests.swift in Sources */, 5C59DA732807B1A300365CDB /* AuthAPIResetPasswordMethodHandlerTests.swift in Sources */, 5C59DA832809214200365CDB /* AuthAPIUserInfoMethodHandlerTests.swift in Sources */, 5CAAA4A4281A0E50007666F1 /* UserAgentTests.swift in Sources */, + 5C4E65C1286D15AF00141449 /* CredentialsManagerSpies.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift index ad6c7001..e90cbe20 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift @@ -25,7 +25,7 @@ extension AuthAPIHandlerTests { extension AuthAPIHandlerTests { func testProducesErrorWhenArgumentsAreMissing() { - let expectation = expectation(description: "arguments are missing") + let expectation = self.expectation(description: "Arguments are missing") sut.handle(FlutterMethodCall(methodName: "", arguments: nil)) { result in assert(result: result, isError: .argumentsMissing) expectation.fulfill() @@ -34,7 +34,7 @@ extension AuthAPIHandlerTests { } func testProducesErrorWhenAccountIsMissing() { - let expectation = expectation(description: "account is missing") + let expectation = self.expectation(description: "account is missing") sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: Account.key))) { result in assert(result: result, isError: .accountMissing) expectation.fulfill() @@ -43,7 +43,7 @@ extension AuthAPIHandlerTests { } func testProducesErrorWhenUserAgentIsMissing() { - let expectation = expectation(description: "userAgent is missing") + let expectation = self.expectation(description: "userAgent is missing") sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: UserAgent.key))) { result in assert(result: result, isError: .userAgentMissing) expectation.fulfill() @@ -63,7 +63,7 @@ extension AuthAPIHandlerTests { let accountDictionary = [AccountProperty.clientId.rawValue: "foo", AccountProperty.domain.rawValue: "bar"] let userAgentDictionary = [UserAgentProperty.name.rawValue: "baz", UserAgentProperty.version.rawValue: "qux"] let argumentsDictionary = [Account.key: accountDictionary, UserAgent.key: userAgentDictionary] - let expectation = self.expectation(description: "called client provider") + let expectation = self.expectation(description: "Called client provider") sut.clientProvider = { account, userAgent in XCTAssertEqual(account.clientId, accountDictionary[AccountProperty.clientId]) XCTAssertEqual(account.domain, accountDictionary[AccountProperty.domain]) @@ -80,7 +80,7 @@ extension AuthAPIHandlerTests { func testCallsMethodHandlerProvider() { let methodName = AuthAPIHandler.Method.loginWithUsernameOrEmail.rawValue - let expectation = self.expectation(description: "called method handler provider") + let expectation = self.expectation(description: "Called method handler provider") sut.methodHandlerProvider = { method, _ in XCTAssertTrue(method.rawValue == methodName) expectation.fulfill() @@ -91,7 +91,7 @@ extension AuthAPIHandlerTests { } func testDoesNotCallMethodHandlerProviderWhenMethodIsUnsupported() { - let expectation = self.expectation(description: "did not call method handler provider") + let expectation = self.expectation(description: "Did not call method handler provider") sut.methodHandlerProvider = { _, _ in XCTFail("called method handler provider") return SpyMethodHandler() @@ -114,7 +114,7 @@ extension AuthAPIHandlerTests { ] methodHandlers.forEach { method, methodHandler in let methodCall = FlutterMethodCall(methodName: method.rawValue, arguments: arguments()) - let expectation = self.expectation(description: "returned \(methodHandler)") + let expectation = self.expectation(description: "Returned \(methodHandler)") expectations.append(expectation) sut.methodHandlerProvider = { method, client in let result = AuthAPIHandler().methodHandlerProvider(method, client) diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift index 24ba9f61..40fad5d5 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = AuthAPILoginUsernameOrEmailMethodHandler.Argument class AuthAPILoginUsernameOrEmailMethodHandlerTests: XCTestCase { - let spy = SpyAuthentication() + var spy: SpyAuthentication! var sut: AuthAPILoginUsernameOrEmailMethodHandler! override func setUpWithError() throws { + spy = SpyAuthentication() sut = AuthAPILoginUsernameOrEmailMethodHandler(client: spy) } } @@ -115,6 +116,7 @@ extension AuthAPILoginUsernameOrEmailMethodHandlerTests { func testProducesCredentials() { let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", idToken: testIdToken, refreshToken: "refreshToken", expiresIn: Date(), diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIRenewMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIRenewMethodHandlerTests.swift index c1951f9c..e2eba1eb 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIRenewMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIRenewMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = AuthAPIRenewMethodHandler.Argument class AuthAPIRenewMethodHandlerTests: XCTestCase { - let spy = SpyAuthentication() + var spy: SpyAuthentication! var sut: AuthAPIRenewMethodHandler! override func setUpWithError() throws { + spy = SpyAuthentication() sut = AuthAPIRenewMethodHandler(client: spy) } } @@ -82,6 +83,7 @@ extension AuthAPIRenewMethodHandlerTests { func testProducesCredentials() { let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", idToken: testIdToken, refreshToken: "refreshToken", expiresIn: Date(), diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIResetPasswordMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIResetPasswordMethodHandlerTests.swift index 58696a0c..fe97ee8c 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIResetPasswordMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIResetPasswordMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = AuthAPIResetPasswordMethodHandler.Argument class AuthAPIResetPasswordMethodHandlerTests: XCTestCase { - let spy = SpyAuthentication() + var spy: SpyAuthentication! var sut: AuthAPIResetPasswordMethodHandler! override func setUpWithError() throws { + spy = SpyAuthentication() sut = AuthAPIResetPasswordMethodHandler(client: spy) } } diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPISignupMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPISignupMethodHandlerTests.swift index 9f1a80d7..1af0ae84 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPISignupMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPISignupMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = AuthAPISignupMethodHandler.Argument class AuthAPISignupMethodHandlerTests: XCTestCase { - let spy = SpyAuthentication() + var spy: SpyAuthentication! var sut: AuthAPISignupMethodHandler! override func setUpWithError() throws { + spy = SpyAuthentication() sut = AuthAPISignupMethodHandler(client: spy) } } diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIUserInfoMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIUserInfoMethodHandlerTests.swift index ab20ac5e..0fd27e8f 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIUserInfoMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIUserInfoMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = AuthAPIUserInfoMethodHandler.Argument class AuthAPIUserInfoMethodHandlerTests: XCTestCase { - let spy = SpyAuthentication() + var spy: SpyAuthentication! var sut: AuthAPIUserInfoMethodHandler! override func setUpWithError() throws { + spy = SpyAuthentication() sut = AuthAPIUserInfoMethodHandler(client: spy) } } diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift new file mode 100644 index 00000000..f7d3680e --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift @@ -0,0 +1,44 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +class CredentialsManagerClearMethodHandlerTests: XCTestCase { + var spy: SpyCredentialsStorage! + var sut: CredentialsManagerClearMethodHandler! + + override func setUpWithError() throws { + spy = SpyCredentialsStorage() + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + sut = CredentialsManagerClearMethodHandler(credentialsManager: credentialsManager) + } +} + +// MARK: - Logout Result + +extension CredentialsManagerClearMethodHandlerTests { + func testCallsSDKClearMethod() { + sut.handle(with: arguments()) { _ in } + XCTAssertTrue(spy.calledDeleteEntry) + } + + func testProducesTrueOnSuccess() { + let expectation = self.expectation(description: "Produced true") + spy.deleteEntryReturnValue = true + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, true) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesFalseOnFailure() { + let expectation = self.expectation(description: "Produced false") + spy.deleteEntryReturnValue = false + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, false) + expectation.fulfill() + } + wait(for: [expectation]) + } +} diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift new file mode 100644 index 00000000..ac0a76ed --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift @@ -0,0 +1,82 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +fileprivate typealias Argument = CredentialsManagerGetMethodHandler.Argument + +class CredentialsManagerGetMethodHandlerTests: XCTestCase { + var spy: SpyCredentialsStorage! + var sut: CredentialsManagerGetMethodHandler! + + override func setUpWithError() throws { + spy = SpyCredentialsStorage() + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + sut = CredentialsManagerGetMethodHandler(credentialsManager: credentialsManager) + } +} + +// MARK: - Required Arguments Error + +extension CredentialsManagerGetMethodHandlerTests { + func testProducesErrorWhenRequiredArgumentsAreMissing() { + let keys: [Argument] = [.scopes, .minTtl, .parameters] + let expectations = keys.map { expectation(description: "\($0.rawValue) is missing") } + for (argument, currentExpectation) in zip(keys, expectations) { + sut.handle(with: arguments(without: argument)) { result in + assert(result: result, isError: .requiredArgumentMissing(argument.rawValue)) + currentExpectation.fulfill() + } + } + wait(for: expectations) + } +} + +// MARK: - Logout Result + +extension CredentialsManagerGetMethodHandlerTests { + func testCallsSDKGetMethod() { + let expectation = self.expectation(description: "Called get credentials method from the SDK") + sut.handle(with: arguments()) { _ in + XCTAssertTrue(self.spy.calledGetEntry) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesCredentials() { + let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", + idToken: testIdToken, + refreshToken: "refreshToken", + expiresIn: Date(timeIntervalSinceNow: 3600), + scope: "foo bar") + let expectation = self.expectation(description: "Produced credentials") + let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) + spy.getEntryReturnValue = data + sut.handle(with: arguments()) { result in + assert(result: result, has: CredentialsProperty.allCases) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesCredentialsManagerError() { + let error = CredentialsManagerError.noCredentials + let expectation = self.expectation(description: "Produced the CredentialsManagerError \(error)") + spy.getEntryReturnValue = nil + sut.handle(with: arguments()) { result in + assert(result: result, isError: error) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Helpers + +extension CredentialsManagerGetMethodHandlerTests { + override func arguments() -> [String: Any] { + return [Argument.scopes.rawValue: [], Argument.minTtl.rawValue: 1, Argument.parameters.rawValue: [:]] + } +} diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift new file mode 100644 index 00000000..8fd6f5de --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift @@ -0,0 +1,162 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +class CredentialsManagerHandlerTests: XCTestCase { + var sut: CredentialsManagerHandler! + + override func setUpWithError() throws { + sut = CredentialsManagerHandler() + } +} + +// MARK: - Registration + +extension CredentialsManagerHandlerTests { + func testRegistersItself() { + let spy = SpyPluginRegistrar() + CredentialsManagerHandler.register(with: spy) + XCTAssertTrue(spy.delegate is CredentialsManagerHandler) + } +} + +// MARK: - Required Arguments + +extension CredentialsManagerHandlerTests { + func testProducesErrorWhenArgumentsAreMissing() { + let expectation = expectation(description: "arguments are missing") + sut.handle(FlutterMethodCall(methodName: "", arguments: nil)) { result in + assert(result: result, isError: .argumentsMissing) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesErrorWhenAccountIsMissing() { + let expectation = expectation(description: "account is missing") + sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: Account.key))) { result in + assert(result: result, isError: .accountMissing) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesErrorWhenUserAgentIsMissing() { + let expectation = expectation(description: "userAgent is missing") + sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: UserAgent.key))) { result in + assert(result: result, isError: .userAgentMissing) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Providers + +extension CredentialsManagerHandlerTests { + + // MARK: AuthAPIClientProvider + + func testCallsAPIClientProvider() { + let methodName = CredentialsManagerHandler.Method.save.rawValue + let accountDictionary = [AccountProperty.clientId.rawValue: "foo", AccountProperty.domain.rawValue: "bar"] + let userAgentDictionary = [UserAgentProperty.name.rawValue: "baz", UserAgentProperty.version.rawValue: "qux"] + let argumentsDictionary = [Account.key: accountDictionary, UserAgent.key: userAgentDictionary] + let expectation = self.expectation(description: "Called API client provider") + sut.apiClientProvider = { account, userAgent in + XCTAssertEqual(account.clientId, accountDictionary[AccountProperty.clientId]) + XCTAssertEqual(account.domain, accountDictionary[AccountProperty.domain]) + XCTAssertEqual(userAgent.name, userAgentDictionary[UserAgentProperty.name]) + XCTAssertEqual(userAgent.version, userAgentDictionary[UserAgentProperty.version]) + expectation.fulfill() + return SpyAuthentication() + } + sut.handle(FlutterMethodCall(methodName: methodName, arguments: argumentsDictionary)) { _ in } + wait(for: [expectation]) + } + + // MARK: CredentialsManagerMethodHandlerProvider + + func testCallsMethodHandlerProvider() { + let methodName = CredentialsManagerHandler.Method.save.rawValue + let expectation = self.expectation(description: "Called method handler provider") + sut.methodHandlerProvider = { method, _ in + XCTAssertTrue(method.rawValue == methodName) + expectation.fulfill() + return SpyMethodHandler() + } + sut.handle(FlutterMethodCall(methodName: methodName, arguments: arguments())) { _ in } + wait(for: [expectation]) + } + + func testDoesNotCallMethodHandlerProviderWhenMethodIsUnsupported() { + let expectation = self.expectation(description: "Did not call method handler provider") + sut.methodHandlerProvider = { _, _ in + XCTFail("called method handler provider") + return SpyMethodHandler() + } + sut.handle(FlutterMethodCall(methodName: "foo", arguments: arguments())) { result in + XCTAssertEqual(result as? NSObject, FlutterMethodNotImplemented) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testReturnsMethodHandlers() { + var expectations: [XCTestExpectation] = [] + let methodHandlers: [CredentialsManagerHandler.Method: MethodHandler.Type] = [ + .save: CredentialsManagerSaveMethodHandler.self, + .hasValid: CredentialsManagerHasValidMethodHandler.self, + .get: CredentialsManagerGetMethodHandler.self, + .clear: CredentialsManagerClearMethodHandler.self + ] + methodHandlers.forEach { method, methodHandler in + let methodCall = FlutterMethodCall(methodName: method.rawValue, arguments: arguments()) + let expectation = self.expectation(description: "Returned \(methodHandler)") + expectations.append(expectation) + sut.methodHandlerProvider = { method, client in + let result = CredentialsManagerHandler().methodHandlerProvider(method, client) + XCTAssertTrue(type(of: result) == methodHandler) + expectation.fulfill() + return result + } + sut.handle(methodCall) { _ in } + } + wait(for: expectations) + } +} + +// MARK: - Method Handlers + +extension CredentialsManagerHandlerTests { + func testCallsMethodHandlers() { + var expectations: [XCTestExpectation] = [] + CredentialsManagerHandler.Method.allCases.forEach { method in + let arguments: [String: Any] = arguments() + let expectation = self.expectation(description: "\(method.rawValue) handler call") + expectations.append(expectation) + let methodCall = FlutterMethodCall(methodName: method.rawValue, arguments: arguments) + let spy = SpyMethodHandler() + sut.methodHandlerProvider = { _, _ in + return spy + } + sut.handle(methodCall) { _ in + XCTAssertTrue(spy.argumentsValue == arguments) + expectation.fulfill() + } + } + wait(for: expectations) + } +} + +// MARK: - Helpers + +extension CredentialsManagerHandlerTests { + override func arguments() -> [String: Any] { + return [ + Account.key: [AccountProperty.clientId.rawValue: "", AccountProperty.domain.rawValue: ""], + UserAgent.key: [UserAgentProperty.name.rawValue: "", UserAgentProperty.version.rawValue: ""] + ] + } +} diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift new file mode 100644 index 00000000..9b0fbfbb --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift @@ -0,0 +1,70 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +fileprivate typealias Argument = CredentialsManagerHasValidMethodHandler.Argument + +class CredentialsManagerHasValidMethodHandlerTests: XCTestCase { + var spy: SpyCredentialsStorage! + var sut: CredentialsManagerHasValidMethodHandler! + + override func setUpWithError() throws { + spy = SpyCredentialsStorage() + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + sut = CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager) + } +} + +// MARK: - Required Arguments Error + +extension CredentialsManagerHasValidMethodHandlerTests { + func testProducesErrorWhenRequiredArgumentIsMissing() { + let argument = Argument.minTtl + let expectation = self.expectation(description: "\(argument.rawValue) is missing") + sut.handle(with: arguments(without: argument)) { result in + assert(result: result, isError: .requiredArgumentMissing(argument.rawValue)) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Logout Result + +extension CredentialsManagerHasValidMethodHandlerTests { + func testCallsSDKHasValidMethod() { + sut.handle(with: arguments()) { _ in } + XCTAssertTrue(spy.calledGetEntry) + } + + func testProducesTrueWithValidCredentials() { + let credentials = Credentials(expiresIn: Date(timeIntervalSinceNow: 3600)) + let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) + let expectation = self.expectation(description: "Produced true") + spy.getEntryReturnValue = data + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, true) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesFalseWithNoValidCredentials() { + let expectation = self.expectation(description: "Produced false") + spy.getEntryReturnValue = nil + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, false) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Helpers + +extension CredentialsManagerHasValidMethodHandlerTests { + override func arguments() -> [String: Any] { + return [Argument.minTtl.rawValue: 0] + } +} diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift new file mode 100644 index 00000000..14cf4538 --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift @@ -0,0 +1,76 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +fileprivate typealias Argument = CredentialsManagerSaveMethodHandler.Argument + +class CredentialsManagerSaveMethodHandlerTests: XCTestCase { + var spy: SpyCredentialsStorage! + var sut: CredentialsManagerSaveMethodHandler! + + override func setUpWithError() throws { + spy = SpyCredentialsStorage() + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + sut = CredentialsManagerSaveMethodHandler(credentialsManager: credentialsManager) + } +} + +// MARK: - Required Arguments Error + +extension CredentialsManagerSaveMethodHandlerTests { + func testProducesErrorWhenRequiredArgumentIsMissing() { + let argument = Argument.credentials + let expectation = self.expectation(description: "\(argument.rawValue) is missing") + sut.handle(with: arguments(without: argument)) { result in + assert(result: result, isError: .requiredArgumentMissing(argument.rawValue)) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Logout Result + +extension CredentialsManagerSaveMethodHandlerTests { + func testCallsSDKSaveMethod() { + sut.handle(with: arguments()) { _ in } + XCTAssertTrue(spy.calledSetEntry) + } + + func testProducesTrueOnSuccess() { + let expectation = self.expectation(description: "Produced true") + spy.setEntryReturnValue = true + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, true) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testProducesFalseOnFailure() { + let expectation = self.expectation(description: "Produced false") + spy.setEntryReturnValue = false + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, false) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + +// MARK: - Helpers + +extension CredentialsManagerSaveMethodHandlerTests { + override func arguments() -> [String: Any] { + let credentials: [String: Any] = [ + CredentialsProperty.accessToken.rawValue: "", + CredentialsProperty.idToken.rawValue: "", + CredentialsProperty.refreshToken.rawValue: "", + CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, + CredentialsProperty.scopes.rawValue: [], + CredentialsProperty.tokenType.rawValue: "" + ] + return [Argument.credentials.rawValue: credentials] + } +} diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift new file mode 100644 index 00000000..5805e814 --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift @@ -0,0 +1,29 @@ +import Auth0 + +// MARK: - Auth0.swift Spies + +class SpyCredentialsStorage: CredentialsStorage { + var getEntryReturnValue: Data? + var setEntryReturnValue = true + var deleteEntryReturnValue = true + + var calledGetEntry = false + var calledSetEntry = false + var calledDeleteEntry = false + + func getEntry(forKey key: String) -> Data? { + self.calledGetEntry = true + print("called get entry: \(self.calledGetEntry)") + return self.getEntryReturnValue + } + + func setEntry(_ data: Data, forKey key: String) -> Bool { + self.calledSetEntry = true + return self.setEntryReturnValue + } + + func deleteEntry(forKey key: String) -> Bool { + self.calledDeleteEntry = true + return self.deleteEntryReturnValue + } +} diff --git a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift index cbf9fae3..c2a631a0 100644 --- a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift +++ b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift @@ -44,22 +44,87 @@ extension ExtensionsTests { } } +// MARK: - Credentials+initFromDictionary + +extension ExtensionsTests { + func testMapsRequiredPropertiesFromDictionary() { + let values: [String: Any] = [ + CredentialsProperty.accessToken.rawValue: "accessToken", + CredentialsProperty.idToken.rawValue: testIdToken, + CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, + CredentialsProperty.scopes.rawValue: [], + CredentialsProperty.tokenType.rawValue: "tokenType" + ] + let credentials = Credentials(from: values) + XCTAssertNotNil(credentials) + XCTAssertEqual(values[CredentialsProperty.accessToken] as? String, credentials?.accessToken) + XCTAssertEqual(values[CredentialsProperty.idToken] as? String, credentials?.idToken) + XCTAssertEqual(values[CredentialsProperty.expiresAt] as? String, credentials?.expiresIn.asISO8601String) + XCTAssertEqual(values[CredentialsProperty.tokenType] as? String, credentials?.tokenType) + XCTAssertNil(credentials?.scope) + } + + func testMapsRefreshTokenFromDictionary() { + let values: [String: Any] = [ + CredentialsProperty.accessToken.rawValue: "", + CredentialsProperty.idToken.rawValue: testIdToken, + CredentialsProperty.refreshToken.rawValue: "refreshToken", + CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, + CredentialsProperty.scopes.rawValue: [], + CredentialsProperty.tokenType.rawValue: "" + ] + let credentials = Credentials(from: values) + XCTAssertNotNil(credentials?.refreshToken) + XCTAssertEqual(values[CredentialsProperty.refreshToken] as? String, credentials?.refreshToken) + } + + func testMapsScopeFromDictionary() { + let values: [String: Any] = [ + CredentialsProperty.accessToken.rawValue: "", + CredentialsProperty.idToken.rawValue: testIdToken, + CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, + CredentialsProperty.scopes.rawValue: ["foo", "bar"], + CredentialsProperty.tokenType.rawValue: "" + ] + let credentials = Credentials(from: values) + XCTAssertNotNil(credentials?.scope) + XCTAssertEqual(values[CredentialsProperty.scopes] as? [String], + credentials?.scope?.split(separator: " ").map(String.init)) + } + + func testFailsToMapCredentialsFromDictionaryWithInvalidExpiresAt() { + let values: [String: Any] = [ + CredentialsProperty.accessToken.rawValue: "", + CredentialsProperty.idToken.rawValue: testIdToken, + CredentialsProperty.scopes.rawValue: [], + CredentialsProperty.tokenType.rawValue: "" + ] + let credentials = Credentials(from: values) + XCTAssertNil(credentials?.scope) + } +} + // MARK: - Credentials+asDictionary extension ExtensionsTests { - func testMapsRequiredCredentialsProperties() { + func testMapsRequiredPropertiesToDictionary() { let idToken = "eyJhbGciOiJIUzI1NiJ9.e30.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo" - let credentials = Credentials(accessToken: "accessToken", idToken: idToken, expiresIn: Date()) + let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", + idToken: idToken, + expiresIn: Date()) let values = try! credentials.asDictionary() XCTAssertEqual(credentials.accessToken, values[CredentialsProperty.accessToken] as? String) XCTAssertEqual(credentials.idToken, values[CredentialsProperty.idToken] as? String) XCTAssertEqual(credentials.expiresIn.asISO8601String, values[CredentialsProperty.expiresAt] as? String) + XCTAssertEqual(credentials.tokenType, values[CredentialsProperty.tokenType] as? String) XCTAssertTrue([] == values[CredentialsProperty.scopes] as? [String]) XCTAssertTrue([:] == values[CredentialsProperty.userProfile] as? [String: Any]) } - func testMapsCredentialsRefreshToken() { + func testMapsRefreshTokenIntoDictionary() { let credentials = Credentials(accessToken: "", + tokenType: "", idToken: testIdToken, refreshToken: "refreshToken", expiresIn: Date()) @@ -68,16 +133,26 @@ extension ExtensionsTests { XCTAssertEqual(credentials.refreshToken, values[CredentialsProperty.refreshToken] as? String) } - func testMapsCredentialsScope() { - let credentials = Credentials(accessToken: "", idToken: testIdToken, expiresIn: Date(), scope: "foo bar") + func testMapsCredentialsScopeIntoDictionary() { + let credentials = Credentials(accessToken: "", + tokenType: "", + idToken: testIdToken, + expiresIn: Date(), + scope: "foo bar") let values = try! credentials.asDictionary() XCTAssertNotNil(credentials.scope) XCTAssertEqual(credentials.scope?.split(separator: " ").map(String.init), values[CredentialsProperty.scopes] as? [String]) } - func testMapsUserProfile() { - let credentials = Credentials(accessToken: "", idToken: testIdToken, expiresIn: Date()) + func testFailsToMapCredentialsWithMalformedIdTokenToDictionary() { + let idToken = "foo" + let credentials = Credentials(accessToken: "", tokenType: "", idToken: idToken, expiresIn: Date()) + XCTAssertThrowsError(try credentials.asDictionary(), HandlerError.idTokenDecodingFailed.message) + } + + func testMapsUserProfileToDictionary() { + let credentials = Credentials(accessToken: "", tokenType: "", idToken: testIdToken, expiresIn: Date()) let values = try! credentials.asDictionary() let jwt = try! decode(jwt: credentials.idToken) let userProfile = UserInfo(json: jwt.body)?.asDictionary() diff --git a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift index 224705ce..8b0fe050 100644 --- a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift @@ -25,7 +25,7 @@ extension WebAuthHandlerTests { extension WebAuthHandlerTests { func testProducesErrorWhenArgumentsAreMissing() { - let expectation = expectation(description: "arguments are missing") + let expectation = self.expectation(description: "Arguments are missing") sut.handle(FlutterMethodCall(methodName: "", arguments: nil)) { result in assert(result: result, isError: .argumentsMissing) expectation.fulfill() @@ -34,7 +34,7 @@ extension WebAuthHandlerTests { } func testProducesErrorWhenAccountIsMissing() { - let expectation = expectation(description: "account is missing") + let expectation = self.expectation(description: "account is missing") sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: Account.key))) { result in assert(result: result, isError: .accountMissing) expectation.fulfill() @@ -43,7 +43,7 @@ extension WebAuthHandlerTests { } func testProducesErrorWhenUserAgentIsMissing() { - let expectation = expectation(description: "userAgent is missing") + let expectation = self.expectation(description: "userAgent is missing") sut.handle(FlutterMethodCall(methodName: "", arguments: arguments(without: UserAgent.key))) { result in assert(result: result, isError: .userAgentMissing) expectation.fulfill() @@ -63,7 +63,7 @@ extension WebAuthHandlerTests { let accountDictionary = [AccountProperty.clientId.rawValue: "foo", AccountProperty.domain.rawValue: "bar"] let userAgentDictionary = [UserAgentProperty.name.rawValue: "baz", UserAgentProperty.version.rawValue: "qux"] let argumentsDictionary = [Account.key: accountDictionary, UserAgent.key: userAgentDictionary] - let expectation = self.expectation(description: "called client provider") + let expectation = self.expectation(description: "Called client provider") sut.clientProvider = { account, userAgent in XCTAssertEqual(account.clientId, accountDictionary[AccountProperty.clientId]) XCTAssertEqual(account.domain, accountDictionary[AccountProperty.domain]) @@ -80,7 +80,7 @@ extension WebAuthHandlerTests { func testCallsMethodHandlerProvider() { let methodName = WebAuthHandler.Method.login.rawValue - let expectation = self.expectation(description: "called method handler provider") + let expectation = self.expectation(description: "Called method handler provider") sut.methodHandlerProvider = { method, _ in XCTAssertTrue(method.rawValue == methodName) expectation.fulfill() @@ -91,7 +91,7 @@ extension WebAuthHandlerTests { } func testDoesNotCallMethodHandlerProviderWhenMethodIsUnsupported() { - let expectation = self.expectation(description: "did not call method handler provider") + let expectation = self.expectation(description: "Did not call method handler provider") sut.methodHandlerProvider = { _, _ in XCTFail("called method handler provider") return SpyMethodHandler() @@ -111,7 +111,7 @@ extension WebAuthHandlerTests { ] methodHandlers.forEach { method, methodHandler in let methodCall = FlutterMethodCall(methodName: method.rawValue, arguments: arguments()) - let expectation = self.expectation(description: "returned \(methodHandler)") + let expectation = self.expectation(description: "Returned \(methodHandler)") expectations.append(expectation) sut.methodHandlerProvider = { method, client in let result = WebAuthHandler().methodHandlerProvider(method, client) diff --git a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginHandlerTests.swift b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift similarity index 98% rename from auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginHandlerTests.swift rename to auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift index fa6c31f3..75359539 100644 --- a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift @@ -6,10 +6,11 @@ import Auth0 fileprivate typealias Argument = WebAuthLoginMethodHandler.Argument class WebAuthLoginHandlerTests: XCTestCase { - let spy = SpyWebAuth() + var spy: SpyWebAuth! var sut: WebAuthLoginMethodHandler! override func setUpWithError() throws { + spy = SpyWebAuth() sut = WebAuthLoginMethodHandler(client: spy) } } @@ -185,6 +186,7 @@ extension WebAuthLoginHandlerTests { func testProducesCredentials() { let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", idToken: testIdToken, refreshToken: "refreshToken", expiresIn: Date(), diff --git a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutHandlerTests.swift b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutMethodHandlerTests.swift similarity index 88% rename from auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutHandlerTests.swift rename to auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutMethodHandlerTests.swift index 62f15624..648ed21e 100644 --- a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLogoutMethodHandlerTests.swift @@ -4,10 +4,11 @@ import Auth0 @testable import auth0_flutter class WebAuthLogoutHandlerTests: XCTestCase { - let spy = SpyWebAuth() + var spy: SpyWebAuth! var sut: WebAuthLogoutMethodHandler! override func setUpWithError() throws { + spy = SpyWebAuth() sut = WebAuthLogoutMethodHandler(client: spy) } } @@ -25,7 +26,7 @@ extension WebAuthLogoutHandlerTests { } func testDoesNotAddReturnToWhenNil() { - sut.handle(with: [:]) { _ in } + sut.handle(with: arguments()) { _ in } XCTAssertNil(spy.redirectURLValue) } } @@ -34,14 +35,14 @@ extension WebAuthLogoutHandlerTests { extension WebAuthLogoutHandlerTests { func testCallsSDKLogoutMethod() { - sut.handle(with: [:]) { _ in } + sut.handle(with: arguments()) { _ in } XCTAssertTrue(spy.calledLogout) } func testProducesNilValue() { let expectation = self.expectation(description: "Produced nil value") spy.logoutResult = .success(()) - sut.handle(with: [:]) { result in + sut.handle(with: arguments()) { result in XCTAssertNil(result) expectation.fulfill() } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift index 45c8dc1b..832e429d 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift @@ -1,10 +1,10 @@ -import Foundation import Flutter import Auth0 struct CredentialsManagerClearMethodHandler: MethodHandler { + let credentialsManager: CredentialsManager func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { - callback(nil) + callback(credentialsManager.clear()) } } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift new file mode 100644 index 00000000..df3046d8 --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift @@ -0,0 +1,21 @@ +import Flutter +import Auth0 + +extension FlutterError { + convenience init(from credentialsManagerError: CredentialsManagerError) { + var code: String + switch credentialsManagerError { + case .noCredentials: code = "NO_CREDENTIALS" + case .noRefreshToken: code = "NO_REFRESH_TOKEN" + case .renewFailed: code = "RENEW_FAILED" + case .biometricsFailed: code = "BIOMETRICS_FAILED" + case .revokeFailed: code = "REVOKE_FAILED" + case .largeMinTTL: code = "LARGE_MIN_TTL" + default: code = "UNKNOWN" + } + + self.init(code: code, + message: String(describing: credentialsManagerError), + details: credentialsManagerError.details) + } +} diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift new file mode 100644 index 00000000..685a70d5 --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift @@ -0,0 +1,33 @@ +import Flutter +import Auth0 + +struct CredentialsManagerGetMethodHandler: MethodHandler { + enum Argument: String { + case scopes + case minTtl + case parameters + } + + let credentialsManager: CredentialsManager + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + guard let scopes = arguments[Argument.scopes] as? [String] else { + return callback(FlutterError(from: .requiredArgumentMissing(Argument.scopes.rawValue))) + } + guard let minTTL = arguments[Argument.minTtl] as? Int else { + return callback(FlutterError(from: .requiredArgumentMissing(Argument.minTtl.rawValue))) + } + guard let parameters = arguments[Argument.parameters] as? [String: Any] else { + return callback(FlutterError(from: .requiredArgumentMissing(Argument.parameters.rawValue))) + } + + credentialsManager.credentials(withScope: scopes.isEmpty ? nil : scopes.asSpaceSeparatedString, + minTTL: minTTL, + parameters: parameters) { + switch $0 { + case let .success(credentials): callback(result(from: credentials)) + case let .failure(error): callback(FlutterError(from: error)) + } + } + } +} diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift index 39df93f0..eab34d8a 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift @@ -3,14 +3,20 @@ import Auth0 // MARK: - Providers -typealias CredentialsManagerMethodHandlerProvider = (_ method: CredentialsManagerHandler.Method) -> MethodHandler +// typealias CredentialsManagerProvider = (_ authentication: Authentication) -> CredentialsManager +typealias CredentialsManagerMethodHandlerProvider = (_ method: CredentialsManagerHandler.Method, + _ credentialsManager: CredentialsManager) -> MethodHandler // MARK: - Credentials Manager Handler public class CredentialsManagerHandler: NSObject, FlutterPlugin { enum Method: String, CaseIterable { + case save = "credentialsManager#saveCredentials" + case hasValid = "credentialsManager#hasValidCredentials" + case get = "credentialsManager#getCredentials" case clear = "credentialsManager#clearCredentials" } + private static let channelName = "auth0.com/auth0_flutter/credentials_manager" public static func register(with registrar: FlutterPluginRegistrar) { @@ -20,9 +26,24 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { registrar.addMethodCallDelegate(handler, channel: channel) } - var methodHandlerProvider: CredentialsManagerMethodHandlerProvider = { method in + var apiClientProvider: AuthAPIClientProvider = { account, userAgent in + var client = Auth0.authentication(clientId: account.clientId, domain: account.domain) + client.using(inLibrary: userAgent.name, version: userAgent.version) + return client + } + + /* + var credentialsManagerProvider: CredentialsManagerProvider = { apiClient in + return CredentialsManager(authentication: apiClient) + } + */ + + var methodHandlerProvider: CredentialsManagerMethodHandlerProvider = { method, credentialsManager in switch method { - case .clear: return CredentialsManagerClearMethodHandler() + case .save: return CredentialsManagerSaveMethodHandler(credentialsManager: credentialsManager) + case .hasValid: return CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager) + case .get: return CredentialsManagerGetMethodHandler(credentialsManager: credentialsManager) + case .clear: return CredentialsManagerClearMethodHandler(credentialsManager: credentialsManager) } } @@ -42,7 +63,9 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { return result(FlutterMethodNotImplemented) } - let methodHandler = methodHandlerProvider(method) + let apiClient = apiClientProvider(account, userAgent) + let credentialsManager = CredentialsManager(authentication: apiClient) + let methodHandler = methodHandlerProvider(method, credentialsManager) methodHandler.handle(with: arguments, callback: result) } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift new file mode 100644 index 00000000..ece8fbec --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift @@ -0,0 +1,18 @@ +import Flutter +import Auth0 + +struct CredentialsManagerHasValidMethodHandler: MethodHandler { + enum Argument: String { + case minTtl + } + + let credentialsManager: CredentialsManager + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + guard let minTTL = arguments[Argument.minTtl] as? Int else { + return callback(FlutterError(from: .requiredArgumentMissing(Argument.minTtl.rawValue))) + } + + callback(credentialsManager.hasValid(minTTL: minTTL)) + } +} diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift new file mode 100644 index 00000000..ce04a589 --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift @@ -0,0 +1,19 @@ +import Flutter +import Auth0 + +struct CredentialsManagerSaveMethodHandler: MethodHandler { + enum Argument: String { + case credentials + } + + let credentialsManager: CredentialsManager + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + guard let credentialsDictionary = arguments[Argument.credentials] as? [String: Any], + let credentials = Credentials(from: credentialsDictionary) else { + return callback(FlutterError(from: .requiredArgumentMissing(Argument.credentials.rawValue))) + } + + callback(credentialsManager.store(credentials: credentials)) + } +} diff --git a/auth0_flutter/ios/Classes/Extensions.swift b/auth0_flutter/ios/Classes/Extensions.swift index a5d672fa..fb881f85 100644 --- a/auth0_flutter/ios/Classes/Extensions.swift +++ b/auth0_flutter/ios/Classes/Extensions.swift @@ -20,8 +20,14 @@ extension Dictionary where Key == String { } extension Date { + static var iso8601Formatter: ISO8601DateFormatter { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + return formatter + } + var asISO8601String: String { - return ISO8601DateFormatter().string(from: self) + return Date.iso8601Formatter.string(from: self) } } @@ -64,6 +70,25 @@ extension Auth0APIError { } extension Credentials { + convenience init?(from dictionary: [String: Any]) { + guard let accessToken = dictionary[CredentialsProperty.accessToken] as? String, + let idToken = dictionary[CredentialsProperty.idToken] as? String, + let expiresAt = dictionary[CredentialsProperty.expiresAt] as? String, + let expiresIn = Date.iso8601Formatter.date(from: expiresAt), + let scopes = dictionary[CredentialsProperty.scopes] as? [String], + let tokenType = dictionary[CredentialsProperty.tokenType] as? String else { + return nil + } + + self.init(accessToken: accessToken, + tokenType: tokenType, + idToken: idToken, + refreshToken: dictionary[CredentialsProperty.refreshToken] as? String, + expiresIn: expiresIn, + scope: scopes.isEmpty ? nil : scopes.asSpaceSeparatedString, + recoveryCode: nil) + } + func asDictionary() throws -> [String: Any] { let jwt = try decode(jwt: idToken) var data: [String: Any] = [ @@ -72,7 +97,7 @@ extension Credentials { CredentialsProperty.expiresAt.rawValue: expiresIn.asISO8601String, CredentialsProperty.scopes.rawValue: scope?.split(separator: " ").map(String.init) ?? [], CredentialsProperty.userProfile.rawValue: UserInfo(json: jwt.body)?.asDictionary() ?? [:], - CredentialsProperty.tokenType.rawValue: tokenType, + CredentialsProperty.tokenType.rawValue: tokenType ] data[CredentialsProperty.refreshToken] = refreshToken return data diff --git a/auth0_flutter/ios/Classes/Enums.swift b/auth0_flutter/ios/Classes/HandlerError.swift similarity index 58% rename from auth0_flutter/ios/Classes/Enums.swift rename to auth0_flutter/ios/Classes/HandlerError.swift index 1d5931ea..d014c6a0 100644 --- a/auth0_flutter/ios/Classes/Enums.swift +++ b/auth0_flutter/ios/Classes/HandlerError.swift @@ -1,38 +1,4 @@ -enum CredentialsProperty: String, CaseIterable { - case accessToken - case idToken - case userProfile - case refreshToken - case expiresAt - case scopes - case tokenType -} - -enum UserInfoProperty: String, CaseIterable { - case sub - case name - case givenName = "given_name" - case familyName = "family_name" - case middleName = "middle_name" - case nickname - case preferredUsername = "preferred_username" - case profile - case picture - case website - case email - case emailVerified = "email_verified" - case gender - case birthdate - case zoneinfo - case locale - case phoneNumber = "phone_number" - case phoneNumberVerified = "phone_number_verified" - case address - case updatedAt = "updated_at" - case customClaims = "custom_claims" -} - -enum HandlerError { +enum HandlerError: Error { case argumentsMissing case accountMissing case userAgentMissing diff --git a/auth0_flutter/ios/Classes/Account.swift b/auth0_flutter/ios/Classes/Models.swift similarity index 51% rename from auth0_flutter/ios/Classes/Account.swift rename to auth0_flutter/ios/Classes/Models.swift index 036844b0..900c36ca 100644 --- a/auth0_flutter/ios/Classes/Account.swift +++ b/auth0_flutter/ios/Classes/Models.swift @@ -19,3 +19,24 @@ struct Account { self.domain = domain } } + +enum UserAgentProperty: String { + case name + case version +} + +struct UserAgent { + let name: String + let version: String + + static let key = "_userAgent" + + init?(from dictionary: [String: String]) { + guard let name = dictionary[UserAgentProperty.name], let version = dictionary[UserAgentProperty.version] else { + return nil + } + + self.name = name + self.version = version + } +} diff --git a/auth0_flutter/ios/Classes/Properties.swift b/auth0_flutter/ios/Classes/Properties.swift new file mode 100644 index 00000000..c9d84f38 --- /dev/null +++ b/auth0_flutter/ios/Classes/Properties.swift @@ -0,0 +1,33 @@ +enum CredentialsProperty: String, CaseIterable { + case accessToken + case idToken + case userProfile + case refreshToken + case expiresAt + case scopes + case tokenType +} + +enum UserInfoProperty: String, CaseIterable { + case sub + case name + case givenName = "given_name" + case familyName = "family_name" + case middleName = "middle_name" + case nickname + case preferredUsername = "preferred_username" + case profile + case picture + case website + case email + case emailVerified = "email_verified" + case gender + case birthdate + case zoneinfo + case locale + case phoneNumber = "phone_number" + case phoneNumberVerified = "phone_number_verified" + case address + case updatedAt = "updated_at" + case customClaims = "custom_claims" +} diff --git a/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift b/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift index 8591acbd..3f25ab19 100644 --- a/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift +++ b/auth0_flutter/ios/Classes/SwiftAuth0FlutterPlugin.swift @@ -1,7 +1,9 @@ import Flutter public class SwiftAuth0FlutterPlugin: NSObject, FlutterPlugin { - static var handlers: [FlutterPlugin.Type] = [WebAuthHandler.self, AuthAPIHandler.self, CredentialsManagerHandler.self] + static var handlers: [FlutterPlugin.Type] = [WebAuthHandler.self, + AuthAPIHandler.self, + CredentialsManagerHandler.self] public static func register(with registrar: FlutterPluginRegistrar) { handlers.forEach { $0.register(with: registrar) } diff --git a/auth0_flutter/ios/Classes/UserAgent.swift b/auth0_flutter/ios/Classes/UserAgent.swift deleted file mode 100644 index 11d47104..00000000 --- a/auth0_flutter/ios/Classes/UserAgent.swift +++ /dev/null @@ -1,20 +0,0 @@ -enum UserAgentProperty: String { - case name - case version -} - -struct UserAgent { - let name: String - let version: String - - static let key = "_userAgent" - - init?(from dictionary: [String: String]) { - guard let name = dictionary[UserAgentProperty.name], let version = dictionary[UserAgentProperty.version] else { - return nil - } - - self.name = name - self.version = version - } -} diff --git a/auth0_flutter/ios/Classes/WebAuth/WebAuthHandler.swift b/auth0_flutter/ios/Classes/WebAuth/WebAuthHandler.swift index e5d335ee..6376eecd 100644 --- a/auth0_flutter/ios/Classes/WebAuth/WebAuthHandler.swift +++ b/auth0_flutter/ios/Classes/WebAuth/WebAuthHandler.swift @@ -13,6 +13,7 @@ public class WebAuthHandler: NSObject, FlutterPlugin { case login = "webAuth#login" case logout = "webAuth#logout" } + private static let channelName = "auth0.com/auth0_flutter/web_auth" public static func register(with registrar: FlutterPluginRegistrar) { From 6bb373fb9c0dae7d2ba070664bb7d4a9d4552137 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Wed, 6 Jul 2022 13:17:15 +0200 Subject: [PATCH 07/38] Implement RequireAuthentication for SecureCredentialsManager (#107) * Implement RequireAuthentication for SecureCredentialsManager * Fix pin-lock due to credentialsManager set to null * Remove unused import --- .../Auth0FlutterAuthMethodCallHandler.kt | 5 +- .../auth0/auth0_flutter/Auth0FlutterPlugin.kt | 8 +- .../Auth0FlutterWebAuthMethodCallHandler.kt | 6 +- .../CredentialsManagerMethodCallHandler.kt | 28 ++++-- .../auth0/auth0_flutter/utils/requestCodes.kt | 5 ++ .../Auth0FlutterAuthMethodCallHandlerTest.kt | 2 +- ...uth0FlutterWebAuthMethodCallHandlerTest.kt | 2 +- ...CredentialsManagerMethodCallHandlerTest.kt | 86 +++++++++++++++++-- 8 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/requestCodes.kt diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt index c27093b2..1ed6e300 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt @@ -1,18 +1,17 @@ package com.auth0.auth0_flutter -import android.content.Context +import android.app.Activity import androidx.annotation.NonNull import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.auth0_flutter.request_handlers.api.* import com.auth0.auth0_flutter.request_handlers.MethodCallRequest -import com.auth0.auth0_flutter.request_handlers.web_auth.WebAuthRequestHandler import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result class Auth0FlutterAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { - lateinit var context: Context; + lateinit var activity: Activity; override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { var requestHandler = requestHandlers.find { it.method == call.method }; diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt index a45ca096..8b50341f 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt @@ -62,9 +62,11 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { } override fun onAttachedToActivity(binding: ActivityPluginBinding) { - webAuthCallHandler.context = binding.activity - authCallHandler.context = binding.activity - credentialsManagerCallHandler.context = binding.activity + webAuthCallHandler.activity = binding.activity + authCallHandler.activity = binding.activity + credentialsManagerCallHandler.activity = binding.activity + + binding.addActivityResultListener(credentialsManagerCallHandler); } override fun onDetachedFromActivityForConfigChanges() { diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt index 4074fedb..fc8bb93a 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt @@ -1,6 +1,6 @@ package com.auth0.auth0_flutter -import android.content.Context +import android.app.Activity import androidx.annotation.NonNull import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import com.auth0.auth0_flutter.request_handlers.web_auth.WebAuthRequestHandler @@ -9,7 +9,7 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result class Auth0FlutterWebAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { - lateinit var context: Context + lateinit var activity: Activity override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { var requestHandler = requestHandlers.find { it.method == call.method }; @@ -17,7 +17,7 @@ class Auth0FlutterWebAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { - lateinit var context: Context +class CredentialsManagerMethodCallHandler(private val requestHandlers: List) : MethodCallHandler, PluginRegistry.ActivityResultListener { + lateinit var activity: Activity; + + var credentialsManager: SecureCredentialsManager? = null; override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { var requestHandler = requestHandlers.find { it.method == call.method }; @@ -22,19 +26,25 @@ class CredentialsManagerMethodCallHandler(private val requestHandlers: List?; if (localAuthentication != null) { - val title = localAuthentication["title"] as String?; - val description = localAuthentication["description"] as String?; - // credentialsManager.requireAuthentication(context as Activity, 111, title, description); + val title = localAuthentication["title"]; + val description = localAuthentication["description"]; + credentialsManager.requireAuthentication(activity, RequestCodes.AUTH_REQ_CODE, title, description); } - requestHandler.handle(credentialsManager, context, request, result); + requestHandler.handle(credentialsManager, activity, request, result); } else { result.notImplemented() } } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { + return credentialsManager?.checkAuthenticationResult(requestCode, resultCode) ?: true; + } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/requestCodes.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/requestCodes.kt new file mode 100644 index 00000000..66262684 --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/requestCodes.kt @@ -0,0 +1,5 @@ +package com.auth0.auth0_flutter.utils + +object RequestCodes { + const val AUTH_REQ_CODE = 111 +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandlerTest.kt index 4d105588..a0bb7268 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandlerTest.kt @@ -33,7 +33,7 @@ class Auth0FlutterAuthMethodCallHandlerTest { val handler = Auth0FlutterAuthMethodCallHandler(requestHandlers) val mockResult = mock() - handler.context = mock() + handler.activity = mock() handler.onMethodCall(MethodCall(method, arguments), mockResult) onResult(mockResult) diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt index 1db5b341..827878f4 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt @@ -33,7 +33,7 @@ class Auth0FlutterWebAuthMethodCallHandlerTest { val handler = Auth0FlutterWebAuthMethodCallHandler(handlers) val mockResult = mock() - handler.context = mock() + handler.activity = mock() handler.onMethodCall(MethodCall(method, arguments), mockResult) onResult(mockResult) diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt index 89e8bf40..614eb09d 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt @@ -1,5 +1,6 @@ package com.auth0.auth0_flutter +import android.app.Activity import android.content.Context import android.content.SharedPreferences import com.auth0.auth0_flutter.request_handlers.api.ApiRequestHandler @@ -33,13 +34,13 @@ class CredentialsManagerMethodCallHandlerTest { method: String, arguments: HashMap = defaultArguments, requestHandlers: List, - context: Context? = null, + activity: Activity? = null, onResult: (Result) -> Unit, ) { val handler = CredentialsManagerMethodCallHandler(requestHandlers) val mockResult = mock() - handler.context = if (context === null) mock() else context; + handler.activity = if (activity === null) mock() else activity; handler.onMethodCall(MethodCall(method, arguments), mockResult) onResult(mockResult) @@ -63,6 +64,75 @@ class CredentialsManagerMethodCallHandlerTest { } } + @Test + fun `handler should not call credentialsManager requireAuthentication`() { + val clearCredentialsHandler = mock(); + + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + + val activity: Activity = mock(); + val mockPrefs: SharedPreferences = mock() + + `when`(activity.getSharedPreferences(any(), any())) + .thenReturn(mockPrefs); + + val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) + val mockResult = mock() + + handler.activity = activity; + handler.credentialsManager = mock(); + + handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments), mockResult) + + verify(handler.credentialsManager, never())?.requireAuthentication(any(), any(), any(), any()) + } + + @Test + fun `handler should call credentialsManager requireAuthentication`() { + val clearCredentialsHandler = mock(); + + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + + val activity: Activity = mock(); + val mockPrefs: SharedPreferences = mock() + + `when`(activity.getSharedPreferences(any(), any())) + .thenReturn(mockPrefs); + + val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) + val mockResult = mock() + + handler.activity = activity; + handler.credentialsManager = mock(); + + handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments + hashMapOf("localAuthentication" to hashMapOf("title" to "test", "description" to "test description"))), mockResult) + + verify(handler.credentialsManager)?.requireAuthentication(eq(activity), eq(111), eq("test"), eq("test description")) + } + + @Test + fun `handler should call credentialsManager requireAuthentication with default values`() { + val clearCredentialsHandler = mock(); + + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + + val activity: Activity = mock(); + val mockPrefs: SharedPreferences = mock() + + `when`(activity.getSharedPreferences(any(), any())) + .thenReturn(mockPrefs); + + val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) + val mockResult = mock() + + handler.activity = activity; + handler.credentialsManager = mock(); + + handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments + hashMapOf("localAuthentication" to hashMapOf())), mockResult) + + verify(handler.credentialsManager)?.requireAuthentication(eq(activity), eq(111), isNull(), isNull()) + } + @Test fun `handler should only run the correct handler`() { val clearCredentialsHandler = mock(); @@ -71,15 +141,15 @@ class CredentialsManagerMethodCallHandlerTest { `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); `when`(hasValidCredentialsHandler.method).thenReturn("credentialsManager#hasValidCredentials"); - val context: Context = mock(); - val mockPrefs: SharedPreferences = mock() + val activity: Activity = mock(); + val mockPrefs: SharedPreferences = mock(); - `when`(context.getSharedPreferences(any(), any())) + `when`(activity.getSharedPreferences(any(), any())) .thenReturn(mockPrefs); - runCallHandler(clearCredentialsHandler.method, context = context, requestHandlers = listOf(clearCredentialsHandler, hasValidCredentialsHandler)) { _ -> - verify(clearCredentialsHandler).handle(any(), eq(context), any(), any()) - verify(hasValidCredentialsHandler, times(0)).handle(any(), eq(context), any(), any()) + runCallHandler(clearCredentialsHandler.method, activity = activity, requestHandlers = listOf(clearCredentialsHandler, hasValidCredentialsHandler)) { _ -> + verify(clearCredentialsHandler).handle(any(), eq(activity), any(), any()) + verify(hasValidCredentialsHandler, times(0)).handle(any(), eq(activity), any(), any()) } } } From c0dd2b4859744fdb29c37f0263d3217c1ab61100 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Fri, 8 Jul 2022 14:16:15 +0100 Subject: [PATCH 08/38] chore: update ClearCredentials test assertion to be consistent with HasValidCredentials (#109) --- .../credentials_manager/ClearCredentialsRequestHandlerTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt index f9129c61..837fa65d 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt @@ -61,7 +61,6 @@ class ClearCredentialsRequestHandlerTest { val captor = argumentCaptor() verify(mockResult).success(captor.capture()) - assert(captor.firstValue) - + assertThat(captor.firstValue, equalTo(true)) } } From 281295068964aec69bd1457cb2f298ef65473c75 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 8 Jul 2022 11:28:39 -0300 Subject: [PATCH 09/38] Add implementation of local authentication for iOS [SDK-3460] (#108) * Add iOS Credentials Manager implementation * Use `self` to call expectation method * Configure date formatter to use fractional seconds * Add implementation of local authentication for iOS * Simplify required properties logic * Remove `Requireable` protocol * Use a default value for the title on iOS * Use dictionary of optional strings * Turn `credentialsManager` into a getter * Use dictionary of optional strings in the handler * Remove unused import * Remove extra whitspace * Fix section name in MARK comments * Remove `webAuthentication().credentials()` --- .../Tests/AuthAPI/AuthAPIHandlerTests.swift | 8 +- ...ntialsManagerClearMethodHandlerTests.swift | 2 +- ...dentialsManagerGetMethodHandlerTests.swift | 2 +- .../CredentialsManagerHandlerTests.swift | 139 +++++++++++++++++- ...alsManagerHasValidMethodHandlerTests.swift | 4 +- ...entialsManagerSaveMethodHandlerTests.swift | 2 +- .../Tests/WebAuth/WebAuthHandlerTests.swift | 8 +- .../CredentialsManagerHandler.swift | 18 +-- .../CredentialsManagerModels.swift | 19 +++ auth0_flutter/ios/Classes/HandlerError.swift | 2 +- auth0_flutter/lib/auth0_flutter.dart | 2 +- .../lib/src/credentials_manager.dart | 7 +- auth0_flutter/lib/src/web_authentication.dart | 21 +-- .../test/web_authentication_test.dart | 64 -------- .../method_channel_credentials_manager.dart | 2 - .../options/local_authentication_options.dart | 17 ++- .../lib/src/request/request.dart | 11 +- .../web-auth/id_token_validation_config.dart | 2 +- 18 files changed, 202 insertions(+), 128 deletions(-) create mode 100644 auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerModels.swift diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift index e90cbe20..73e64fbc 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIHandlerTests.swift @@ -102,7 +102,11 @@ extension AuthAPIHandlerTests { } wait(for: [expectation]) } +} + +// MARK: - Method Handlers +extension AuthAPIHandlerTests { func testReturnsMethodHandlers() { var expectations: [XCTestExpectation] = [] let methodHandlers: [AuthAPIHandler.Method: MethodHandler.Type] = [ @@ -126,11 +130,7 @@ extension AuthAPIHandlerTests { } wait(for: expectations) } -} - -// MARK: - Method Handlers -extension AuthAPIHandlerTests { func testCallsMethodHandlers() { var expectations: [XCTestExpectation] = [] AuthAPIHandler.Method.allCases.forEach { method in diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift index f7d3680e..e6f99c9d 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerClearMethodHandlerTests.swift @@ -14,7 +14,7 @@ class CredentialsManagerClearMethodHandlerTests: XCTestCase { } } -// MARK: - Logout Result +// MARK: - Clear Result extension CredentialsManagerClearMethodHandlerTests { func testCallsSDKClearMethod() { diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift index ac0a76ed..158b7764 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift @@ -32,7 +32,7 @@ extension CredentialsManagerGetMethodHandlerTests { } } -// MARK: - Logout Result +// MARK: - Get Result extension CredentialsManagerGetMethodHandlerTests { func testCallsSDKGetMethod() { diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift index 8fd6f5de..bfae8e07 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift @@ -1,6 +1,6 @@ import XCTest -import Auth0 +@testable import Auth0 @testable import auth0_flutter class CredentialsManagerHandlerTests: XCTestCase { @@ -25,7 +25,7 @@ extension CredentialsManagerHandlerTests { extension CredentialsManagerHandlerTests { func testProducesErrorWhenArgumentsAreMissing() { - let expectation = expectation(description: "arguments are missing") + let expectation = expectation(description: "Arguments are missing") sut.handle(FlutterMethodCall(methodName: "", arguments: nil)) { result in assert(result: result, isError: .argumentsMissing) expectation.fulfill() @@ -52,6 +52,133 @@ extension CredentialsManagerHandlerTests { } } +// MARK: - Arguments + +extension CredentialsManagerHandlerTests { + + // MARK: title (local authentication) + + func testUsesDefaultLocalAuthenticationTitle() { + let expectation = expectation(description: "Default local authentication title is used") + var credentialsManager: CredentialsManager? + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [:] + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value))) { _ in + XCTAssertEqual(credentialsManager?.bioAuth?.title, "Please authenticate to continue") + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testSetsLocalAuthenticationTitle() { + let expectation = expectation(description: "Local authentication title is set") + var credentialsManager: CredentialsManager? + let title = "foo" + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [LocalAuthenticationProperty.title.rawValue: title] + let methodCall = FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value)) + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(methodCall) { _ in + XCTAssertEqual(credentialsManager?.bioAuth?.title, title) + expectation.fulfill() + } + wait(for: [expectation]) + } + + // MARK: cancelTitle (local authentication) + + func testAddsCancelTitle() { + let expectation = expectation(description: "Local authentication cancelTitle is added") + var credentialsManager: CredentialsManager? + let cancelTitle = "foo" + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [ + LocalAuthenticationProperty.title.rawValue: "", + LocalAuthenticationProperty.cancelTitle.rawValue: cancelTitle + ] + let methodCall = FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value)) + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(methodCall) { _ in + XCTAssertEqual(credentialsManager?.bioAuth?.cancelTitle, cancelTitle) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testDoesNotAddCancelTitleWhenNil() { + let expectation = expectation(description: "Local authentication cancelTitle is not added") + var credentialsManager: CredentialsManager? + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [LocalAuthenticationProperty.title.rawValue: ""] + let methodCall = FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value)) + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(methodCall) { _ in + XCTAssertNil(credentialsManager?.bioAuth?.cancelTitle) + expectation.fulfill() + } + wait(for: [expectation]) + } + + // MARK: fallbackTitle (local authentication) + + func testAddsFallbackTitle() { + let expectation = expectation(description: "Local authentication fallbackTitle is added") + var credentialsManager: CredentialsManager? + let fallbackTitle = "foo" + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [ + LocalAuthenticationProperty.title.rawValue: "", + LocalAuthenticationProperty.fallbackTitle.rawValue: fallbackTitle + ] + let methodCall = FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value)) + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(methodCall) { _ in + XCTAssertEqual(credentialsManager?.bioAuth?.fallbackTitle, fallbackTitle) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testDoesNotAddFallbackTitleWhenNil() { + let expectation = expectation(description: "Local authentication fallbackTitle is not added") + var credentialsManager: CredentialsManager? + let method = CredentialsManagerHandler.Method.save.rawValue + let key = LocalAuthentication.key + let value: [String: String?] = [LocalAuthenticationProperty.title.rawValue: ""] + let methodCall = FlutterMethodCall(methodName: method, arguments: arguments(withKey: key, value: value)) + sut.methodHandlerProvider = { _, instance in + credentialsManager = instance + return SpyMethodHandler() + } + sut.handle(methodCall) { _ in + XCTAssertNil(credentialsManager?.bioAuth?.fallbackTitle) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + // MARK: - Providers extension CredentialsManagerHandlerTests { @@ -102,7 +229,11 @@ extension CredentialsManagerHandlerTests { } wait(for: [expectation]) } +} +// MARK: - Method Handlers + +extension CredentialsManagerHandlerTests { func testReturnsMethodHandlers() { var expectations: [XCTestExpectation] = [] let methodHandlers: [CredentialsManagerHandler.Method: MethodHandler.Type] = [ @@ -125,11 +256,7 @@ extension CredentialsManagerHandlerTests { } wait(for: expectations) } -} -// MARK: - Method Handlers - -extension CredentialsManagerHandlerTests { func testCallsMethodHandlers() { var expectations: [XCTestExpectation] = [] CredentialsManagerHandler.Method.allCases.forEach { method in diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift index 9b0fbfbb..a2af7f6e 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift @@ -30,10 +30,10 @@ extension CredentialsManagerHasValidMethodHandlerTests { } } -// MARK: - Logout Result +// MARK: - Has Valid Result extension CredentialsManagerHasValidMethodHandlerTests { - func testCallsSDKHasValidMethod() { + func testCallsSDKGetMethod() { sut.handle(with: arguments()) { _ in } XCTAssertTrue(spy.calledGetEntry) } diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift index 14cf4538..cd6a9bb0 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSaveMethodHandlerTests.swift @@ -30,7 +30,7 @@ extension CredentialsManagerSaveMethodHandlerTests { } } -// MARK: - Logout Result +// MARK: - Save Result extension CredentialsManagerSaveMethodHandlerTests { func testCallsSDKSaveMethod() { diff --git a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift index 8b0fe050..998f7195 100644 --- a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthHandlerTests.swift @@ -102,7 +102,11 @@ extension WebAuthHandlerTests { } wait(for: [expectation]) } +} + +// MARK: - Method Handlers +extension WebAuthHandlerTests { func testReturnsMethodHandlers() { var expectations: [XCTestExpectation] = [] let methodHandlers: [WebAuthHandler.Method: MethodHandler.Type] = [ @@ -123,11 +127,7 @@ extension WebAuthHandlerTests { } wait(for: expectations) } -} - -// MARK: - Method Handlers -extension WebAuthHandlerTests { func testCallsMethodHandlers() { var expectations: [XCTestExpectation] = [] WebAuthHandler.Method.allCases.forEach { method in diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift index eab34d8a..146ca739 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHandler.swift @@ -3,7 +3,6 @@ import Auth0 // MARK: - Providers -// typealias CredentialsManagerProvider = (_ authentication: Authentication) -> CredentialsManager typealias CredentialsManagerMethodHandlerProvider = (_ method: CredentialsManagerHandler.Method, _ credentialsManager: CredentialsManager) -> MethodHandler @@ -32,12 +31,6 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { return client } - /* - var credentialsManagerProvider: CredentialsManagerProvider = { apiClient in - return CredentialsManager(authentication: apiClient) - } - */ - var methodHandlerProvider: CredentialsManagerMethodHandlerProvider = { method, credentialsManager in switch method { case .save: return CredentialsManagerSaveMethodHandler(credentialsManager: credentialsManager) @@ -64,9 +57,16 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { } let apiClient = apiClientProvider(account, userAgent) - let credentialsManager = CredentialsManager(authentication: apiClient) - let methodHandler = methodHandlerProvider(method, credentialsManager) + var credentialsManager = CredentialsManager(authentication: apiClient) + if let localAuthenticationDictionary = arguments[LocalAuthentication.key] as? [String: String?] { + let localAuthentication = LocalAuthentication(from: localAuthenticationDictionary) + credentialsManager.enableBiometrics(withTitle: localAuthentication.title, + cancelTitle: localAuthentication.cancelTitle, + fallbackTitle: localAuthentication.fallbackTitle) + } + + let methodHandler = methodHandlerProvider(method, credentialsManager) methodHandler.handle(with: arguments, callback: result) } } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerModels.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerModels.swift new file mode 100644 index 00000000..390b11cb --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerModels.swift @@ -0,0 +1,19 @@ +enum LocalAuthenticationProperty: String, CaseIterable { + case title + case cancelTitle + case fallbackTitle +} + +struct LocalAuthentication { + let title: String + let cancelTitle: String? + let fallbackTitle: String? + + static let key = "localAuthentication" + + init(from dictionary: [String: String?]) { + self.title = dictionary[LocalAuthenticationProperty.title] as? String ?? "Please authenticate to continue" + self.cancelTitle = dictionary[LocalAuthenticationProperty.cancelTitle] as? String + self.fallbackTitle = dictionary[LocalAuthenticationProperty.fallbackTitle] as? String + } +} diff --git a/auth0_flutter/ios/Classes/HandlerError.swift b/auth0_flutter/ios/Classes/HandlerError.swift index d014c6a0..0479a5ca 100644 --- a/auth0_flutter/ios/Classes/HandlerError.swift +++ b/auth0_flutter/ios/Classes/HandlerError.swift @@ -1,4 +1,4 @@ -enum HandlerError: Error { +enum HandlerError { case argumentsMissing case accountMissing case userAgentMissing diff --git a/auth0_flutter/lib/auth0_flutter.dart b/auth0_flutter/lib/auth0_flutter.dart index 7c2192f8..749631e0 100644 --- a/auth0_flutter/lib/auth0_flutter.dart +++ b/auth0_flutter/lib/auth0_flutter.dart @@ -64,7 +64,7 @@ class Auth0 { /// by setting [customCredentialsManager]. /// In case you want to opt-out of using any [CredentialsManager] alltogether, set [useCredentialsManager] to `false`. /// If you want to use biometrics or pass-phrase when using the [DefaultCredentialsManager], set [localAuthentication]` to an instance of [LocalAuthenticationOptions]. - /// Note however that this settings has no effect when specifying a [customCredentialsManager] + /// Note however that this setting has no effect when specifying a [customCredentialsManager]. WebAuthentication webAuthentication({ final bool useCredentialsManager = true, final LocalAuthenticationOptions? localAuthentication, diff --git a/auth0_flutter/lib/src/credentials_manager.dart b/auth0_flutter/lib/src/credentials_manager.dart index 1745ad12..54f00e2e 100644 --- a/auth0_flutter/lib/src/credentials_manager.dart +++ b/auth0_flutter/lib/src/credentials_manager.dart @@ -22,15 +22,14 @@ abstract class CredentialsManager { class DefaultCredentialsManager extends CredentialsManager { final Account _account; final UserAgent _userAgent; - late LocalAuthenticationOptions? _localAuthentication; + final LocalAuthenticationOptions? _localAuthentication; DefaultCredentialsManager( this._account, this._userAgent, { final LocalAuthenticationOptions? localAuthentication - }) { - _localAuthentication = localAuthentication; - } + }) + : _localAuthentication = localAuthentication; /// Retrieves the credentials from the storage and refreshes them if they have already expired. /// diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index 6a8dff26..0c5c5951 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -22,7 +22,7 @@ class WebAuthentication { final UserAgent _userAgent; final CredentialsManager? _credentialsManager; - CredentialsManager? credentialsManager() => _credentialsManager; + CredentialsManager? get credentialsManager => _credentialsManager; WebAuthentication(this._account, this._userAgent, this._credentialsManager); @@ -86,25 +86,6 @@ class WebAuthentication { await _credentialsManager?.clear(); } - /// Retrieves the Credentials for the current user. Calls the [CredentialsManager] when available, returns `null` if not. - /// - /// Change the minimum time in seconds that the access token should last before expiration by setting the [minTtl]. - /// Use the [scopes] parameter to set the scope to request for the access token. If `null` is passed, the previous scope will be kept. - /// Use the [parameters] parameter to send additional parameters in the request to refresh expired credentials. - Future credentials({ - final int minTtl = 0, - final Set scopes = const {}, - final Map parameters = const {}, - }) async { - final credentials = await _credentialsManager?.get( - minTtl: minTtl, - scopes: scopes, - parameters: parameters, - ); - - return credentials; - } - WebAuthRequest _createWebAuthRequest( final TOptions options) => diff --git a/auth0_flutter/test/web_authentication_test.dart b/auth0_flutter/test/web_authentication_test.dart index 30c50f87..59192696 100644 --- a/auth0_flutter/test/web_authentication_test.dart +++ b/auth0_flutter/test/web_authentication_test.dart @@ -166,70 +166,6 @@ void main() { }); }); - group('credentials', () { - test('calls the credentials manager', () async { - when(mockedCMPlatform.getCredentials(any)) - .thenAnswer((final _) async => TestPlatform.loginResult); - - await Auth0('test-domain', 'test-clientId') - .webAuthentication() - .credentials( - minTtl: 30, - scopes: {'a', 'b'}, - parameters: {'test': 'test-value'}); - - final verificationResult = - verify(mockedCMPlatform.getCredentials(captureAny)).captured.single - as CredentialsManagerRequest; - expect(verificationResult.account.domain, 'test-domain'); - expect(verificationResult.account.clientId, 'test-clientId'); - expect(verificationResult.options?.minTtl, 30); - expect(verificationResult.options?.scopes, {'a', 'b'}); - expect(verificationResult.options?.parameters['test'], 'test-value'); - }); - - test('returns null when opted out of credential manager', () async { - when(mockedCMPlatform.getCredentials(any)) - .thenAnswer((final _) async => TestPlatform.loginResult); - - final result = await Auth0('test-domain', 'test-clientId') - .webAuthentication(useCredentialsManager: false) - .credentials( - minTtl: 30, - scopes: {'a', 'b'}, - parameters: {'test': 'test-value'}); - - expect(result, null); - }); - - test('uses custom Credential Manager on success', () async { - when(mockedCMPlatform.getCredentials(any)) - .thenAnswer((final _) async => TestPlatform.loginResult); - final mockCm = MockCredentialsManager(); - when(mockCm.get( - minTtl: anyNamed('minTtl'), - scopes: anyNamed('scopes'), - parameters: anyNamed('parameters'))) - .thenAnswer((final _) async => TestPlatform.loginResult); - - await Auth0('test-domain', 'test-clientId') - .webAuthentication(customCredentialsManager: mockCm) - .credentials( - minTtl: 30, - scopes: {'a', 'b'}, - parameters: {'test': 'test-value'}); - - // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager - verifyNever(mockedCMPlatform.getCredentials(any)); - - verify(mockCm.get( - minTtl: anyNamed('minTtl'), - scopes: anyNamed('scopes'), - parameters: anyNamed('parameters'))) - .called(1); - }); - }); - group('logout', () { test('calls the platform to logout', () async { when(mockedPlatform.logout(any)).thenAnswer((final _) async => {}); diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart index fe0c6149..e1a18601 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; -import '../auth/api_exception.dart'; import '../credentials.dart'; import '../request/request.dart'; import '../request/request_options.dart'; @@ -66,7 +65,6 @@ class MethodChannelCredentialsManager extends CredentialsManagerPlatform { final TResult? result; try { result = await _channel.invokeMethod(method, request.toMap()); - } on PlatformException catch (e) { throw CredentialsManagerException.fromPlatformException(e); } diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart index 143fd973..3d1a65d0 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart @@ -1,6 +1,17 @@ +/// Configuration settings for local authentication prompts. class LocalAuthenticationOptions { - String? title; - String? description; + /// Title to display on the local authentication prompt. Defaults to **Please authenticate to continue** on iOS, `null` on Android. + final String? title; - LocalAuthenticationOptions({this.title, this.description}); + /// (Android only): Description to display on the local authentication prompt. + final String? description; + + /// (iOS only): Cancel message to display on the local authentication prompt. + final String? cancelTitle; + + /// (iOS only): Fallback message to display on the local authentication prompt after a failed match. + final String? fallbackTitle; + + LocalAuthenticationOptions( + {this.title, this.description, this.cancelTitle, this.fallbackTitle}); } diff --git a/auth0_flutter_platform_interface/lib/src/request/request.dart b/auth0_flutter_platform_interface/lib/src/request/request.dart index 53472c5c..5de996d2 100644 --- a/auth0_flutter_platform_interface/lib/src/request/request.dart +++ b/auth0_flutter_platform_interface/lib/src/request/request.dart @@ -18,7 +18,8 @@ abstract class BaseRequest { class CredentialsManagerRequest extends BaseRequest { - late LocalAuthenticationOptions? localAuthentication; + final LocalAuthenticationOptions? localAuthentication; + CredentialsManagerRequest({ required final Account account, final TOptions? options, @@ -33,9 +34,11 @@ class CredentialsManagerRequest ..addAll({ 'localAuthentication': { 'title': localAuthentication?.title, - 'description': localAuthentication?.description - } - }); + 'description': localAuthentication?.description, + 'cancelTitle': localAuthentication?.cancelTitle, + 'fallbackTitle': localAuthentication?.fallbackTitle + } + }); } else { return super.toMap(); } diff --git a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart index 9c244f71..2d095f62 100644 --- a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart +++ b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart @@ -1,6 +1,6 @@ /// Configuration settings for ID token validation. class IdTokenValidationConfig { - /// The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms. + /// The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. Defaults to 60 seconds. final int? leeway; /// The issuer to be used for validation of JWTs. Defaults to the domain used to when calling [Auth0.new]. From f17011c60d2517a3071161b753936a2fc1ddabc5 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 8 Jul 2022 22:42:04 -0300 Subject: [PATCH 10/38] Add `offline_access` to the default scope [SDK-3435] (#112) --- auth0_flutter/README.md | 4 ++-- .../api/LoginApiRequestHandler.kt | 4 +--- .../web_auth/LoginWebAuthRequestHandler.kt | 4 +--- .../LoginWebAuthRequestHandlerTest.kt | 18 ++++++++-------- .../api/LoginApiRequestHandlerTest.kt | 4 ++-- ...ginUsernameOrEmailMethodHandlerTests.swift | 4 ++-- .../CredentialsManagerSpies.swift | 1 - .../WebAuthLoginMethodHandlerTests.swift | 4 ++-- ...APILoginUsernameOrEmailMethodHandler.swift | 2 +- .../WebAuth/WebAuthLoginMethodHandler.swift | 8 +++---- auth0_flutter/lib/src/authentication_api.dart | 11 +++++++--- auth0_flutter/lib/src/web_authentication.dart | 9 ++++++-- .../test/authentication_api_test.dart | 7 ++++--- .../test/web_authentication_test.dart | 21 +++++++++++++++++++ 14 files changed, 63 insertions(+), 38 deletions(-) diff --git a/auth0_flutter/README.md b/auth0_flutter/README.md index 346b714e..c77d0ce9 100644 --- a/auth0_flutter/README.md +++ b/auth0_flutter/README.md @@ -223,7 +223,7 @@ final result = await auth0.webAuthentication.login();
Add scope values - Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile` and `email`. Regardless of the values specified, `openid` is always included. + Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile`, `email`, and `offline_access`. Regardless of the values specified, `openid` is always included. ```dart final result = await auth0.webAuthentication @@ -371,7 +371,7 @@ final result = await auth0.api.login(
Add scope values - Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile` and `email`. Regardless of the values specified, `openid` is always included. + Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile`, `email`, and `offline_access`. Regardless of the values specified, `openid` is always included. ```dart final result = await auth0.api.login( diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt index ae510287..73457885 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt @@ -37,9 +37,7 @@ class LoginApiRequestHandler : ApiRequestHandler { ); val scopes = args.getOrDefault("scopes", arrayListOf()) as ArrayList<*> - if (scopes.isNotEmpty()) { - loginBuilder.setScope(scopes.joinToString(separator = " ")) - } + loginBuilder.setScope(scopes.joinToString(separator = " ")) if (args.getOrDefault("audience", null) is String) { loginBuilder.setAudience(args["audience"] as String) diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt index 51588191..a8f67300 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt @@ -25,9 +25,7 @@ class LoginWebAuthRequestHandler(private val builderResolver: (MethodCallRequest val args = request.data val scopes = args.getOrDefault("scopes", arrayListOf()) as ArrayList<*> - if (scopes.isNotEmpty()) { - builder.withScope(scopes.joinToString(separator = " ")) - } + builder.withScope(scopes.joinToString(separator = " ")) if (args.getOrDefault("audience", null) is String) { builder.withAudience(args["audience"] as String) diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt index f0f26198..28d5cdf7 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt @@ -24,7 +24,7 @@ import java.util.* @RunWith(RobolectricTestRunner::class) class LoginWebAuthRequestHandlerTest { private val defaultCredentials = - Credentials(JwtTestUtils.createJwt(), "test", "", null, Date(), "openid profile email") + Credentials(JwtTestUtils.createJwt(), "test", "", null, Date(), "openid profile email offline_access") fun runRequestHandler( args: HashMap = hashMapOf(), @@ -61,11 +61,11 @@ class LoginWebAuthRequestHandlerTest { assertThat(map["idToken"], equalTo(defaultCredentials.idToken)) assertThat(map["accessToken"], equalTo(defaultCredentials.accessToken)) assertThat(map["expiresAt"], equalTo(formattedDate)) - assertThat(map["scopes"], equalTo(listOf("openid", "profile", "email"))) + assertThat(map["scopes"], equalTo(listOf("openid", "profile", "email", "offline_access"))) assertThat(map["refreshToken"], nullValue()) }) - verify(builder, never()).withScope(any()) + verify(builder).withScope("") verify(builder, never()).withAudience(any()) verify(builder, never()).withOrganization(any()) verify(builder, never()).withInvitationUrl(any()) @@ -81,31 +81,31 @@ class LoginWebAuthRequestHandlerTest { @Test fun `handler should request scopes from the SDK when specified`() { val args = hashMapOf( - "scopes" to arrayListOf("openid", "profile", "email") + "scopes" to arrayListOf("openid", "profile", "email", "offline_access") ) runRequestHandler(args) { _, builder -> - verify(builder).withScope("openid profile email") + verify(builder).withScope("openid profile email offline_access") } } @Test - fun `handler should not add scopes when given an empty array`() { + fun `handler should add an empty scope when given an empty array`() { val args = hashMapOf( "scopes" to arrayListOf() ) runRequestHandler(args) { _, builder -> - verify(builder, never()).withScope(anyOrNull()) + verify(builder).withScope("") } } @Test - fun `handler should not add scopes when not specified`() { + fun `handler should add an empty scope when not specified`() { val args = hashMapOf() runRequestHandler(args) { _, builder -> - verify(builder, never()).withScope(anyOrNull()) + verify(builder).withScope("") } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt index 723fce11..99a742f2 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt @@ -201,7 +201,7 @@ class LoginApiRequestHandlerTest { } @Test - fun `should not configure the scopes when not provided`() { + fun `should configure an empty scope when not provided`() { val options = hashMapOf( "usernameOrEmail" to "test-email", "password" to "test-pass", @@ -223,7 +223,7 @@ class LoginApiRequestHandlerTest { mockResult ); - verify(mockLoginBuilder, times(0)).setScope(any()); + verify(mockLoginBuilder).setScope(""); } @Test diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift index 40fad5d5..2baa7a6a 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandlerTests.swift @@ -85,9 +85,9 @@ extension AuthAPILoginUsernameOrEmailMethodHandlerTests { XCTAssertEqual(spy.arguments["scope"] as? String, value.asSpaceSeparatedString) } - func testAddsDefaultScopesWhenEmpty() { + func testAddsEmptyScopeWhenEmpty() { sut.handle(with: arguments(withKey: Argument.scopes, value: [])) { _ in } - XCTAssertEqual(spy.arguments["scope"] as? String, Auth0.defaultScope) + XCTAssertEqual(spy.arguments["scope"] as? String, "") } // MARK: audience diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift index 5805e814..ded4867a 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerSpies.swift @@ -13,7 +13,6 @@ class SpyCredentialsStorage: CredentialsStorage { func getEntry(forKey key: String) -> Data? { self.calledGetEntry = true - print("called get entry: \(self.calledGetEntry)") return self.getEntryReturnValue } diff --git a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift index 75359539..778cbb18 100644 --- a/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/WebAuth/WebAuthLoginMethodHandlerTests.swift @@ -79,9 +79,9 @@ extension WebAuthLoginHandlerTests { XCTAssertEqual(spy.scopeValue, value.asSpaceSeparatedString) } - func testDoesNotAddScopesWhenEmpty() { + func testAddsEmptyScopeWhenEmpty() { sut.handle(with: arguments(withKey: Argument.scopes, value: [])) { _ in } - XCTAssertNil(spy.scopeValue) + XCTAssertEqual(spy.scopeValue, "") } // MARK: audience diff --git a/auth0_flutter/ios/Classes/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandler.swift b/auth0_flutter/ios/Classes/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandler.swift index 58d30888..9140a8d2 100644 --- a/auth0_flutter/ios/Classes/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandler.swift +++ b/auth0_flutter/ios/Classes/AuthAPI/AuthAPILoginUsernameOrEmailMethodHandler.swift @@ -37,7 +37,7 @@ struct AuthAPILoginUsernameOrEmailMethodHandler: MethodHandler { password: password, realmOrConnection: connectionOrRealm, audience: audience, - scope: scopes.isEmpty ? Auth0.defaultScope : scopes.asSpaceSeparatedString) + scope: scopes.asSpaceSeparatedString) .parameters(parameters) .start { switch $0 { diff --git a/auth0_flutter/ios/Classes/WebAuth/WebAuthLoginMethodHandler.swift b/auth0_flutter/ios/Classes/WebAuth/WebAuthLoginMethodHandler.swift index c4232448..f6f54006 100644 --- a/auth0_flutter/ios/Classes/WebAuth/WebAuthLoginMethodHandler.swift +++ b/auth0_flutter/ios/Classes/WebAuth/WebAuthLoginMethodHandler.swift @@ -29,11 +29,9 @@ struct WebAuthLoginMethodHandler: MethodHandler { return callback(FlutterError(from: .requiredArgumentMissing(Argument.parameters.rawValue))) } - var webAuth = client.parameters(parameters) - - if !scopes.isEmpty { - webAuth = webAuth.scope(scopes.asSpaceSeparatedString) - } + var webAuth = client + .scope(scopes.asSpaceSeparatedString) + .parameters(parameters) if useEphemeralSession { webAuth = webAuth.useEphemeralSession() diff --git a/auth0_flutter/lib/src/authentication_api.dart b/auth0_flutter/lib/src/authentication_api.dart index 73efe390..f711b330 100644 --- a/auth0_flutter/lib/src/authentication_api.dart +++ b/auth0_flutter/lib/src/authentication_api.dart @@ -38,7 +38,7 @@ class AuthenticationApi { /// ## Notes /// /// * [audience] relates to the API Identifier you want to reference in your access tokens (see [API settings](https://auth0.com/docs/get-started/apis/api-settings)) - /// * [scopes] defaults to `openid profile email` + /// * [scopes] defaults to `openid profile email offline_access` /// * [parameters] can be used to sent through custom parameters to the endpoint to be picked up in a Rule or Action. /// /// ## Usage example @@ -55,7 +55,12 @@ class AuthenticationApi { required final String password, required final String connectionOrRealm, final String? audience, - final Set scopes = const {}, + final Set scopes = const { + 'openid', + 'profile', + 'email', + 'offline_access' + }, final Map parameters = const {}, }) => Auth0FlutterAuthPlatform.instance @@ -134,7 +139,7 @@ class AuthenticationApi { /// usernameOrEmail: 'my@email.com', /// password: 'my_password' /// connectionOrRealm: 'Username-Password-Authentication', - /// scopes: {'openid', 'profile', 'email', 'offline_access'} + /// scopes: {'openid', 'profile', 'email', 'phone', 'offline_access'} /// }); /// /// if (result.refreshToken != null) { diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index 0c5c5951..ddff7473 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -39,13 +39,18 @@ class WebAuthentication { /// * (iOS only): [useEphemeralSession] controls whether shared persistent storage is used for cookies. [Read more on the effects this setting has](https://github.com/auth0/Auth0.swift/blob/master/FAQ.md#1-how-can-i-disable-the-login-alert-box) /// * (Android only): specify [scheme] if you're using a custom URL scheme for your app. This value must match the value used to configure the `auth0Scheme` manifest placeholder, for the Redirect intent filter to work /// * [audience] relates to the API Identifier you want to reference in your access tokens (see [API settings](https://auth0.com/docs/get-started/apis/api-settings)) - /// * [scopes] defaults to `openid profile email`. You can override these scopes, but `openid` is always requested regardless of this setting. + /// * [scopes] defaults to `openid profile email offline_access`. You can override these scopes, but `openid` is always requested regardless of this setting. /// * Arbitrary [parameters] can be specified and then picked up in a custom Auth0 [Action](https://auth0.com/docs/customize/actions) or [Rule](https://auth0.com/docs/customize/rules). /// * If you want to log into a specific organization, provide the [organizationId]. Provide [invitationUrl] if a user has been invited to /// join an organization. Future login({ final String? audience, - final Set scopes = const {}, + final Set scopes = const { + 'openid', + 'profile', + 'email', + 'offline_access' + }, final String? redirectUrl, final String? organizationId, final String? invitationUrl, diff --git a/auth0_flutter/test/authentication_api_test.dart b/auth0_flutter/test/authentication_api_test.dart index 753010b2..8bb71189 100644 --- a/auth0_flutter/test/authentication_api_test.dart +++ b/auth0_flutter/test/authentication_api_test.dart @@ -21,7 +21,7 @@ class TestPlatform extends Mock 'idToken': 'idToken', 'refreshToken': 'refreshToken', 'expiresAt': DateTime.now().toIso8601String(), - 'scopes': ['a'], + 'scopes': ['a', 'b'], 'userProfile': {'sub': '123', 'name': 'John Doe'}, 'tokenType': 'Bearer' }); @@ -31,7 +31,7 @@ class TestPlatform extends Mock 'idToken': 'idToken', 'refreshToken': 'refreshToken', 'expiresAt': DateTime.now().toIso8601String(), - 'scopes': ['a'], + 'scopes': ['a', 'b'], 'userProfile': {'sub': '123', 'name': 'John Doe'}, 'tokenType': 'Bearer' }); @@ -131,7 +131,8 @@ void main() { .captured .single as ApiRequest; // ignore: inference_failure_on_collection_literal - expect(verificationResult.options.scopes, []); + expect(verificationResult.options.scopes, + ['openid', 'profile', 'email', 'offline_access']); // ignore: inference_failure_on_collection_literal expect(verificationResult.options.parameters, {}); expect(result, TestPlatform.loginResult); diff --git a/auth0_flutter/test/web_authentication_test.dart b/auth0_flutter/test/web_authentication_test.dart index 59192696..19be8d94 100644 --- a/auth0_flutter/test/web_authentication_test.dart +++ b/auth0_flutter/test/web_authentication_test.dart @@ -148,6 +148,27 @@ void main() { verificationResult.accessToken, TestPlatform.loginResult.accessToken); }); + test('set scope and parameters to default value when omitted', () async { + when(mockedPlatform.login(any)) + .thenAnswer((final _) async => TestPlatform.loginResult); + when(mockedCMPlatform.saveCredentials(any)) + .thenAnswer((final _) async => true); + + final result = await Auth0('test-domain', 'test-clientId') + .webAuthentication() + .login(); + + final verificationResult = verify(mockedPlatform.login(captureAny)) + .captured + .single as WebAuthRequest; + // ignore: inference_failure_on_collection_literal + expect(verificationResult.options.scopes, + ['openid', 'profile', 'email', 'offline_access']); + // ignore: inference_failure_on_collection_literal + expect(verificationResult.options.parameters, {}); + expect(result, TestPlatform.loginResult); + }); + test('does not use EphemeralSession by default', () async { when(mockedPlatform.login(any)) .thenAnswer((final _) async => TestPlatform.loginResult); From 74c8d8173306a4a83adb9334a90ab1f7d93f63e9 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Sat, 9 Jul 2022 19:24:19 -0300 Subject: [PATCH 11/38] Add missing assertions to Swift unit tests (#114) --- .../ios/Runner.xcodeproj/project.pbxproj | 12 +- .../example/ios/Tests/AccountTests.swift | 21 --- .../AuthAPI/AuthAPIExtensionsTests.swift | 7 +- .../CredentialsManagerHandlerTests.swift | 3 + .../example/ios/Tests/ExtensionsTests.swift | 146 +++++++++--------- .../example/ios/Tests/ModelsTests.swift | 37 +++++ .../example/ios/Tests/UserAgentTests.swift | 21 --- 7 files changed, 121 insertions(+), 126 deletions(-) delete mode 100644 auth0_flutter/example/ios/Tests/AccountTests.swift create mode 100644 auth0_flutter/example/ios/Tests/ModelsTests.swift delete mode 100644 auth0_flutter/example/ios/Tests/UserAgentTests.swift diff --git a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 375df610..ad071b59 100644 --- a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -34,8 +34,7 @@ 5C59DA8B2809386B00365CDB /* AuthAPIExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA8A2809386B00365CDB /* AuthAPIExtensionsTests.swift */; }; 5C59DA8D280938BE00365CDB /* WebAuthExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA8C280938BE00365CDB /* WebAuthExtensionsTests.swift */; }; 5C59DA97280958FB00365CDB /* SmokeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C59DA96280958FB00365CDB /* SmokeTests.swift */; }; - 5CAAA4A2281A0C7D007666F1 /* AccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CAAA4A1281A0C7D007666F1 /* AccountTests.swift */; }; - 5CAAA4A4281A0E50007666F1 /* UserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CAAA4A3281A0E50007666F1 /* UserAgentTests.swift */; }; + 5CAAA4A2281A0C7D007666F1 /* ModelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CAAA4A1281A0C7D007666F1 /* ModelsTests.swift */; }; 5E38CCA5A74BB28EABC10976 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29F5DF109AAC0995DAF67FD3 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -109,8 +108,7 @@ 5C59DA8C280938BE00365CDB /* WebAuthExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthExtensionsTests.swift; sourceTree = ""; }; 5C59DA94280958FA00365CDB /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5C59DA96280958FB00365CDB /* SmokeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmokeTests.swift; sourceTree = ""; }; - 5CAAA4A1281A0C7D007666F1 /* AccountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTests.swift; sourceTree = ""; }; - 5CAAA4A3281A0E50007666F1 /* UserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentTests.swift; sourceTree = ""; }; + 5CAAA4A1281A0C7D007666F1 /* ModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelsTests.swift; sourceTree = ""; }; 5E0D97321D283DD3C2559B6B /* Pods-Runner-RunnerUITests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-RunnerUITests.profile.xcconfig"; path = "Target Support Files/Pods-Runner-RunnerUITests/Pods-Runner-RunnerUITests.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -178,8 +176,7 @@ 5C328B5127F7B11300451E70 /* WebAuth */, 5C4E65BC286D022200141449 /* CredentialsManager */, 5C335E3E27FBCD1D00EDDE3A /* SwiftAuth0FlutterPluginTests.swift */, - 5CAAA4A1281A0C7D007666F1 /* AccountTests.swift */, - 5CAAA4A3281A0E50007666F1 /* UserAgentTests.swift */, + 5CAAA4A1281A0C7D007666F1 /* ModelsTests.swift */, 5C335E4027FBD2FE00EDDE3A /* ExtensionsTests.swift */, 5C328B5627F7BFEA00451E70 /* Mocks.swift */, 5C328B4F27F7B0E600451E70 /* Utilities.swift */, @@ -584,7 +581,7 @@ 5C4E65C5286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift in Sources */, 5C328B4827F7822600451E70 /* WebAuthHandlerTests.swift in Sources */, 5C328B5327F7B12F00451E70 /* WebAuthSpies.swift in Sources */, - 5CAAA4A2281A0C7D007666F1 /* AccountTests.swift in Sources */, + 5CAAA4A2281A0C7D007666F1 /* ModelsTests.swift in Sources */, 5C59DA6527FFCF0600365CDB /* AuthAPIHandlerTests.swift in Sources */, 5C4E65C7286D24A900141449 /* CredentialsManagerSaveMethodHandlerTests.swift in Sources */, 5C59DA712807B19900365CDB /* AuthAPIRenewMethodHandlerTests.swift in Sources */, @@ -598,7 +595,6 @@ 5C335E4127FBD2FE00EDDE3A /* ExtensionsTests.swift in Sources */, 5C59DA732807B1A300365CDB /* AuthAPIResetPasswordMethodHandlerTests.swift in Sources */, 5C59DA832809214200365CDB /* AuthAPIUserInfoMethodHandlerTests.swift in Sources */, - 5CAAA4A4281A0E50007666F1 /* UserAgentTests.swift in Sources */, 5C4E65C1286D15AF00141449 /* CredentialsManagerSpies.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/auth0_flutter/example/ios/Tests/AccountTests.swift b/auth0_flutter/example/ios/Tests/AccountTests.swift deleted file mode 100644 index 55b287e8..00000000 --- a/auth0_flutter/example/ios/Tests/AccountTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -import XCTest - -@testable import auth0_flutter - -class AccountTests: XCTestCase {} - -// MARK: - Failable Initializer - -extension AccountTests { - func testReturnsNilWhenRequiredParametersAreMissing() { - let parameters: [AccountProperty] = [.clientId, .domain] - parameters.forEach { parameter in - XCTAssertNil(Account(from: [parameter.rawValue: "foo"])) - } - } - - func testReturnsInstanceWhenRequiredParametersArePresent() { - let parameters = [AccountProperty.clientId.rawValue: "foo", AccountProperty.domain.rawValue: "bar"] - XCTAssertNotNil(Account(from: parameters)) - } -} diff --git a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIExtensionsTests.swift b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIExtensionsTests.swift index 8b506b65..c6ccb9a7 100644 --- a/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIExtensionsTests.swift +++ b/auth0_flutter/example/ios/Tests/AuthAPI/AuthAPIExtensionsTests.swift @@ -4,7 +4,7 @@ import Auth0 @testable import auth0_flutter class AuthAPIExtensionsTests: XCTestCase { - func testInitializesFlutterErrorFromAuthAPIError() { + func testInitializesFlutterErrorFromAuthAPIError() throws { let errors: [AuthAPIErrorFlag: [String: Any]] = [ .isMultifactorRequired: ["code": "mfa_required"], .isMultifactorEnrollRequired: ["code": "unsupported_challenge_type"], @@ -27,9 +27,10 @@ class AuthAPIExtensionsTests: XCTestCase { for (flag, info) in errors { let error = AuthenticationError(info: info, statusCode: 400) let flutterError = FlutterError(from: error) - let flags = (flutterError.details as? [String: Any])?[AuthAPIErrorKey.errorFlags] as? [String: Bool] + let details = try XCTUnwrap(flutterError.details as? [String: Any]) + let flags = try XCTUnwrap(details[AuthAPIErrorKey.errorFlags] as? [String: Bool]) assert(flutterError: flutterError, is: error) - XCTAssertEqual(flags?[flag], true) + XCTAssertEqual(flags[flag], true) } } } diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift index bfae8e07..545da34a 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHandlerTests.swift @@ -130,6 +130,7 @@ extension CredentialsManagerHandlerTests { return SpyMethodHandler() } sut.handle(methodCall) { _ in + XCTAssertNotNil(credentialsManager?.bioAuth) XCTAssertNil(credentialsManager?.bioAuth?.cancelTitle) expectation.fulfill() } @@ -154,6 +155,7 @@ extension CredentialsManagerHandlerTests { return SpyMethodHandler() } sut.handle(methodCall) { _ in + XCTAssertNotNil(credentialsManager?.bioAuth) XCTAssertEqual(credentialsManager?.bioAuth?.fallbackTitle, fallbackTitle) expectation.fulfill() } @@ -172,6 +174,7 @@ extension CredentialsManagerHandlerTests { return SpyMethodHandler() } sut.handle(methodCall) { _ in + XCTAssertNotNil(credentialsManager?.bioAuth) XCTAssertNil(credentialsManager?.bioAuth?.fallbackTitle) expectation.fulfill() } diff --git a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift index c2a631a0..7ec88716 100644 --- a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift +++ b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift @@ -47,7 +47,7 @@ extension ExtensionsTests { // MARK: - Credentials+initFromDictionary extension ExtensionsTests { - func testMapsRequiredPropertiesFromDictionary() { + func testMapsRequiredPropertiesFromDictionary() throws { let values: [String: Any] = [ CredentialsProperty.accessToken.rawValue: "accessToken", CredentialsProperty.idToken.rawValue: testIdToken, @@ -55,16 +55,15 @@ extension ExtensionsTests { CredentialsProperty.scopes.rawValue: [], CredentialsProperty.tokenType.rawValue: "tokenType" ] - let credentials = Credentials(from: values) - XCTAssertNotNil(credentials) - XCTAssertEqual(values[CredentialsProperty.accessToken] as? String, credentials?.accessToken) - XCTAssertEqual(values[CredentialsProperty.idToken] as? String, credentials?.idToken) - XCTAssertEqual(values[CredentialsProperty.expiresAt] as? String, credentials?.expiresIn.asISO8601String) - XCTAssertEqual(values[CredentialsProperty.tokenType] as? String, credentials?.tokenType) - XCTAssertNil(credentials?.scope) + let credentials = try XCTUnwrap(Credentials(from: values)) + XCTAssertEqual(values[CredentialsProperty.accessToken] as? String, credentials.accessToken) + XCTAssertEqual(values[CredentialsProperty.idToken] as? String, credentials.idToken) + XCTAssertEqual(values[CredentialsProperty.expiresAt] as? String, credentials.expiresIn.asISO8601String) + XCTAssertEqual(values[CredentialsProperty.tokenType] as? String, credentials.tokenType) + XCTAssertNil(credentials.scope) } - func testMapsRefreshTokenFromDictionary() { + func testMapsRefreshTokenFromDictionary() throws { let values: [String: Any] = [ CredentialsProperty.accessToken.rawValue: "", CredentialsProperty.idToken.rawValue: testIdToken, @@ -73,12 +72,12 @@ extension ExtensionsTests { CredentialsProperty.scopes.rawValue: [], CredentialsProperty.tokenType.rawValue: "" ] - let credentials = Credentials(from: values) - XCTAssertNotNil(credentials?.refreshToken) - XCTAssertEqual(values[CredentialsProperty.refreshToken] as? String, credentials?.refreshToken) + let credentials = try XCTUnwrap(Credentials(from: values)) + XCTAssertNotNil(credentials.refreshToken) + XCTAssertEqual(values[CredentialsProperty.refreshToken] as? String, credentials.refreshToken) } - func testMapsScopeFromDictionary() { + func testMapsScopeFromDictionary() throws { let values: [String: Any] = [ CredentialsProperty.accessToken.rawValue: "", CredentialsProperty.idToken.rawValue: testIdToken, @@ -86,34 +85,35 @@ extension ExtensionsTests { CredentialsProperty.scopes.rawValue: ["foo", "bar"], CredentialsProperty.tokenType.rawValue: "" ] - let credentials = Credentials(from: values) - XCTAssertNotNil(credentials?.scope) + let credentials = try XCTUnwrap(Credentials(from: values)) + XCTAssertNotNil(credentials.scope) XCTAssertEqual(values[CredentialsProperty.scopes] as? [String], - credentials?.scope?.split(separator: " ").map(String.init)) + credentials.scope?.split(separator: " ").map(String.init)) } - func testFailsToMapCredentialsFromDictionaryWithInvalidExpiresAt() { + func testFailsToMapCredentialsFromDictionaryWithInvalidExpiresAt() throws { let values: [String: Any] = [ CredentialsProperty.accessToken.rawValue: "", CredentialsProperty.idToken.rawValue: testIdToken, + CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, CredentialsProperty.scopes.rawValue: [], CredentialsProperty.tokenType.rawValue: "" ] - let credentials = Credentials(from: values) - XCTAssertNil(credentials?.scope) + let credentials = try XCTUnwrap(Credentials(from: values)) + XCTAssertNil(credentials.scope) } } // MARK: - Credentials+asDictionary extension ExtensionsTests { - func testMapsRequiredPropertiesToDictionary() { + func testMapsRequiredPropertiesToDictionary() throws { let idToken = "eyJhbGciOiJIUzI1NiJ9.e30.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo" let credentials = Credentials(accessToken: "accessToken", tokenType: "tokenType", idToken: idToken, expiresIn: Date()) - let values = try! credentials.asDictionary() + let values = try credentials.asDictionary() XCTAssertEqual(credentials.accessToken, values[CredentialsProperty.accessToken] as? String) XCTAssertEqual(credentials.idToken, values[CredentialsProperty.idToken] as? String) XCTAssertEqual(credentials.expiresIn.asISO8601String, values[CredentialsProperty.expiresAt] as? String) @@ -122,24 +122,24 @@ extension ExtensionsTests { XCTAssertTrue([:] == values[CredentialsProperty.userProfile] as? [String: Any]) } - func testMapsRefreshTokenIntoDictionary() { + func testMapsRefreshTokenIntoDictionary() throws { let credentials = Credentials(accessToken: "", tokenType: "", idToken: testIdToken, refreshToken: "refreshToken", expiresIn: Date()) - let values = try! credentials.asDictionary() + let values = try credentials.asDictionary() XCTAssertNotNil(credentials.refreshToken) XCTAssertEqual(credentials.refreshToken, values[CredentialsProperty.refreshToken] as? String) } - func testMapsCredentialsScopeIntoDictionary() { + func testMapsCredentialsScopeIntoDictionary() throws { let credentials = Credentials(accessToken: "", tokenType: "", idToken: testIdToken, expiresIn: Date(), scope: "foo bar") - let values = try! credentials.asDictionary() + let values = try credentials.asDictionary() XCTAssertNotNil(credentials.scope) XCTAssertEqual(credentials.scope?.split(separator: " ").map(String.init), values[CredentialsProperty.scopes] as? [String]) @@ -151,11 +151,11 @@ extension ExtensionsTests { XCTAssertThrowsError(try credentials.asDictionary(), HandlerError.idTokenDecodingFailed.message) } - func testMapsUserProfileToDictionary() { + func testMapsUserProfileToDictionary() throws { let credentials = Credentials(accessToken: "", tokenType: "", idToken: testIdToken, expiresIn: Date()) - let values = try! credentials.asDictionary() - let jwt = try! decode(jwt: credentials.idToken) - let userProfile = UserInfo(json: jwt.body)?.asDictionary() + let values = try credentials.asDictionary() + let jwt = try decode(jwt: credentials.idToken) + let userProfile = try XCTUnwrap(UserInfo(json: jwt.body)?.asDictionary()) XCTAssertTrue(userProfile == values[CredentialsProperty.userProfile] as? [String: Any]) } } @@ -163,234 +163,234 @@ extension ExtensionsTests { // MARK: - UserInfo+asDictionary extension ExtensionsTests { - func testMapsRequiredUserInfoProperties() { - let userInfo = UserInfo(json: [UserInfoProperty.sub.rawValue: "foo"])! + func testMapsRequiredUserInfoProperties() throws { + let userInfo = try XCTUnwrap(UserInfo(json: [UserInfoProperty.sub.rawValue: "foo"])) let values = userInfo.asDictionary() XCTAssertEqual(userInfo.sub, values[UserInfoProperty.sub] as? String) XCTAssertTrue(values[UserInfoProperty.customClaims] as? [String: Any] == [:]) } - func testMapsUserInfoName() { + func testMapsUserInfoName() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.name.rawValue: "name" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.name) XCTAssertEqual(userInfo.name, values[UserInfoProperty.name] as? String) } - func testMapsUserInfoGivenName() { + func testMapsUserInfoGivenName() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.givenName.rawValue: "givenName" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.givenName) XCTAssertEqual(userInfo.givenName, values[UserInfoProperty.givenName] as? String) } - func testMapsUserInfoFamilyName() { + func testMapsUserInfoFamilyName() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.familyName.rawValue: "familyName" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.familyName) XCTAssertEqual(userInfo.familyName, values[UserInfoProperty.familyName] as? String) } - func testMapsUserInfoMiddleName() { + func testMapsUserInfoMiddleName() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.middleName.rawValue: "middleName" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.middleName) XCTAssertEqual(userInfo.middleName, values[UserInfoProperty.middleName] as? String) } - func testMapsUserInfoNickname() { + func testMapsUserInfoNickname() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.nickname.rawValue: "nickname" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.nickname) XCTAssertEqual(userInfo.nickname, values[UserInfoProperty.nickname] as? String) } - func testMapsUserInfoPreferredUsername() { + func testMapsUserInfoPreferredUsername() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.preferredUsername.rawValue: "preferredUsername" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.preferredUsername) XCTAssertEqual(userInfo.preferredUsername, values[UserInfoProperty.preferredUsername] as? String) } - func testMapsUserInfoProfile() { + func testMapsUserInfoProfile() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.profile.rawValue: "https://example.com/profile" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.profile) XCTAssertEqual(userInfo.profile?.absoluteString, values[UserInfoProperty.profile] as? String) } - func testMapsUserInfoPicture() { + func testMapsUserInfoPicture() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.picture.rawValue: "https://example.com/picture" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.picture) XCTAssertEqual(userInfo.picture?.absoluteString, values[UserInfoProperty.picture] as? String) } - func testMapsUserInfoWebsite() { + func testMapsUserInfoWebsite() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.website.rawValue: "https://example.com/website" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.website) XCTAssertEqual(userInfo.website?.absoluteString, values[UserInfoProperty.website] as? String) } - func testMapsUserInfoEmail() { + func testMapsUserInfoEmail() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.email.rawValue: "email" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.email) XCTAssertEqual(userInfo.email, values[UserInfoProperty.email] as? String) } - func testMapsUserInfoEmailVerified() { + func testMapsUserInfoEmailVerified() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.emailVerified.rawValue: true ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.emailVerified) XCTAssertEqual(userInfo.emailVerified, values[UserInfoProperty.emailVerified] as? Bool) } - func testMapsUserInfoGender() { + func testMapsUserInfoGender() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.gender.rawValue: "gender" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.gender) XCTAssertEqual(userInfo.gender, values[UserInfoProperty.gender] as? String) } - func testMapsUserInfoBirthdate() { + func testMapsUserInfoBirthdate() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.birthdate.rawValue: "birthdate" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.birthdate) XCTAssertEqual(userInfo.birthdate, values[UserInfoProperty.birthdate] as? String) } - func testMapsUserInfoZoneinfo() { + func testMapsUserInfoZoneinfo() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.zoneinfo.rawValue: "America/Los_Angeles" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.zoneinfo) XCTAssertEqual(userInfo.zoneinfo?.identifier, values[UserInfoProperty.zoneinfo] as? String) } - func testMapsUserInfoLocale() { + func testMapsUserInfoLocale() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.locale.rawValue: "en_US" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.locale) XCTAssertEqual(userInfo.locale?.identifier, values[UserInfoProperty.locale] as? String) } - func testMapsUserInfoPhoneNumber() { + func testMapsUserInfoPhoneNumber() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.phoneNumber.rawValue: "phoneNumber" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.phoneNumber) XCTAssertEqual(userInfo.phoneNumber, values[UserInfoProperty.phoneNumber] as? String) } - func testMapsUserInfoPhoneNumberVerified() { + func testMapsUserInfoPhoneNumberVerified() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.phoneNumberVerified.rawValue: true ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.phoneNumberVerified) XCTAssertEqual(userInfo.phoneNumberVerified, values[UserInfoProperty.phoneNumberVerified] as? Bool) } - func testMapsUserInfoAddress() { + func testMapsUserInfoAddress() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.address.rawValue: ["foo": "bar"] as [String: String] ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.address) XCTAssertEqual(userInfo.address, values[UserInfoProperty.address] as? [String: String]) } - func testMapsUserInfoUpdatedAt() { + func testMapsUserInfoUpdatedAt() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.updatedAt.rawValue: "2022-04-15T03:15:51.787Z" ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.updatedAt) XCTAssertEqual(userInfo.updatedAt?.asISO8601String, values[UserInfoProperty.updatedAt] as? String) } - func testMapsUserInfoCustomClaims() { + func testMapsUserInfoCustomClaims() throws { let data: [String: Any] = [ UserInfoProperty.sub.rawValue: "", UserInfoProperty.customClaims.rawValue: ["foo": "bar"] ] - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertNotNil(userInfo.customClaims) XCTAssertTrue(userInfo.customClaims == values[UserInfoProperty.customClaims] as? [String: Any]) } - func testFiltersUserInfoCustomClaims() { + func testFiltersUserInfoCustomClaims() throws { let customClaims: [String: Any] = ["foo": "bar"] let claims: [String: Any] = [ "sub": "sub", // Required @@ -407,7 +407,7 @@ extension ExtensionsTests { "c_hash": "cHash" ] let data = customClaims.merging(claims) { (first, _) in first } - let userInfo = UserInfo(json: data)! + let userInfo = try XCTUnwrap(UserInfo(json: data)) let values = userInfo.asDictionary() XCTAssertTrue(values[UserInfoProperty.customClaims] as? [String: Any] == customClaims) } diff --git a/auth0_flutter/example/ios/Tests/ModelsTests.swift b/auth0_flutter/example/ios/Tests/ModelsTests.swift new file mode 100644 index 00000000..7b76328b --- /dev/null +++ b/auth0_flutter/example/ios/Tests/ModelsTests.swift @@ -0,0 +1,37 @@ +import XCTest + +@testable import auth0_flutter + +class ModelsTests: XCTestCase {} + +// MARK: - Account + +extension ModelsTests { + func testReturnsNilAccountWhenRequiredParametersAreMissing() { + let parameters: [AccountProperty] = [.clientId, .domain] + parameters.forEach { parameter in + XCTAssertNil(Account(from: [parameter.rawValue: "foo"])) + } + } + + func testReturnsAccountInstanceWhenRequiredParametersArePresent() { + let parameters = [AccountProperty.clientId.rawValue: "foo", AccountProperty.domain.rawValue: "bar"] + XCTAssertNotNil(Account(from: parameters)) + } +} + +// MARK: - UserAgent + +extension ModelsTests { + func testReturnsNilUserAgentWhenRequiredParametersAreMissing() { + let parameters: [UserAgentProperty] = [.name, .version] + parameters.forEach { parameter in + XCTAssertNil(UserAgent(from: [parameter.rawValue: "foo"])) + } + } + + func testReturnsUserAgentInstanceWhenRequiredParametersArePresent() { + let parameters = [UserAgentProperty.name.rawValue: "foo", UserAgentProperty.version.rawValue: "bar"] + XCTAssertNotNil(UserAgent(from: parameters)) + } +} diff --git a/auth0_flutter/example/ios/Tests/UserAgentTests.swift b/auth0_flutter/example/ios/Tests/UserAgentTests.swift deleted file mode 100644 index c50d51cf..00000000 --- a/auth0_flutter/example/ios/Tests/UserAgentTests.swift +++ /dev/null @@ -1,21 +0,0 @@ -import XCTest - -@testable import auth0_flutter - -class UserAgentTests: XCTestCase {} - -// MARK: - Failable Initializer - -extension UserAgentTests { - func testReturnsNilWhenRequiredParametersAreMissing() { - let parameters: [UserAgentProperty] = [.name, .version] - parameters.forEach { parameter in - XCTAssertNil(UserAgent(from: [parameter.rawValue: "foo"])) - } - } - - func testReturnsInstanceWhenRequiredParametersArePresent() { - let parameters = [UserAgentProperty.name.rawValue: "foo", UserAgentProperty.version.rawValue: "bar"] - XCTAssertNotNil(UserAgent(from: parameters)) - } -} From 57b41c793e63df711c5ec6af50c08212240bbb00 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Sun, 10 Jul 2022 15:47:46 -0300 Subject: [PATCH 12/38] Fix token type key in Kotlin handlers (#113) --- .../request_handlers/api/LoginApiRequestHandler.kt | 2 +- .../request_handlers/api/RenewApiRequestHandler.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt index 73457885..e76c58c9 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt @@ -72,7 +72,7 @@ class LoginApiRequestHandler : ApiRequestHandler { "userProfile" to userProfile.toMap(), "expiresAt" to formattedDate, "scopes" to scope, - "type" to credentials.type + "tokenType" to credentials.type ) ) } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt index 571c6ce1..44bc3402 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt @@ -63,7 +63,7 @@ class RenewApiRequestHandler : ApiRequestHandler { "userProfile" to userProfile.toMap(), "expiresAt" to formattedDate, "scopes" to scope, - "type" to credentials.type + "tokenType" to credentials.type ) ) } From 6e9ebd14e2350fffec4d06c6c1ab748feae1516c Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Mon, 11 Jul 2022 18:14:12 -0300 Subject: [PATCH 13/38] Use current Circle image (#115) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 53061376..55d71032 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ parameters: jobs: test_flutter_package: docker: - - image: cimg/base:2022.04 + - image: cimg/base:current steps: - checkout - flutter/install_sdk_and_pub: From 81d26fc29da9e156241365e0a2e63f207c561b75 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 13 Jul 2022 00:16:11 -0300 Subject: [PATCH 14/38] Add GitHub templates [SDK-3493] (#116) * Add GitHub templates * Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Steve Hobbs * Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Steve Hobbs Co-authored-by: Steve Hobbs --- .github/ISSUE_TEMPLATE/Bug Report.yml | 78 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/Feature Request.yml | 53 +++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 11 +++ .github/PULL_REQUEST_TEMPLATE.md | 40 +++++++++++ 4 files changed, 182 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Bug Report.yml create mode 100644 .github/ISSUE_TEMPLATE/Feature Request.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml new file mode 100644 index 00000000..ed5e310e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -0,0 +1,78 @@ +name: ๐Ÿž Report a bug +description: Have you found a bug or issue? Create a bug report for this library + +body: + - type: markdown + attributes: + value: | + **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. + + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: The issue can be reproduced in the [auth0_flutter sample app](https://github.com/auth0-samples/auth0-flutter-samples/tree/main/sample) (or N/A). + required: true + - label: I have looked into the [README](https://github.com/auth0/auth0-flutter/tree/main/auth0_flutter#readme) and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://pub.dev/documentation/auth0_flutter/latest/) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/auth0-flutter/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com/c/sdks/5) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise description of the issue, including what you expected to happen. + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent. + placeholder: | + 1. Step 1... + 2. Step 2... + 3. ... + validations: + required: true + + - type: input + id: environment-version + attributes: + label: auth0_flutter version + validations: + required: true + + - type: input + id: environment-flutter-version + attributes: + label: Flutter version + validations: + required: true + + - type: dropdown + id: environment-platform + attributes: + label: Platform + multiple: true + options: + - Android + - iOS + validations: + required: true + + - type: input + id: environment-platform-version + attributes: + label: Platform version(s) + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml new file mode 100644 index 00000000..52824483 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -0,0 +1,53 @@ +name: ๐Ÿงฉ Feature request +description: Suggest an idea or a feature for this library +labels: ["feature request"] + +body: + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have looked into the [README](https://github.com/auth0/auth0-flutter/tree/main/auth0_flutter#readme) and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://pub.dev/documentation/auth0_flutter/latest/) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/auth0-flutter/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com/c/sdks/5) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Describe the problem you'd like to have solved + description: A clear and concise description of what the problem is. + placeholder: I'm always frustrated when... + validations: + required: true + + - type: textarea + id: ideal-solution + attributes: + label: Describe the ideal solution + description: A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + id: alternatives-and-workarounds + attributes: + label: Alternatives and current workarounds + description: A clear and concise description of any alternatives you've considered or any workarounds that are currently in place. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..24ac1e1d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: ๐Ÿค” Help & Questions + url: https://community.auth0.com/c/sdks/5 + about: Ask general support or usage questions in the Auth0 Community forums. + - name: ๐Ÿ“‘ FAQ + url: https://github.com/auth0/auth0-flutter/blob/main/auth0_flutter/FAQ.md + about: Check some commonly asked questions. + - name: ๐Ÿ“– API Documentation + url: https://pub.dev/documentation/auth0_flutter/latest/ + about: Check the public API documentation for in-depth overview of all the available features. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..7a9d56b0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,40 @@ + + +- [ ] All new/changed/fixed functionality is covered by tests (or N/A) +- [ ] I have added documentation for all new/changed functionality (or N/A) + + + +### ๐Ÿ“‹ Changes + + + +### ๐Ÿ“Ž References + + + +### ๐ŸŽฏ Testing + + From f5e814800f6a258caa5686a4502e362db5e6f457 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 13 Jul 2022 05:06:28 -0300 Subject: [PATCH 15/38] Update `flutter_lints` to v2 (#117) --- auth0_flutter/analysis_options.yaml | 3 +-- auth0_flutter/example/lib/main.dart | 1 + auth0_flutter/example/pubspec.yaml | 2 +- auth0_flutter/lib/src/authentication_api.dart | 4 ++-- auth0_flutter/pubspec.yaml | 2 +- auth0_flutter_platform_interface/analysis_options.yaml | 3 +-- .../lib/src/web-auth/id_token_validation_config.dart | 2 +- auth0_flutter_platform_interface/pubspec.yaml | 2 +- .../test/method_channel_auth0_flutter_auth_test.dart | 2 +- .../test/method_channel_credentials_manager_test.dart | 9 ++++----- 10 files changed, 14 insertions(+), 16 deletions(-) diff --git a/auth0_flutter/analysis_options.yaml b/auth0_flutter/analysis_options.yaml index b6813c8d..7bfddbf3 100644 --- a/auth0_flutter/analysis_options.yaml +++ b/auth0_flutter/analysis_options.yaml @@ -91,5 +91,4 @@ linter: sort_pub_dependencies: true # Specific rules - public_member_api_docs: false # 'true' after EA - package_api_docs: false # 'true' after EA + package_api_docs: true diff --git a/auth0_flutter/example/lib/main.dart b/auth0_flutter/example/lib/main.dart index 594b29dd..ccbcd5fe 100644 --- a/auth0_flutter/example/lib/main.dart +++ b/auth0_flutter/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +// ignore: depend_on_referenced_packages import 'package:flutter_driver/driver_extension.dart'; import 'example_app.dart'; diff --git a/auth0_flutter/example/pubspec.yaml b/auth0_flutter/example/pubspec.yaml index c2565c58..4907c028 100644 --- a/auth0_flutter/example/pubspec.yaml +++ b/auth0_flutter/example/pubspec.yaml @@ -41,7 +41,7 @@ dev_dependencies: dotenv: '^4.0.1' flutter_driver: sdk: flutter - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 flutter_test: sdk: flutter test: '^1.16.5' diff --git a/auth0_flutter/lib/src/authentication_api.dart b/auth0_flutter/lib/src/authentication_api.dart index f711b330..2a50fa2c 100644 --- a/auth0_flutter/lib/src/authentication_api.dart +++ b/auth0_flutter/lib/src/authentication_api.dart @@ -3,10 +3,10 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interfac /// An interface for calling some of the endpoints in [Auth0's Authentication API](https://auth0.com/docs/api/authentication). /// /// This class presents building blocks for doing more fine-grained authentication with Auth0 using Username and Password login. Unlike -/// [WebAuthentication], these do **not** use [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) (the recommended way of doing authentication), +/// `WebAuthentication`, these do **not** use [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) (the recommended way of doing authentication), /// and thus users are not redirected to Auth0 for authentication. /// -/// It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as [Auth0.api]. +/// It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as `Auth0.api`. /// /// Usage example: /// diff --git a/auth0_flutter/pubspec.yaml b/auth0_flutter/pubspec.yaml index bd9d7d5b..57c11bba 100644 --- a/auth0_flutter/pubspec.yaml +++ b/auth0_flutter/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: dev_dependencies: build_runner: ^2.1.8 - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 flutter_test: sdk: flutter mockito: ^5.1.0 diff --git a/auth0_flutter_platform_interface/analysis_options.yaml b/auth0_flutter_platform_interface/analysis_options.yaml index b6813c8d..7bfddbf3 100644 --- a/auth0_flutter_platform_interface/analysis_options.yaml +++ b/auth0_flutter_platform_interface/analysis_options.yaml @@ -91,5 +91,4 @@ linter: sort_pub_dependencies: true # Specific rules - public_member_api_docs: false # 'true' after EA - package_api_docs: false # 'true' after EA + package_api_docs: true diff --git a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart index 2d095f62..3b460bd2 100644 --- a/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart +++ b/auth0_flutter_platform_interface/lib/src/web-auth/id_token_validation_config.dart @@ -3,7 +3,7 @@ class IdTokenValidationConfig { /// The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. Defaults to 60 seconds. final int? leeway; - /// The issuer to be used for validation of JWTs. Defaults to the domain used to when calling [Auth0.new]. + /// The issuer to be used for validation of JWTs. Defaults to the domain used to when calling `Auth0.new`. final String? issuer; /// Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0. diff --git a/auth0_flutter_platform_interface/pubspec.yaml b/auth0_flutter_platform_interface/pubspec.yaml index 5ec9eca8..f97dfed7 100644 --- a/auth0_flutter_platform_interface/pubspec.yaml +++ b/auth0_flutter_platform_interface/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: build_runner: ^2.1.8 - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 flutter_test: sdk: flutter mockito: ^5.1.0 diff --git a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart index dccdc384..59422f03 100644 --- a/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_auth0_flutter_auth_test.dart @@ -215,7 +215,7 @@ void main() { expectLater( actual, - throwsA(predicate((e) => + throwsA(predicate((final e) => e is ApiException && e.message == 'Channel returned null.'))); }); diff --git a/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart index 88e19d44..a9e38c3e 100644 --- a/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart +++ b/auth0_flutter_platform_interface/test/method_channel_credentials_manager_test.dart @@ -1,5 +1,4 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; -import 'package:auth0_flutter_platform_interface/src/credentials-manager/credentials_manager_exception.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; @@ -145,7 +144,7 @@ void main() { expectLater( actual, - throwsA(predicate((e) => + throwsA(predicate((final e) => e is CredentialsManagerException && e.message == 'Channel returned null.'))); }); @@ -297,7 +296,7 @@ void main() { expectLater( actual, - throwsA(predicate((e) => + throwsA(predicate((final e) => e is CredentialsManagerException && e.message == 'Channel returned null.'))); }); @@ -395,7 +394,7 @@ void main() { expectLater( actual, - throwsA(predicate((e) => + throwsA(predicate((final e) => e is CredentialsManagerException && e.message == 'Channel returned null.'))); }); @@ -471,7 +470,7 @@ void main() { expectLater( actual, - throwsA(predicate((e) => + throwsA(predicate((final e) => e is CredentialsManagerException && e.message == 'Channel returned null.'))); }); From aab5e389d01b09e186b7f6f5265244a15097cf3c Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Wed, 13 Jul 2022 15:55:48 +0100 Subject: [PATCH 16/38] chore: remove docs folder from source control (#118) * Remove docs folder * Add docs folder into gitignore --- auth0_flutter/.gitignore | 1 + auth0_flutter/doc/api/__404error.html | 103 -- .../api/auth0_flutter/ApiException-class.html | 552 --------- .../ApiException.fromPlatformException.html | 173 --- .../ApiException/ApiException.html | 167 --- .../ApiException/ApiException.unknown.html | 164 --- .../api/auth0_flutter/ApiException/code.html | 163 --- .../auth0_flutter/ApiException/details.html | 163 --- .../ApiException/isAccessDenied.html | 168 --- .../isBrowserAppNotAvailable.html | 169 --- .../ApiException/isCanceled.html | 168 --- .../ApiException/isInvalidAuthorizeURL.html | 169 --- .../ApiException/isInvalidConfiguration.html | 169 --- .../ApiException/isInvalidCredentials.html | 169 --- .../ApiException/isLoginRequired.html | 168 --- .../isMultifactorCodeInvalid.html | 169 --- .../isMultifactorEnrollRequired.html | 169 --- .../ApiException/isMultifactorRequired.html | 169 --- .../isMultifactorTokenInvalid.html | 169 --- .../ApiException/isNetworkError.html | 168 --- .../ApiException/isPKCENotAvailable.html | 169 --- .../ApiException/isPasswordAlreadyUsed.html | 169 --- .../ApiException/isPasswordLeaked.html | 169 --- .../isPasswordNotStrongEnough.html | 169 --- .../ApiException/isRefreshTokenDeleted.html | 169 --- .../ApiException/isRuleError.html | 168 --- .../ApiException/isTooManyAttempts.html | 169 --- .../ApiException/isVerificationRequired.html | 169 --- .../auth0_flutter/ApiException/message.html | 163 --- .../ApiException/statusCode.html | 163 --- .../auth0_flutter/ApiException/toString.html | 183 --- .../doc/api/auth0_flutter/Auth0-class.html | 274 ----- .../doc/api/auth0_flutter/Auth0/Auth0.html | 143 --- .../doc/api/auth0_flutter/Auth0/api.html | 158 --- .../Auth0/webAuthentication.html | 153 --- .../AuthenticationApi-class.html | 336 ------ .../AuthenticationApi/AuthenticationApi.html | 141 --- .../AuthenticationApi/login.html | 186 --- .../AuthenticationApi/renewCredentials.html | 180 --- .../AuthenticationApi/resetPassword.html | 163 --- .../AuthenticationApi/signup.html | 173 --- .../AuthenticationApi/userProfile.html | 165 --- .../api/auth0_flutter/Credentials-class.html | 330 ------ .../Credentials/Credentials.fromMap.html | 151 --- .../Credentials/Credentials.html | 154 --- .../Credentials/accessToken.html | 152 --- .../auth0_flutter/Credentials/expiresAt.html | 147 --- .../auth0_flutter/Credentials/idToken.html | 151 --- .../Credentials/refreshToken.html | 149 --- .../api/auth0_flutter/Credentials/scopes.html | 148 --- .../Credentials/userProfile.html | 148 --- .../IdTokenValidationConfig-class.html | 287 ----- .../IdTokenValidationConfig.html | 140 --- .../IdTokenValidationConfig/issuer.html | 143 --- .../IdTokenValidationConfig/leeway.html | 143 --- .../IdTokenValidationConfig/maxAge.html | 143 --- .../api/auth0_flutter/UserProfile-class.html | 511 --------- .../UserProfile/UserProfile.fromMap.html | 193 ---- .../UserProfile/UserProfile.html | 199 ---- .../auth0_flutter/UserProfile/address.html | 163 --- .../auth0_flutter/UserProfile/birthdate.html | 163 --- .../UserProfile/customClaims.html | 162 --- .../api/auth0_flutter/UserProfile/email.html | 163 --- .../auth0_flutter/UserProfile/familyName.html | 163 --- .../api/auth0_flutter/UserProfile/gender.html | 163 --- .../auth0_flutter/UserProfile/givenName.html | 163 --- .../UserProfile/isEmailVerified.html | 163 --- .../UserProfile/isPhoneNumberVerified.html | 163 --- .../api/auth0_flutter/UserProfile/locale.html | 163 --- .../auth0_flutter/UserProfile/middleName.html | 163 --- .../api/auth0_flutter/UserProfile/name.html | 163 --- .../auth0_flutter/UserProfile/nickname.html | 163 --- .../UserProfile/phoneNumber.html | 163 --- .../auth0_flutter/UserProfile/pictureURL.html | 163 --- .../UserProfile/preferredUsername.html | 163 --- .../auth0_flutter/UserProfile/profileURL.html | 163 --- .../api/auth0_flutter/UserProfile/sub.html | 162 --- .../auth0_flutter/UserProfile/updatedAt.html | 163 --- .../auth0_flutter/UserProfile/websiteURL.html | 163 --- .../auth0_flutter/UserProfile/zoneinfo.html | 163 --- .../auth0_flutter/WebAuthException-class.html | 299 ----- ...ebAuthException.fromPlatformException.html | 141 --- .../WebAuthException/WebAuthException.html | 144 --- .../WebAuthException.unknown.html | 140 --- .../auth0_flutter/WebAuthException/code.html | 142 --- .../WebAuthException/details.html | 142 --- .../WebAuthException/message.html | 142 --- .../WebAuthException/toString.html | 162 --- .../WebAuthentication-class.html | 289 ----- .../WebAuthentication/WebAuthentication.html | 138 --- .../WebAuthentication/login.html | 190 --- .../WebAuthentication/logout.html | 153 --- .../auth0_flutter/auth0_flutter-library.html | 208 ---- auth0_flutter/doc/api/categories.json | 1 - auth0_flutter/doc/api/index.html | 473 -------- auth0_flutter/doc/api/index.json | 1 - .../doc/api/static-assets/favicon.png | Bin 1767 -> 0 bytes .../doc/api/static-assets/github.css | 99 -- .../doc/api/static-assets/highlight.pack.js | 775 ------------- .../doc/api/static-assets/play_button.svg | 1 - auth0_flutter/doc/api/static-assets/readme.md | 22 - auth0_flutter/doc/api/static-assets/script.js | 501 -------- .../doc/api/static-assets/styles.css | 1022 ----------------- 103 files changed, 1 insertion(+), 19336 deletions(-) delete mode 100644 auth0_flutter/doc/api/__404error.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/code.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/details.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/message.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/api.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html delete mode 100644 auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html delete mode 100644 auth0_flutter/doc/api/categories.json delete mode 100644 auth0_flutter/doc/api/index.html delete mode 100644 auth0_flutter/doc/api/index.json delete mode 100644 auth0_flutter/doc/api/static-assets/favicon.png delete mode 100644 auth0_flutter/doc/api/static-assets/github.css delete mode 100644 auth0_flutter/doc/api/static-assets/highlight.pack.js delete mode 100644 auth0_flutter/doc/api/static-assets/play_button.svg delete mode 100644 auth0_flutter/doc/api/static-assets/readme.md delete mode 100644 auth0_flutter/doc/api/static-assets/script.js delete mode 100644 auth0_flutter/doc/api/static-assets/styles.css diff --git a/auth0_flutter/.gitignore b/auth0_flutter/.gitignore index 2de69c93..8a9a8f11 100644 --- a/auth0_flutter/.gitignore +++ b/auth0_flutter/.gitignore @@ -26,3 +26,4 @@ .dart_tool/ .packages build/ +**/doc/api \ No newline at end of file diff --git a/auth0_flutter/doc/api/__404error.html b/auth0_flutter/doc/api/__404error.html deleted file mode 100644 index ef34672b..00000000 --- a/auth0_flutter/doc/api/__404error.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - auth0_flutter - Dart API docs - - - - - - - - - - - - - - - - - -
- -
- - -
auth0_flutter
- -
- -
- - -
-

404: Something's gone wrong :-(

- -
-

You've tried to visit a page that doesn't exist. Luckily this site - has other pages.

-

If you were looking for something specific, try searching: -

-

- -
-
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html b/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html deleted file mode 100644 index cb113f0d..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException-class.html +++ /dev/null @@ -1,552 +0,0 @@ - - - - - - - - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
ApiException
- -
- -
- - -
-
-

ApiException class - Null safety - -

- - - - - - -
-

Constructors

- -
-
- ApiException(String code, String message, Map<String, dynamic> details, Map _errorFlags, int statusCode) -
-
- -
const
-
-
- ApiException.fromPlatformException(PlatformException e) -
-
- -
factory
-
-
- ApiException.unknown(String message) -
-
- -
const
-
-
-
- -
-

Properties

- -
-
- code - String - -
-
- -
final, inherited
- -
- -
- details - Map<String, dynamic> - -
-
- -
final, inherited
- -
- -
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- isAccessDenied - bool - -
-
- -
read-only
- -
- -
- isBrowserAppNotAvailable - bool - -
-
- -
read-only
- -
- -
- isCanceled - bool - -
-
- -
read-only
- -
- -
- isInvalidAuthorizeURL - bool - -
-
- -
read-only
- -
- -
- isInvalidConfiguration - bool - -
-
- -
read-only
- -
- -
- isInvalidCredentials - bool - -
-
- -
read-only
- -
- -
- isLoginRequired - bool - -
-
- -
read-only
- -
- -
- isMultifactorCodeInvalid - bool - -
-
- -
read-only
- -
- -
- isMultifactorEnrollRequired - bool - -
-
- -
read-only
- -
- -
- isMultifactorRequired - bool - -
-
- -
read-only
- -
- -
- isMultifactorTokenInvalid - bool - -
-
- -
read-only
- -
- -
- isNetworkError - bool - -
-
- -
read-only
- -
- -
- isPasswordAlreadyUsed - bool - -
-
- -
read-only
- -
- -
- isPasswordLeaked - bool - -
-
- -
read-only
- -
- -
- isPasswordNotStrongEnough - bool - -
-
- -
read-only
- -
- -
- isPKCENotAvailable - bool - -
-
- -
read-only
- -
- -
- isRefreshTokenDeleted - bool - -
-
- -
read-only
- -
- -
- isRuleError - bool - -
-
- -
read-only
- -
- -
- isTooManyAttempts - bool - -
-
- -
read-only
- -
- -
- isVerificationRequired - bool - -
-
- -
read-only
- -
- -
- message - String - -
-
- -
final, inherited
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
- statusCode - int - -
-
- -
final
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html deleted file mode 100644 index ac14a61c..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.fromPlatformException.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - ApiException.fromPlatformException constructor - ApiException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
ApiException.fromPlatformException
- -
- -
- - -
-
-

ApiException.fromPlatformException constructor - Null safety -

- -
- ApiException.fromPlatformException(
  1. PlatformException e
  2. -
) -
- - - - - -
-

Implementation

-
factory ApiException.fromPlatformException(final PlatformException e) {
-  final Map<String, dynamic> errorDetails = e.detailsMap;
-  final statusCode =
-      errorDetails.getOrDefault(_statusCodeKey, 0);
-  final errorFlags =
-      errorDetails.getOrDefault(_errorFlagsKey, <dynamic, dynamic>{});
-
-  errorDetails.remove(_statusCodeKey);
-  errorDetails.remove(_errorFlagsKey);
-
-  return ApiException(
-      e.code, e.messageString, errorDetails, errorFlags, statusCode);
-}
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html deleted file mode 100644 index 6688bceb..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - ApiException constructor - ApiException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
ApiException
- -
- -
- - -
-
-

ApiException constructor - Null safety -

- -
const - ApiException(
  1. String code,
  2. -
  3. String message,
  4. -
  5. Map<String, dynamic> details,
  6. -
  7. Map _errorFlags,
  8. -
  9. int statusCode
  10. -
) -
- - - - - -
-

Implementation

-
const ApiException(final String code, final String message,
-    final Map<String, dynamic> details, this._errorFlags, this.statusCode)
-    : super(code, message, details);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html deleted file mode 100644 index 694402ca..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/ApiException.unknown.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - ApiException.unknown constructor - ApiException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
ApiException.unknown
- -
- -
- - -
-
-

ApiException.unknown constructor - Null safety -

- -
const - ApiException.unknown(
  1. String message
  2. -
) -
- - - - - -
-

Implementation

-
const ApiException.unknown(final String message)
-    : _errorFlags = const {},
-      statusCode = 0,
-      super.unknown(message);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html deleted file mode 100644 index 72ae8ca7..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/code.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - code property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
code
- -
- -
- - -
-
-

code property - Null safety -

- -
- String - code -
final, inherited
- -
- - - -
-

Implementation

-
final String code;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html deleted file mode 100644 index 952a1abb..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/details.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - details property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
details
- -
- -
- - -
-
-

details property - Null safety -

- -
- Map<String, dynamic> - details -
final, inherited
- -
- - - -
-

Implementation

-
final Map<String, dynamic> details;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html deleted file mode 100644 index 2c3f7640..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isAccessDenied.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - isAccessDenied property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isAccessDenied
- -
- -
- - -
-
-

isAccessDenied property - Null safety -

- - - -
- -
- bool - isAccessDenied - - -
- - - - -
-

Implementation

-
bool get isAccessDenied => _errorFlags.getBooleanOrFalse('isAccessDenied');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html deleted file mode 100644 index 5afa8b54..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isBrowserAppNotAvailable.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isBrowserAppNotAvailable property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isBrowserAppNotAvailable
- -
- -
- - -
-
-

isBrowserAppNotAvailable property - Null safety -

- - - -
- -
- bool - isBrowserAppNotAvailable - - -
- - - - -
-

Implementation

-
bool get isBrowserAppNotAvailable =>
-    _errorFlags.getBooleanOrFalse('isBrowserAppNotAvailable');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html deleted file mode 100644 index 4be42b14..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isCanceled.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - isCanceled property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isCanceled
- -
- -
- - -
-
-

isCanceled property - Null safety -

- - - -
- -
- bool - isCanceled - - -
- - - - -
-

Implementation

-
bool get isCanceled => _errorFlags.getBooleanOrFalse('isCanceled');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html deleted file mode 100644 index f026623d..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidAuthorizeURL.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isInvalidAuthorizeURL property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isInvalidAuthorizeURL
- -
- -
- - -
-
-

isInvalidAuthorizeURL property - Null safety -

- - - -
- -
- bool - isInvalidAuthorizeURL - - -
- - - - -
-

Implementation

-
bool get isInvalidAuthorizeURL =>
-    _errorFlags.getBooleanOrFalse('isInvalidAuthorizeURL');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html deleted file mode 100644 index 8a35b9e8..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidConfiguration.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isInvalidConfiguration property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isInvalidConfiguration
- -
- -
- - -
-
-

isInvalidConfiguration property - Null safety -

- - - -
- -
- bool - isInvalidConfiguration - - -
- - - - -
-

Implementation

-
bool get isInvalidConfiguration =>
-    _errorFlags.getBooleanOrFalse('isInvalidConfiguration');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html deleted file mode 100644 index 9a25e196..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isInvalidCredentials.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isInvalidCredentials property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isInvalidCredentials
- -
- -
- - -
-
-

isInvalidCredentials property - Null safety -

- - - -
- -
- bool - isInvalidCredentials - - -
- - - - -
-

Implementation

-
bool get isInvalidCredentials =>
-    _errorFlags.getBooleanOrFalse('isInvalidCredentials');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html deleted file mode 100644 index 45df9ac3..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isLoginRequired.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - isLoginRequired property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isLoginRequired
- -
- -
- - -
-
-

isLoginRequired property - Null safety -

- - - -
- -
- bool - isLoginRequired - - -
- - - - -
-

Implementation

-
bool get isLoginRequired => _errorFlags.getBooleanOrFalse('isLoginRequired');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html deleted file mode 100644 index de5e0ff0..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorCodeInvalid.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isMultifactorCodeInvalid property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isMultifactorCodeInvalid
- -
- -
- - -
-
-

isMultifactorCodeInvalid property - Null safety -

- - - -
- -
- bool - isMultifactorCodeInvalid - - -
- - - - -
-

Implementation

-
bool get isMultifactorCodeInvalid =>
-    _errorFlags.getBooleanOrFalse('isMultifactorCodeInvalid');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html deleted file mode 100644 index ee0e511b..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorEnrollRequired.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isMultifactorEnrollRequired property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isMultifactorEnrollRequired
- -
- -
- - -
-
-

isMultifactorEnrollRequired property - Null safety -

- - - -
- -
- bool - isMultifactorEnrollRequired - - -
- - - - -
-

Implementation

-
bool get isMultifactorEnrollRequired =>
-    _errorFlags.getBooleanOrFalse('isMultifactorEnrollRequired');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html deleted file mode 100644 index ab418a11..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorRequired.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isMultifactorRequired property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isMultifactorRequired
- -
- -
- - -
-
-

isMultifactorRequired property - Null safety -

- - - -
- -
- bool - isMultifactorRequired - - -
- - - - -
-

Implementation

-
bool get isMultifactorRequired =>
-    _errorFlags.getBooleanOrFalse('isMultifactorRequired');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html deleted file mode 100644 index e2b77250..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isMultifactorTokenInvalid.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isMultifactorTokenInvalid property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isMultifactorTokenInvalid
- -
- -
- - -
-
-

isMultifactorTokenInvalid property - Null safety -

- - - -
- -
- bool - isMultifactorTokenInvalid - - -
- - - - -
-

Implementation

-
bool get isMultifactorTokenInvalid =>
-    _errorFlags.getBooleanOrFalse('isMultifactorTokenInvalid');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html deleted file mode 100644 index 8c5cc6c1..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isNetworkError.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - isNetworkError property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isNetworkError
- -
- -
- - -
-
-

isNetworkError property - Null safety -

- - - -
- -
- bool - isNetworkError - - -
- - - - -
-

Implementation

-
bool get isNetworkError => _errorFlags.getBooleanOrFalse('isNetworkError');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html deleted file mode 100644 index d8569a2a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPKCENotAvailable.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isPKCENotAvailable property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isPKCENotAvailable
- -
- -
- - -
-
-

isPKCENotAvailable property - Null safety -

- - - -
- -
- bool - isPKCENotAvailable - - -
- - - - -
-

Implementation

-
bool get isPKCENotAvailable =>
-    _errorFlags.getBooleanOrFalse('isPKCENotAvailable');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html deleted file mode 100644 index a1f6d14c..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordAlreadyUsed.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isPasswordAlreadyUsed property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isPasswordAlreadyUsed
- -
- -
- - -
-
-

isPasswordAlreadyUsed property - Null safety -

- - - -
- -
- bool - isPasswordAlreadyUsed - - -
- - - - -
-

Implementation

-
bool get isPasswordAlreadyUsed =>
-    _errorFlags.getBooleanOrFalse('isPasswordAlreadyUsed');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html deleted file mode 100644 index 33d790b7..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordLeaked.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isPasswordLeaked property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isPasswordLeaked
- -
- -
- - -
-
-

isPasswordLeaked property - Null safety -

- - - -
- -
- bool - isPasswordLeaked - - -
- - - - -
-

Implementation

-
bool get isPasswordLeaked =>
-    _errorFlags.getBooleanOrFalse('isPasswordLeaked');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html deleted file mode 100644 index 8b41f64f..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isPasswordNotStrongEnough.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isPasswordNotStrongEnough property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isPasswordNotStrongEnough
- -
- -
- - -
-
-

isPasswordNotStrongEnough property - Null safety -

- - - -
- -
- bool - isPasswordNotStrongEnough - - -
- - - - -
-

Implementation

-
bool get isPasswordNotStrongEnough =>
-    _errorFlags.getBooleanOrFalse('isPasswordNotStrongEnough');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html deleted file mode 100644 index a4b762e6..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRefreshTokenDeleted.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isRefreshTokenDeleted property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isRefreshTokenDeleted
- -
- -
- - -
-
-

isRefreshTokenDeleted property - Null safety -

- - - -
- -
- bool - isRefreshTokenDeleted - - -
- - - - -
-

Implementation

-
bool get isRefreshTokenDeleted =>
-    _errorFlags.getBooleanOrFalse('isRefreshTokenDeleted');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html deleted file mode 100644 index cb995693..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isRuleError.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - isRuleError property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isRuleError
- -
- -
- - -
-
-

isRuleError property - Null safety -

- - - -
- -
- bool - isRuleError - - -
- - - - -
-

Implementation

-
bool get isRuleError => _errorFlags.getBooleanOrFalse('isRuleError');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html deleted file mode 100644 index aa937c62..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isTooManyAttempts.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isTooManyAttempts property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isTooManyAttempts
- -
- -
- - -
-
-

isTooManyAttempts property - Null safety -

- - - -
- -
- bool - isTooManyAttempts - - -
- - - - -
-

Implementation

-
bool get isTooManyAttempts =>
-    _errorFlags.getBooleanOrFalse('isTooManyAttempts');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html deleted file mode 100644 index 56c31b56..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/isVerificationRequired.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - isVerificationRequired property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isVerificationRequired
- -
- -
- - -
-
-

isVerificationRequired property - Null safety -

- - - -
- -
- bool - isVerificationRequired - - -
- - - - -
-

Implementation

-
bool get isVerificationRequired =>
-    _errorFlags.getBooleanOrFalse('isVerificationRequired');
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html deleted file mode 100644 index 7f158a2f..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/message.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - message property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
message
- -
- -
- - -
-
-

message property - Null safety -

- -
- String - message -
final, inherited
- -
- - - -
-

Implementation

-
final String message;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html deleted file mode 100644 index 01422e9b..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/statusCode.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - statusCode property - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
statusCode
- -
- -
- - -
-
-

statusCode property - Null safety -

- -
- int - statusCode -
final
- -
- - - -
-

Implementation

-
final int statusCode;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html b/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html deleted file mode 100644 index a12d2255..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/ApiException/toString.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - toString method - ApiException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
toString
- -
- -
- - -
-
-

toString method - Null safety -

- -
- -
-
    -
  1. @override
  2. -
-
- -String -toString() - -
inherited
- -
- -
-

A string representation of this object.

-

Some classes have a default textual representation, -often paired with a static parse function (like int.parse). -These classes will provide the textual representation as -their string representation.

-

Other classes have no meaningful textual representation -that a program will care about. -Such classes will typically override toString to provide -useful information when inspecting the object, -mainly for debugging or logging.

-
- - - -
-

Implementation

-
@override
-String toString() => '$code: $message';
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html b/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html deleted file mode 100644 index 70cc7745..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Auth0-class.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - - Auth0 class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
Auth0
- -
- -
- - -
-
-

Auth0 class - Null safety - -

- - -
-

Primary interface for interacting with Auth0 using web authentication, or the authentication API.

-
- - - - -
-

Constructors

- -
-
- Auth0(String domain, String clientId) -
-
- Creates an intance of an Auth0 client with the provided domain and clientId properties. -
-
-
- -
-

Properties

- -
-
- api - AuthenticationApi - -
-
- An instance of AuthenticationApi, the primary interface for interacting with the Auth0 Authentication API -
read-only
- -
- -
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
- webAuthentication - WebAuthentication - -
-
- An instance of WebAuthentication, the primary interface for interacting with the Auth0 Universal Login page. -
read-only
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html deleted file mode 100644 index d911039c..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Auth0/Auth0.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - Auth0 constructor - Auth0 - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
Auth0
- -
- -
- - -
-
-

Auth0 constructor - Null safety -

- -
- Auth0(
  1. String domain,
  2. -
  3. String clientId
  4. -
) -
- - -
-

Creates an intance of an Auth0 client with the provided domain and clientId properties.

-

domain and clientId are both values that can be retrieved from the application in your Auth0 Dashboard.

-
- - - -
-

Implementation

-
Auth0(final String domain, final String clientId)
-    : _account = Account(domain, clientId);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html deleted file mode 100644 index f10c2bb2..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Auth0/api.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - api property - Auth0 class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
api
- -
- -
- - -
-
-

api property - Null safety -

- - - -
- -
- AuthenticationApi - api - - -
- - -
-

An instance of AuthenticationApi, the primary interface for interacting with the Auth0 Authentication API

-

Usage example:

-
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
-
-final result = await auth0.api.login({
-  usernameOrEmail: 'my@email.com',
-  password: 'my_password'
-  connectionOrRealm: 'Username-Password-Authentication'
-});
-
-final accessToken = result.accessToken;
-
-
- - -
-

Implementation

-
AuthenticationApi get api => AuthenticationApi(_account, _userAgent);
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html b/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html deleted file mode 100644 index 286db633..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Auth0/webAuthentication.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - webAuthentication property - Auth0 class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
webAuthentication
- -
- -
- - -
-
-

webAuthentication property - Null safety -

- - - -
- -
- WebAuthentication - webAuthentication - - -
- - -
-

An instance of WebAuthentication, the primary interface for interacting with the Auth0 Universal Login page.

-

Usage example:

-
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
-final result = await auth0.webAuthentication.login();
-final accessToken = result.accessToken;
-
-
- - -
-

Implementation

-
WebAuthentication get webAuthentication =>
-    WebAuthentication(_account, _userAgent);
-
- -
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html deleted file mode 100644 index 0929be64..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi-class.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
AuthenticationApi
- -
- -
- - -
-
-

AuthenticationApi class - Null safety - -

- - -
-

An interface for calling some of the endpoints in Auth0's Authentication API.

-

This class presents building blocks for doing more fine-grained authentication with Auth0 using Username and Password login. Unlike -WebAuthentication, these do not use Auth0 Universal Login (the recommended way of doing authentication), -and thus users are not redirected to Auth0 for authentication.

-

It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as Auth0.api.

-

Usage example:

-
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
-
-final result = await auth0.api.login({
-  usernameOrEmail: 'my@email.com',
-  password: 'my_password'
-  connectionOrRealm: 'Username-Password-Authentication'
-})
-
-final accessToken = result.accessToken;
-
-
- - - - -
-

Constructors

- -
-
- AuthenticationApi(Account _account, UserAgent _userAgent) -
-
- -
-
-
- -
-

Properties

- -
-
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
-
- - -
-

Methods

-
-
- login({required String usernameOrEmail, required String password, required String connectionOrRealm, String? audience, Set<String> scopes = const {}, Map<String, String> parameters = const {}}) - Future<Credentials> - - - -
-
- Authenticates the user using a usernameOrEmail and a password, with the specified connectionOrRealm. If successful, it returns -a set of tokens, as well as the user's profile (constructed from ID token claims). - - -
- -
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- renewCredentials({required String refreshToken, Set<String> scopes = const {}, Map<String, String> parameters = const {}}) - Future<Credentials> - - - -
-
- Uses a refreshToken to get a new access token. - - -
- -
- resetPassword({required String email, required String connection, Map<String, String> parameters = const {}}) - Future<void> - - - -
-
- Initiates a reset of password of the user with the specific email address in the specific connection. - - -
- -
- signup({required String email, required String password, String? username, required String connection, Map<String, String> userMetadata = const {}, Map<String, String> parameters = const {}}) - Future<DatabaseUser> - - - -
-
- Registers a new user with the specified email address and password in the specified connection. - - -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
- userProfile({required String accessToken, Map<String, String> parameters = const {}}) - Future<UserProfile> - - - -
-
- Fetches the user's profile from the /userinfo endpoint. An accessToken from a successful authentication call must be supplied. - - -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html deleted file mode 100644 index 56d98436..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/AuthenticationApi.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - AuthenticationApi constructor - AuthenticationApi - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
AuthenticationApi
- -
- -
- - -
-
-

AuthenticationApi constructor - Null safety -

- -
- AuthenticationApi(
  1. Account _account,
  2. -
  3. UserAgent _userAgent
  4. -
) -
- - - - - -
-

Implementation

-
AuthenticationApi(this._account, this._userAgent);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html deleted file mode 100644 index 56247cf4..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/login.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - login method - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
login
- -
- -
- - -
-
-

login method - Null safety -

- -
- - -Future<Credentials> -login(
  1. {required String usernameOrEmail,
  2. -
  3. required String password,
  4. -
  5. required String connectionOrRealm,
  6. -
  7. String? audience,
  8. -
  9. Set<String> scopes = const {},
  10. -
  11. Map<String, String> parameters = const {}}
  12. -
) - - - -
- -
-

Authenticates the user using a usernameOrEmail and a password, with the specified connectionOrRealm. If successful, it returns -a set of tokens, as well as the user's profile (constructed from ID token claims).

-

If using the default username and password database connection, connectionOrRealm should be set to Username-Password-Authentication.

-

Endpoint docs

-

https://auth0.com/docs/api/authentication#login

-

Notes

-
    -
  • audience relates to the API Identifier you want to reference in your access tokens (see API settings)
  • -
  • scopes defaults to openid profile email
  • -
  • parameters can be used to sent through custom parameters to the endpoint to be picked up in a Rule or Action.
  • -
-

Usage example

-
final result = await auth0.api.login({
-  usernameOrEmail: 'my@email.com',
-  password: 'my_password'
-  connectionOrRealm: 'Username-Password-Authentication'
-});
-
-
- - - -
-

Implementation

-
Future<Credentials> login({
-  required final String usernameOrEmail,
-  required final String password,
-  required final String connectionOrRealm,
-  final String? audience,
-  final Set<String> scopes = const {},
-  final Map<String, String> parameters = const {},
-}) =>
-    Auth0FlutterAuthPlatform.instance
-        .login(_createApiRequest(AuthLoginOptions(
-      usernameOrEmail: usernameOrEmail,
-      password: password,
-      connectionOrRealm: connectionOrRealm,
-      audience: audience,
-      scopes: scopes,
-      parameters: parameters,
-    )));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html deleted file mode 100644 index f824128f..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/renewCredentials.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - renewCredentials method - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
renewCredentials
- -
- -
- - -
-
-

renewCredentials method - Null safety -

- -
- - -Future<Credentials> -renewCredentials(
  1. {required String refreshToken,
  2. -
  3. Set<String> scopes = const {},
  4. -
  5. Map<String, String> parameters = const {}}
  6. -
) - - - -
- -
-

Uses a refreshToken to get a new access token.

-

Endpoint

-

https://auth0.com/docs/api/authentication#refresh-token

-

Notes

-
    -
  • Refresh tokens can be retrieved by specifying the offline_access scope during authentication.
  • -
  • scopes can be specified if a reduced set of scopes is desired.
  • -
-

Further reading

-

Refresh Tokens on Auth0 docs

-

Usage example

-
final result = await auth0.api.login({
-  usernameOrEmail: 'my@email.com',
-  password: 'my_password'
-  connectionOrRealm: 'Username-Password-Authentication',
-  scopes: {'openid', 'profile', 'email', 'offline_access'}
-});
-
-if (result.refreshToken != null) {
-   await auth0.api.renewCredentials(refreshToken: result.refreshToken!);
-}
-
-
- - - -
-

Implementation

-
Future<Credentials> renewCredentials({
-  required final String refreshToken,
-  final Set<String> scopes = const {},
-  final Map<String, String> parameters = const {},
-}) =>
-    Auth0FlutterAuthPlatform.instance.renew(_createApiRequest(
-        AuthRenewOptions(
-            refreshToken: refreshToken,
-            scopes: scopes,
-            parameters: parameters)));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html deleted file mode 100644 index 9e26b32d..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/resetPassword.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - resetPassword method - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
resetPassword
- -
- -
- - -
-
-

resetPassword method - Null safety -

- -
- - -Future<void> -resetPassword(
  1. {required String email,
  2. -
  3. required String connection,
  4. -
  5. Map<String, String> parameters = const {}}
  6. -
) - - - -
- -
-

Initiates a reset of password of the user with the specific email address in the specific connection.

-

Endpoint

-

https://auth0.com/docs/api/authentication#change-password

-

Notes

-

Calling this endpoint does not reset the user's password in itself, but it asks Auth0 to send the user -an email with a link they can use to reset their password on the web.

-

Arbitrary parameters can be specified and then picked up in a custom Auth0 Action or - Rule.

-
- - - -
-

Implementation

-
Future<void> resetPassword(
-        {required final String email,
-        required final String connection,
-        final Map<String, String> parameters = const {}}) =>
-    Auth0FlutterAuthPlatform.instance.resetPassword(_createApiRequest(
-        AuthResetPasswordOptions(
-            email: email, connection: connection, parameters: parameters)));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html deleted file mode 100644 index 3431ce7f..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/signup.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - signup method - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
signup
- -
- -
- - -
-
-

signup method - Null safety -

- -
- - -Future<DatabaseUser> -signup(
  1. {required String email,
  2. -
  3. required String password,
  4. -
  5. String? username,
  6. -
  7. required String connection,
  8. -
  9. Map<String, String> userMetadata = const {},
  10. -
  11. Map<String, String> parameters = const {}}
  12. -
) - - - -
- -
-

Registers a new user with the specified email address and password in the specified connection.

-

Endpoint -https://auth0.com/docs/api/authentication#signup

-

Notes

-
    -
  • username is only required if the connection you specify requires it
  • -
-
- - - -
-

Implementation

-
Future<DatabaseUser> signup(
-        {required final String email,
-        required final String password,
-        final String? username,
-        required final String connection,
-        final Map<String, String> userMetadata = const {},
-        final Map<String, String> parameters = const {}}) =>
-    Auth0FlutterAuthPlatform.instance.signup(_createApiRequest(
-        AuthSignupOptions(
-            email: email,
-            password: password,
-            connection: connection,
-            username: username,
-            userMetadata: userMetadata,
-            parameters: parameters)));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html b/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html deleted file mode 100644 index 63d821a9..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/AuthenticationApi/userProfile.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - userProfile method - AuthenticationApi class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
userProfile
- -
- -
- - -
-
-

userProfile method - Null safety -

- -
- - -Future<UserProfile> -userProfile(
  1. {required String accessToken,
  2. -
  3. Map<String, String> parameters = const {}}
  4. -
) - - - -
- -
-

Fetches the user's profile from the /userinfo endpoint. An accessToken from a successful authentication call must be supplied.

-

Endpoint

-

https://auth0.com/docs/api/authentication#user-profile

-

Usage example

-
final result = await auth0.api.login({
-  usernameOrEmail: 'my@email.com',
-  password: 'my_password'
-  connectionOrRealm: 'Username-Password-Authentication'
-});
-
-final profile = await auth0.api.userProfile({ accessToken: result.accessToken });
-
-
- - - -
-

Implementation

-
Future<UserProfile> userProfile(
-        {required final String accessToken,
-        final Map<String, String> parameters = const {}}) =>
-    Auth0FlutterAuthPlatform.instance.userInfo(_createApiRequest(
-        AuthUserInfoOptions(
-            accessToken: accessToken, parameters: parameters)));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html b/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html deleted file mode 100644 index 1aa62cae..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials-class.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
Credentials
- -
- -
- - -
-
-

Credentials class - Null safety - -

- - -
-

A collection of authentication artifacts obtained from Auth0 when a user logs in.

-
- - - - -
-

Constructors

- -
-
- Credentials({required String idToken, required String accessToken, String? refreshToken, required DateTime expiresAt, Set<String> scopes = const {}, required UserProfile userProfile}) -
-
- -
-
- Credentials.fromMap(Map result) -
-
- -
factory
-
-
-
- -
-

Properties

- -
-
- accessToken - String - -
-
- Token that can be used to make authenticated requests to the specified API (the audience value used on login). -
final
- -
- -
- expiresAt - DateTime - -
-
- The absolute date and time of when the access token expiries. -
final
- -
- -
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- idToken - String - -
-
- A JSON Web Token that contains the user information. -
final
- -
- -
- refreshToken - String? - -
-
- Token that can be used to request a new access token. -
final
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
- scopes - Set<String> - -
-
- The scopes that have been grated by the authorization server. -
final
- -
- -
- userProfile - UserProfile - -
-
- Properties and attributes relating to the authenticated user. -
final
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html deleted file mode 100644 index e1852204..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.fromMap.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - Credentials.fromMap constructor - Credentials - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
Credentials.fromMap
- -
- -
- - -
-
-

Credentials.fromMap constructor - Null safety -

- -
- Credentials.fromMap(
  1. Map result
  2. -
) -
- - - - - -
-

Implementation

-
factory Credentials.fromMap(final Map<dynamic, dynamic> result) =>
-    Credentials(
-      idToken: result['idToken'] as String,
-      accessToken: result['accessToken'] as String,
-      refreshToken: result['refreshToken'] as String?,
-      expiresAt: DateTime.parse(result['expiresAt'] as String),
-      scopes: Set<String>.from(result['scopes'] as List<Object?>),
-      userProfile: UserProfile.fromMap(Map<String, dynamic>.from(
-          result['userProfile'] as Map<dynamic, dynamic>)),
-    );
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html deleted file mode 100644 index 35156baf..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/Credentials.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - Credentials constructor - Credentials - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
Credentials
- -
- -
- - -
-
-

Credentials constructor - Null safety -

- -
- Credentials(
  1. {required String idToken,
  2. -
  3. required String accessToken,
  4. -
  5. String? refreshToken,
  6. -
  7. required DateTime expiresAt,
  8. -
  9. Set<String> scopes = const {},
  10. -
  11. required UserProfile userProfile}
  12. -
) -
- - - - - -
-

Implementation

-
Credentials({
-  required this.idToken,
-  required this.accessToken,
-  this.refreshToken,
-  required this.expiresAt,
-  this.scopes = const {},
-  required this.userProfile,
-});
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html deleted file mode 100644 index 5305ca2a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/accessToken.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - accessToken property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
accessToken
- -
- -
- - -
-
-

accessToken property - Null safety -

- -
- String - accessToken -
final
- -
- -
-

Token that can be used to make authenticated requests to the specified API (the audience value used on login).

-

Futher reading

- -
- - -
-

Implementation

-
final String accessToken;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html deleted file mode 100644 index f874ebf9..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/expiresAt.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - expiresAt property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
expiresAt
- -
- -
- - -
-
-

expiresAt property - Null safety -

- -
- DateTime - expiresAt -
final
- -
- -
-

The absolute date and time of when the access token expiries.

-
- - -
-

Implementation

-
final DateTime expiresAt;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html deleted file mode 100644 index fbefe4ae..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/idToken.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - idToken property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
idToken
- -
- -
- - -
-
-

idToken property - Null safety -

- -
- String - idToken -
final
- -
- -
-

A JSON Web Token that contains the user information.

-

Important: The ID tokens obtained from Web Auth login are automatically validated by the underlying native SDK, ensuring their -contents have not been tampered with.

-

This is not the case for the ID tokens obtained when using the authentication API directly.

-

You must validate ID tokens received from the Authentication API client before using the information they contain.

-
- - -
-

Implementation

-
final String idToken;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html deleted file mode 100644 index f9483350..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/refreshToken.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - refreshToken property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
refreshToken
- -
- -
- - -
-
-

refreshToken property - Null safety -

- -
- String? - refreshToken -
final
- -
- -
-

Token that can be used to request a new access token.

-

The scope offline_access must have been requested on login for a refresh token to be returned.

-

Read more about refresh tokens.

-
- - -
-

Implementation

-
final String? refreshToken;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html deleted file mode 100644 index b8531562..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/scopes.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - scopes property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
scopes
- -
- -
- - -
-
-

scopes property - Null safety -

- -
- Set<String> - scopes -
final
- -
- -
-

The scopes that have been grated by the authorization server.

-

Read more about scopes.

-
- - -
-

Implementation

-
final Set<String> scopes;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html b/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html deleted file mode 100644 index dc9e0078..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/Credentials/userProfile.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - userProfile property - Credentials class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
userProfile
- -
- -
- - -
-
-

userProfile property - Null safety -

- -
- UserProfile - userProfile -
final
- -
- -
-

Properties and attributes relating to the authenticated user.

-

Read more about Auth0 User Profiles

-
- - -
-

Implementation

-
final UserProfile userProfile;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html deleted file mode 100644 index 0252b60f..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig-class.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - IdTokenValidationConfig class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
IdTokenValidationConfig
- -
- -
- - -
-
-

IdTokenValidationConfig class - Null safety - -

- - -
-

Configuration settings for ID token validation.

-
- - - - -
-

Constructors

- -
-
- IdTokenValidationConfig({int? leeway, String? issuer, int? maxAge}) -
-
- -
const
-
-
-
- -
-

Properties

- -
-
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- issuer - String? - -
-
- The issuer to be used for validation of JWTs. Defaults to the domain used to when calling Auth0.new. -
final
- -
- -
- leeway - int? - -
-
- The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms. -
final
- -
- -
- maxAge - int? - -
-
- Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0. -
final
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html deleted file mode 100644 index 3e351542..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - IdTokenValidationConfig constructor - IdTokenValidationConfig - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
IdTokenValidationConfig
- -
- -
- - -
-
-

IdTokenValidationConfig constructor - Null safety -

- -
const - IdTokenValidationConfig(
  1. {int? leeway,
  2. -
  3. String? issuer,
  4. -
  5. int? maxAge}
  6. -
) -
- - - - - -
-

Implementation

-
const IdTokenValidationConfig({this.leeway, this.issuer, this.maxAge});
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html deleted file mode 100644 index f261cf25..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/issuer.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - issuer property - IdTokenValidationConfig class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
issuer
- -
- -
- - -
-
-

issuer property - Null safety -

- -
- String? - issuer -
final
- -
- -
-

The issuer to be used for validation of JWTs. Defaults to the domain used to when calling Auth0.new.

-
- - -
-

Implementation

-
final String? issuer;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html deleted file mode 100644 index 83325f1a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/leeway.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - leeway property - IdTokenValidationConfig class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
leeway
- -
- -
- - -
-
-

leeway property - Null safety -

- -
- int? - leeway -
final
- -
- -
-

The value in seconds used to account for clock skew in JWT expirations. Typically, this value is no more than a minute or two at maximum. This defaults to 60 seconds on native platforms.

-
- - -
-

Implementation

-
final int? leeway;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html b/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html deleted file mode 100644 index fc6b5ae3..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/IdTokenValidationConfig/maxAge.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - maxAge property - IdTokenValidationConfig class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
maxAge
- -
- -
- - -
-
-

maxAge property - Null safety -

- -
- int? - maxAge -
final
- -
- -
-

Maximum allowable elasped time (in seconds) since authentication. If the last time the user authenticated is greater than this value, the user must be reauthenticated. Defaults to 0.

-
- - -
-

Implementation

-
final int? maxAge;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html deleted file mode 100644 index 3fa30f59..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile-class.html +++ /dev/null @@ -1,511 +0,0 @@ - - - - - - - - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
UserProfile
- -
- -
- - -
-
-

UserProfile class - Null safety - -

- - -
-

A collection of properties that represents the authenticated user, extracted from ID token claims.

-
- - - - -
-

Constructors

- -
-
- UserProfile({required String sub, String? name, String? givenName, String? familyName, String? middleName, String? nickname, String? preferredUsername, Uri? profileURL, Uri? pictureURL, Uri? websiteURL, String? email, bool? isEmailVerified, String? gender, String? birthdate, String? zoneinfo, String? locale, String? phoneNumber, bool? isPhoneNumberVerified, Map<String, String>? address, DateTime? updatedAt, Map<String, dynamic>? customClaims}) -
-
- -
const
-
-
- UserProfile.fromMap(Map<String, dynamic> result) -
-
- -
factory
-
-
-
- -
-

Properties

- -
-
- address - Map<String, String>? - -
-
- The address of the user. -
final
- -
- -
- birthdate - String? - -
-
- The birthdate of the user. -
final
- -
- -
- customClaims - Map<String, dynamic>? - -
-
- Any custom claims -
final
- -
- -
- email - String? - -
-
- The email of the user. -
final
- -
- -
- familyName - String? - -
-
- The last name of the user. -
final
- -
- -
- gender - String? - -
-
- The gender of the user. -
final
- -
- -
- givenName - String? - -
-
- The first name of the user. -
final
- -
- -
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- isEmailVerified - bool? - -
-
- If the user's email is verified. -
final
- -
- -
- isPhoneNumberVerified - bool? - -
-
- If the user's phone number is verified. -
final
- -
- -
- locale - String? - -
-
- The locale of the user. -
final
- -
- -
- middleName - String? - -
-
- The middle name of the user. -
final
- -
- -
- name - String? - -
-
- The name of the user. -
final
- -
- -
- nickname - String? - -
-
- The nickname of the user. -
final
- -
- -
- phoneNumber - String? - -
-
- The phone number of the user. -
final
- -
- -
- pictureURL - Uri? - -
-
- The URL of the user's picture. -
final
- -
- -
- preferredUsername - String? - -
-
- The preferred username of the user. -
final
- -
- -
- profileURL - Uri? - -
-
- The URL of the user's profile page. -
final
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
- sub - String - -
-
- The Auth0 user identifier. -
final
- -
- -
- updatedAt - DateTime? - -
-
- The date and time the user's information was last updated. -
final
- -
- -
- websiteURL - Uri? - -
-
- The URL of the user's website. -
final
- -
- -
- zoneinfo - String? - -
-
- The time zone of the user. -
final
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html deleted file mode 100644 index 5063d1c2..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.fromMap.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - UserProfile.fromMap constructor - UserProfile - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
UserProfile.fromMap
- -
- -
- - -
-
-

UserProfile.fromMap constructor - Null safety -

- -
- UserProfile.fromMap(
  1. Map<String, dynamic> result
  2. -
) -
- - - - - -
-

Implementation

-
factory UserProfile.fromMap(final Map<String, dynamic> result) => UserProfile(
-      sub: result['sub'] as String,
-      name: result['name'] as String?,
-      givenName: result['given_name'] as String?,
-      familyName: result['family_name'] as String?,
-      middleName: result['middle_name'] as String?,
-      nickname: result['nickname'] as String?,
-      preferredUsername: result['preferred_username'] as String?,
-      profileURL: result['profile'] != null
-          ? Uri.parse(result['profile'] as String)
-          : null,
-      pictureURL: result['picture'] != null
-          ? Uri.parse(result['picture'] as String)
-          : null,
-      websiteURL: result['website'] != null
-          ? Uri.parse(result['website'] as String)
-          : null,
-      email: result['email'] as String?,
-      isEmailVerified: result['email_verified'] as bool?,
-      gender: result['gender'] as String?,
-      birthdate: result['birthdate'] as String?,
-      zoneinfo: result['zoneinfo'] as String?,
-      locale: result['locale'] as String?,
-      phoneNumber: result['phone_number'] as String?,
-      isPhoneNumberVerified: result['phone_number_verified'] as bool?,
-      address: result['address'] != null
-          ? Map<String, String>.from(
-              result['address'] as Map<dynamic, dynamic>)
-          : null,
-      updatedAt: result['updated_at'] != null
-          ? DateTime.parse(result['updated_at'] as String)
-          : null,
-      customClaims: result['custom_claims'] != null
-          ? Map<String, dynamic>.from(
-              result['custom_claims'] as Map<dynamic, dynamic>)
-          : null,
-    );
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html deleted file mode 100644 index 9b90b660..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/UserProfile.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - UserProfile constructor - UserProfile - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
UserProfile
- -
- -
- - -
-
-

UserProfile constructor - Null safety -

- -
const - UserProfile(
  1. {required String sub,
  2. -
  3. String? name,
  4. -
  5. String? givenName,
  6. -
  7. String? familyName,
  8. -
  9. String? middleName,
  10. -
  11. String? nickname,
  12. -
  13. String? preferredUsername,
  14. -
  15. Uri? profileURL,
  16. -
  17. Uri? pictureURL,
  18. -
  19. Uri? websiteURL,
  20. -
  21. String? email,
  22. -
  23. bool? isEmailVerified,
  24. -
  25. String? gender,
  26. -
  27. String? birthdate,
  28. -
  29. String? zoneinfo,
  30. -
  31. String? locale,
  32. -
  33. String? phoneNumber,
  34. -
  35. bool? isPhoneNumberVerified,
  36. -
  37. Map<String, String>? address,
  38. -
  39. DateTime? updatedAt,
  40. -
  41. Map<String, dynamic>? customClaims}
  42. -
) -
- - - - - -
-

Implementation

-
const UserProfile({
-  required final this.sub,
-  final this.name,
-  final this.givenName,
-  final this.familyName,
-  final this.middleName,
-  final this.nickname,
-  final this.preferredUsername,
-  final this.profileURL,
-  final this.pictureURL,
-  final this.websiteURL,
-  final this.email,
-  final this.isEmailVerified,
-  final this.gender,
-  final this.birthdate,
-  final this.zoneinfo,
-  final this.locale,
-  final this.phoneNumber,
-  final this.isPhoneNumberVerified,
-  final this.address,
-  final this.updatedAt,
-  final this.customClaims,
-});
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html deleted file mode 100644 index 1ac52639..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/address.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - address property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
address
- -
- -
- - -
-
-

address property - Null safety -

- -
- Map<String, String>? - address -
final
- -
- -
-

The address of the user.

-

Requires the address scope.

-
- - -
-

Implementation

-
final Map<String, String>? address;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html deleted file mode 100644 index cd39c5c5..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/birthdate.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - birthdate property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
birthdate
- -
- -
- - -
-
-

birthdate property - Null safety -

- -
- String? - birthdate -
final
- -
- -
-

The birthdate of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? birthdate;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html deleted file mode 100644 index 71b932ba..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/customClaims.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - customClaims property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
customClaims
- -
- -
- - -
-
-

customClaims property - Null safety -

- -
- Map<String, dynamic>? - customClaims -
final
- -
- -
-

Any custom claims

-
- - -
-

Implementation

-
final Map<String, dynamic>? customClaims;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html deleted file mode 100644 index 46e47eae..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/email.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - email property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
email
- -
- -
- - -
-
-

email property - Null safety -

- -
- String? - email -
final
- -
- -
-

The email of the user.

-

Requires the email scope.

-
- - -
-

Implementation

-
final String? email;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html deleted file mode 100644 index a230b33b..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/familyName.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - familyName property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
familyName
- -
- -
- - -
-
-

familyName property - Null safety -

- -
- String? - familyName -
final
- -
- -
-

The last name of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? familyName;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html deleted file mode 100644 index cc8833b7..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/gender.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - gender property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
gender
- -
- -
- - -
-
-

gender property - Null safety -

- -
- String? - gender -
final
- -
- -
-

The gender of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? gender;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html deleted file mode 100644 index 823d404c..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/givenName.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - givenName property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
givenName
- -
- -
- - -
-
-

givenName property - Null safety -

- -
- String? - givenName -
final
- -
- -
-

The first name of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? givenName;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html deleted file mode 100644 index f2a38192..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isEmailVerified.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - isEmailVerified property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isEmailVerified
- -
- -
- - -
-
-

isEmailVerified property - Null safety -

- -
- bool? - isEmailVerified -
final
- -
- -
-

If the user's email is verified.

-

Requires the email scope.

-
- - -
-

Implementation

-
final bool? isEmailVerified;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html deleted file mode 100644 index 1a9ed490..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/isPhoneNumberVerified.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - isPhoneNumberVerified property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
isPhoneNumberVerified
- -
- -
- - -
-
-

isPhoneNumberVerified property - Null safety -

- -
- bool? - isPhoneNumberVerified -
final
- -
- -
-

If the user's phone number is verified.

-

Requires the phone scope.

-
- - -
-

Implementation

-
final bool? isPhoneNumberVerified;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html deleted file mode 100644 index bb73dd34..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/locale.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - locale property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
locale
- -
- -
- - -
-
-

locale property - Null safety -

- -
- String? - locale -
final
- -
- -
-

The locale of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? locale;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html deleted file mode 100644 index 89257643..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/middleName.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - middleName property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
middleName
- -
- -
- - -
-
-

middleName property - Null safety -

- -
- String? - middleName -
final
- -
- -
-

The middle name of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? middleName;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html deleted file mode 100644 index 8aad3202..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/name.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - name property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
name
- -
- -
- - -
-
-

name property - Null safety -

- -
- String? - name -
final
- -
- -
-

The name of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? name;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html deleted file mode 100644 index 07463b7c..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/nickname.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - nickname property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
nickname
- -
- -
- - -
-
-

nickname property - Null safety -

- -
- String? - nickname -
final
- -
- -
-

The nickname of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? nickname;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html deleted file mode 100644 index 5f41c595..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/phoneNumber.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - phoneNumber property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
phoneNumber
- -
- -
- - -
-
-

phoneNumber property - Null safety -

- -
- String? - phoneNumber -
final
- -
- -
-

The phone number of the user.

-

Requires the phone scope.

-
- - -
-

Implementation

-
final String? phoneNumber;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html deleted file mode 100644 index ae15c4af..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/pictureURL.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - pictureURL property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
pictureURL
- -
- -
- - -
-
-

pictureURL property - Null safety -

- -
- Uri? - pictureURL -
final
- -
- -
-

The URL of the user's picture.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final Uri? pictureURL;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html deleted file mode 100644 index 9a267f77..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/preferredUsername.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - preferredUsername property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
preferredUsername
- -
- -
- - -
-
-

preferredUsername property - Null safety -

- -
- String? - preferredUsername -
final
- -
- -
-

The preferred username of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? preferredUsername;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html deleted file mode 100644 index 34087e92..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/profileURL.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - profileURL property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
profileURL
- -
- -
- - -
-
-

profileURL property - Null safety -

- -
- Uri? - profileURL -
final
- -
- -
-

The URL of the user's profile page.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final Uri? profileURL;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html deleted file mode 100644 index ce1c17c3..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/sub.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - sub property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
sub
- -
- -
- - -
-
-

sub property - Null safety -

- -
- String - sub -
final
- -
- -
-

The Auth0 user identifier.

-
- - -
-

Implementation

-
final String sub;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html deleted file mode 100644 index b6716bc9..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/updatedAt.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - updatedAt property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
updatedAt
- -
- -
- - -
-
-

updatedAt property - Null safety -

- -
- DateTime? - updatedAt -
final
- -
- -
-

The date and time the user's information was last updated.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final DateTime? updatedAt;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html deleted file mode 100644 index fda019d2..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/websiteURL.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - websiteURL property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
websiteURL
- -
- -
- - -
-
-

websiteURL property - Null safety -

- -
- Uri? - websiteURL -
final
- -
- -
-

The URL of the user's website.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final Uri? websiteURL;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html b/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html deleted file mode 100644 index 0eb5bc70..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/UserProfile/zoneinfo.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - zoneinfo property - UserProfile class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
zoneinfo
- -
- -
- - -
-
-

zoneinfo property - Null safety -

- -
- String? - zoneinfo -
final
- -
- -
-

The time zone of the user.

-

Requires the profile scope.

-
- - -
-

Implementation

-
final String? zoneinfo;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html deleted file mode 100644 index 6284b8b4..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException-class.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - WebAuthException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthException
- -
- -
- - -
-
-

WebAuthException class - Null safety - -

- - - - - - -
-

Constructors

- -
-
- WebAuthException(String code, String message, Map<String, dynamic> details) -
-
- -
const
-
-
- WebAuthException.fromPlatformException(PlatformException e) -
-
- -
-
- WebAuthException.unknown(String message) -
-
- -
const
-
-
-
- -
-

Properties

- -
-
- code - String - -
-
- -
final, inherited
- -
- -
- details - Map<String, dynamic> - -
-
- -
final, inherited
- -
- -
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- message - String - -
-
- -
final, inherited
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
-
- - -
-

Methods

-
-
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html deleted file mode 100644 index 181695d2..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - WebAuthException.fromPlatformException constructor - WebAuthException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthException.fromPlatformException
- -
- -
- - -
-
-

WebAuthException.fromPlatformException constructor - Null safety -

- -
- WebAuthException.fromPlatformException(
  1. PlatformException e
  2. -
) -
- - - - - -
-

Implementation

-
WebAuthException.fromPlatformException(final PlatformException e)
-    : this(e.code, e.messageString, e.detailsMap);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html deleted file mode 100644 index f69460c4..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - WebAuthException constructor - WebAuthException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthException
- -
- -
- - -
-
-

WebAuthException constructor - Null safety -

- -
const - WebAuthException(
  1. String code,
  2. -
  3. String message,
  4. -
  5. Map<String, dynamic> details
  6. -
) -
- - - - - -
-

Implementation

-
const WebAuthException(final String code, final String message,
-    final Map<String, dynamic> details)
-    : super(code, message, details);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html deleted file mode 100644 index ce519b9a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/WebAuthException.unknown.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - WebAuthException.unknown constructor - WebAuthException - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthException.unknown
- -
- -
- - -
-
-

WebAuthException.unknown constructor - Null safety -

- -
const - WebAuthException.unknown(
  1. String message
  2. -
) -
- - - - - -
-

Implementation

-
const WebAuthException.unknown(final String message) : super.unknown(message);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html deleted file mode 100644 index 5bae622a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/code.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - code property - WebAuthException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
code
- -
- -
- - -
-
-

code property - Null safety -

- -
- String - code -
final, inherited
- -
- - - -
-

Implementation

-
final String code;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html deleted file mode 100644 index f99e83b2..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/details.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - details property - WebAuthException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
details
- -
- -
- - -
-
-

details property - Null safety -

- -
- Map<String, dynamic> - details -
final, inherited
- -
- - - -
-

Implementation

-
final Map<String, dynamic> details;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html deleted file mode 100644 index 77051ede..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/message.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - message property - WebAuthException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
message
- -
- -
- - -
-
-

message property - Null safety -

- -
- String - message -
final, inherited
- -
- - - -
-

Implementation

-
final String message;
-
-
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html deleted file mode 100644 index 94a8b03a..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthException/toString.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - toString method - WebAuthException class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
toString
- -
- -
- - -
-
-

toString method - Null safety -

- -
- -
-
    -
  1. @override
  2. -
-
- -String -toString() - -
inherited
- -
- -
-

A string representation of this object.

-

Some classes have a default textual representation, -often paired with a static parse function (like int.parse). -These classes will provide the textual representation as -their string representation.

-

Other classes have no meaningful textual representation -that a program will care about. -Such classes will typically override toString to provide -useful information when inspecting the object, -mainly for debugging or logging.

-
- - - -
-

Implementation

-
@override
-String toString() => '$code: $message';
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html deleted file mode 100644 index 67e570fb..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication-class.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - WebAuthentication class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthentication
- -
- -
- - -
-
-

WebAuthentication class - Null safety - -

- - -
-

An interface for authenticating users using the Auth0 Universal Login page.

-

Authentication using Universal Login works by redirecting your user to a login page hosted on Auth0's servers. To achieve this on a native device, -this class uses the Auth0.Android and Auth0.Swift SDKs on Android and iOS respectively to -perform interactions with Universal Login.

-

It is not intended for you to instantiate this class yourself, as an instance of it is already exposed as Auth0.webAuthentication.

-

Usage example:

-
final auth0 = Auth0('DOMAIN', 'CLIENT_ID');
-final result = await auth0.webAuthentication.login();
-final accessToken = result.accessToken;
-
-
- - - - -
-

Constructors

- -
-
- WebAuthentication(Account _account, UserAgent _userAgent) -
-
- -
-
-
- -
-

Properties

- -
-
- hashCode - int - -
-
- The hash code for this object. -
read-only, inherited
- -
- -
- runtimeType - Type - -
-
- A representation of the runtime type of the object. -
read-only, inherited
- -
- -
-
- - -
-

Methods

-
-
- login({String? audience, Set<String> scopes = const {}, String? redirectUrl, String? organizationId, String? invitationUrl, String? scheme, bool useEphemeralSession = false, Map<String, String> parameters = const {}, IdTokenValidationConfig idTokenValidationConfig = const IdTokenValidationConfig()}) - Future<Credentials> - - - -
-
- Redirects the user to the Auth0 Universal Login page for authentication. If successful, it returns -a set of tokens, as well as the user's profile (constructed from ID token claims). - - -
- -
- logout({String? returnTo, String? scheme}) - Future<void> - - - -
-
- Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application -once logout is complete. - - -
- -
- noSuchMethod(Invocation invocation) - → dynamic - - - -
-
- Invoked when a non-existent method or property is accessed. -
inherited
- -
- -
- toString() - String - - - -
-
- A string representation of this object. -
inherited
- -
- -
-
- -
-

Operators

-
-
- operator ==(Object other) - bool - - - -
-
- The equality operator. -
inherited
- -
- -
-
- - - - - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html deleted file mode 100644 index 488b66f9..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/WebAuthentication.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - WebAuthentication constructor - WebAuthentication - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
WebAuthentication
- -
- -
- - -
-
-

WebAuthentication constructor - Null safety -

- -
- WebAuthentication(
  1. Account _account,
  2. -
  3. UserAgent _userAgent
  4. -
) -
- - - - - -
-

Implementation

-
WebAuthentication(this._account, this._userAgent);
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html deleted file mode 100644 index c6cc0c0d..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/login.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - login method - WebAuthentication class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
login
- -
- -
- - -
-
-

login method - Null safety -

- -
- - -Future<Credentials> -login(
  1. {String? audience,
  2. -
  3. Set<String> scopes = const {},
  4. -
  5. String? redirectUrl,
  6. -
  7. String? organizationId,
  8. -
  9. String? invitationUrl,
  10. -
  11. String? scheme,
  12. -
  13. bool useEphemeralSession = false,
  14. -
  15. Map<String, String> parameters = const {},
  16. -
  17. IdTokenValidationConfig idTokenValidationConfig = const IdTokenValidationConfig()}
  18. -
) - - - -
- -
-

Redirects the user to the Auth0 Universal Login page for authentication. If successful, it returns -a set of tokens, as well as the user's profile (constructed from ID token claims).

-

If redirectUrl is not specified, a default URL is used that incorporates the domain value specified to Auth0.new, and scheme on Android, or the -bundle identifier in iOS. redirectUrl must appear in your Allowed Callback URLs list for the Auth0 app. Read more about redirecting users.

-

How the ID token is validated can be configured using idTokenValidationConfig, but in general the defaults for this are adequate.

-

Additonal notes:

-
    -
  • (iOS only): useEphemeralSession controls whether shared persistent storage is used for cookies. Read more on the effects this setting has
  • -
  • (Android only): specify scheme if you're using a custom URL scheme for your app. This value must match the value used to configure the auth0Scheme manifest placeholder, for the Redirect intent filter to work
  • -
  • audience relates to the API Identifier you want to reference in your access tokens (see API settings)
  • -
  • scopes defaults to openid profile email. You can override these scopes, but openid is always requested regardless of this setting.
  • -
  • Arbitrary parameters can be specified and then picked up in a custom Auth0 Action or
  • -
  • If you want to log into a specific organization, provide the organizationId. Provide invitationUrl if a user has been invited to -join an organization. - Rule.
  • -
-
- - - -
-

Implementation

-
Future<Credentials> login({
-  final String? audience,
-  final Set<String> scopes = const {},
-  final String? redirectUrl,
-  final String? organizationId,
-  final String? invitationUrl,
-  final String? scheme,
-  final bool useEphemeralSession = false,
-  final Map<String, String> parameters = const {},
-  final IdTokenValidationConfig idTokenValidationConfig =
-      const IdTokenValidationConfig(),
-}) =>
-    Auth0FlutterWebAuthPlatform.instance.login(_createWebAuthRequest(
-        WebAuthLoginOptions(
-            audience: audience,
-            scopes: scopes,
-            redirectUrl: redirectUrl,
-            organizationId: organizationId,
-            invitationUrl: invitationUrl,
-            parameters: parameters,
-            idTokenValidationConfig: idTokenValidationConfig,
-            scheme: scheme,
-            useEphemeralSession: useEphemeralSession)));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html b/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html deleted file mode 100644 index 54ff2cfd..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/WebAuthentication/logout.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - logout method - WebAuthentication class - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
logout
- -
- -
- - -
-
-

logout method - Null safety -

- -
- - -Future<void> -logout(
  1. {String? returnTo,
  2. -
  3. String? scheme}
  4. -
) - - - -
- -
-

Redirects the user to the Auth0 Logout endpoint to remove their authentication session, and log out. The user is immediately redirected back to the application -once logout is complete.

-

If returnTo is not specified, a default URL is used that incorporates the domain value specified to Auth0.new, and scheme on Android, or the -bundle identifier in iOS. returnTo must appear in your Allowed Logout URLs list for the Auth0 app. Read more about redirecting users after logout.

-

(Android only): scheme must match the scheme that was used to configure the auth0Scheme manifest placeholder

-
- - - -
-

Implementation

-
Future<void> logout({final String? returnTo, final String? scheme}) =>
-    Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest(
-      WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme),
-    ));
-
- - -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html b/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html deleted file mode 100644 index 7f0f8c59..00000000 --- a/auth0_flutter/doc/api/auth0_flutter/auth0_flutter-library.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - auth0_flutter library - Dart API - - - - - - - - - - - - - - - - - -
- -
- - -
auth0_flutter
- -
- -
- - -
-
-

auth0_flutter library - Null safety - -

- - - - -
-

Classes

- -
-
- Auth0 - -
-
- Primary interface for interacting with Auth0 using web authentication, or the authentication API. -
- -
- AuthenticationApi - -
-
- An interface for calling some of the endpoints in Auth0's Authentication API. -
- -
- Credentials - -
-
- A collection of authentication artifacts obtained from Auth0 when a user logs in. -
- -
- IdTokenValidationConfig - -
-
- Configuration settings for ID token validation. -
- -
- UserProfile - -
-
- A collection of properties that represents the authenticated user, extracted from ID token claims. -
- -
- WebAuthentication - -
-
- An interface for authenticating users using the Auth0 Universal Login page. -
- -
-
- - - - - - - - -
-

Exceptions / Errors

- -
-
- ApiException - -
-
- -
- -
- WebAuthException - -
-
- -
- -
-
- -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/categories.json b/auth0_flutter/doc/api/categories.json deleted file mode 100644 index fe51488c..00000000 --- a/auth0_flutter/doc/api/categories.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/auth0_flutter/doc/api/index.html b/auth0_flutter/doc/api/index.html deleted file mode 100644 index 302f18fc..00000000 --- a/auth0_flutter/doc/api/index.html +++ /dev/null @@ -1,473 +0,0 @@ - - - - - - - - - auth0_flutter - Dart API docs - - - - - - - - - - - - - - - - - -
- -
- - -
auth0_flutter
- -
- -
- - -
- -
-

Auth0 SDK for Flutter (Beta)

-

CircleCI

-

Auth0 SDK for Android / iOS Flutter apps.

-
-

โš ๏ธ This library is currently in Beta. We do not recommend using this library in production yet. As we move towards First Availability, please be aware that releases may contain breaking changes.

-
-
-

Table of Contents

- -

Requirements

-
FlutterAndroidiOS
SDK 3.0+Android API 21+iOS 12+
Dart 2.17+Java 8+Swift 5.3+
Xcode 12.x / 13.x
-

Installation

-

During the Beta stage the SDK will not be published to Pub.dev, but you can install it as a path package. Extract the contents of the provided zip file and then add the following dependency in your pubspec.yaml file:

-
auth0_flutter:
-    path: path/to/auth0_flutter
-
-

Then, run flutter pub get.

-

Getting Started

-

Configuration

-

auth0_flutter needs the Client ID and Domain of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your Auth0 application. If you are using a Custom Domain, use the value of your Custom Domain instead of the value from the settings page.

-
-

โš ๏ธ Make sure that the application type of the Auth0 application is Native. If you donโ€™t have a Native Auth0 application already, create one before continuing.

-
-
final auth0 = Auth0('YOUR_AUTH0_DOMAIN', 'YOUR_AUTH0_CLIENT_ID');
-
-

Web Auth Configuration

- -

Configure callback and logout URLs

-

The callback and logout URLs are the URLs that Auth0 invokes to redirect back to your app. Auth0 invokes the callback URL after authenticating the user, and the logout URL after removing the session cookie.

-

Since callback and logout URLs can be manipulated, you will need to add your URLs to the Allowed Callback URLs and Allowed Logout URLs fields in the settings page of your Auth0 application. This will enable Auth0 to recognize these URLs as valid. If the callback and logout URLs are not set, users will be unable to log in and out of the app and will get an error.

-

Go to the settings page of your Auth0 application and add the corresponding URLs to Allowed Callback URLs and Allowed Logout URLs, according to the platforms used by your app. If you are using a Custom Domain, replace YOUR_AUTH0_DOMAIN with the value of your Custom Domain instead of the value from the settings page.

-
Android
-
https://YOUR_AUTH0_DOMAIN/android/YOUR_APP_PACKAGE_NAME/callback
-
-

E.g. if your Auth0 Domain was company.us.auth0.com and your Android app package name was com.company.myapp, then this value would be:

-
https://company.us.auth0.com/android/com.company.myapp/callback
-
-
iOS
-
YOUR_BUNDLE_IDENTIFIER://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback
-
-

E.g. if your iOS bundle identifier was com.company.myapp and your Auth0 Domain was company.us.auth0.com, then this value would be:

-
com.company.myapp://company.us.auth0.com/ios/com.company.myapp/callback
-
-

Android configuration: manifest placeholders

-

Open the android/build.gradle file and add the following manifest placeholders inside android > defaultConfig. The applicationId value will be auto-replaced at runtime with your Android app package name.

-
// android/build.gradle
-
-android {
-    // ...
-    defaultConfig {
-        // ...
-        // Add the following line
-        manifestPlaceholders = [auth0Domain: "YOUR_AUTH0_DOMAIN", auth0Scheme: "${applicationId}"]
-    }
-    // ...
-}
-
-

E.g. if your Auth0 Domain was company.us.auth0.com, then the manifest placeholders line would be:

-
manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${applicationId}"]
-
-
-

๐Ÿ’ก If your Android app is using product flavors, you might need to specify different manifest placeholders for each flavor.

-
- Skipping the Android Web Auth configuration -

If you don't plan to use Web Auth, you will notice that the compiler will still prompt you to provide the manifestPlaceholders values, since the RedirectActivity included in this library will require them, and the Gradle tasks won't be able to run without them.

-

Re-declare the activity manually using tools:node="remove" in the android/src/main/AndroidManifest.xml file to make the manifest merger remove it from the final manifest file. Additionally, one more unused activity can be removed from the final APK by using the same process. A complete snippet to achieve this is:

-
  <!-- android/src/main/AndroidManifest.xml -->
-
-  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      xmlns:tools="http://schemas.android.com/tools"
-      package="com.company.myapp">
-      <application android:theme="@style/AppTheme">
-          <!-- ... -->
-    
-          <activity
-              android:name="com.auth0.android.provider.AuthenticationActivity"
-              tools:node="remove"/>
-          <!-- Optional: Remove RedirectActivity -->
-          <activity
-              android:name="com.auth0.android.provider.RedirectActivity"
-              tools:node="remove"/>
-    
-          <!-- ... -->
-      </application>
-  </manifest>
-
-

iOS configuration: custom URL scheme

-

Open the ios/Runner/Info.plist file and add the following snippet inside the top-level <dict> tag. This registers your iOS Bundle Identifier as a custom URL scheme, so the callback and logout URLs can reach your app.

-
<!-- ios/Runner/Info.plist -->
-
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-<!-- ... -->
-
-    <key>CFBundleURLTypes</key>
-    <array>
-        <dict>
-            <key>CFBundleTypeRole</key>
-            <string>None</string>
-            <key>CFBundleURLName</key>
-            <string>auth0</string>
-            <key>CFBundleURLSchemes</key>
-            <array>
-                <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-            </array>
-        </dict>
-    </array>
-  
-<!-- ... -->
-</dict>
-</plist>
-
-
-

๐Ÿ’ก If you're opening the Info.plist file in Xcode and it is not being shown in this format, you can Right Click on Info.plist in the Xcode project navigator and then select Open As > Source Code.

-
-

Web Auth Login

-

Import auth0_flutter in the file where you want to present the login page.

-
import 'package:auth0_flutter/auth0_flutter.dart';
-
-

Then, present the Universal Login page in the onPressed callback of your Login button.

-
final result = await auth0.webAuthentication.login();
-
- Add an audience value -

Specify an audience to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the API Identifier of your Auth0 API, e.g. https://example.com/api.

-
  final result = await auth0.webAuthentication
-      .login(audience: 'YOUR_AUTH0_API_IDENTIFIER');
-
- Add scope values -

Specify scopes to request permission to access protected resources, like the user profile. The default scope values are openid, profile and email. Regardless of the values specified, openid is always included.

-
  final result = await auth0.webAuthentication
-      .login(scopes: {'profile', 'email', 'offline_access', 'read:todos'});
-
- Add a custom scheme value (Android-only) -

On Android, auth0_flutter uses https by default as the callback URL scheme. This works best for Android API 23+ if you're using Android App Links, but in previous Android versions this may show the intent chooser dialog prompting the user to choose either your app or the browser. You can change this behavior by using a custom unique scheme so that Android opens the link directly with your app. Note that schemes can only have lowercase letters.

-
    -
  1. Update the auth0Scheme manifest placeholder on the android/build.gradle file.
  2. -
  3. Update the Allowed Callback URLs in the settings page of your Auth0 application.
  4. -
  5. Pass the scheme value to the login() method.
  6. -
-
  final result = await auth0.webAuthentication.login(scheme: {'demo'});
-
-

Web Auth Logout

-

Logging the user out involves clearing the Universal Login session cookie and then deleting the user's credentials from your app.

-

Call the logout() method in the in the onPressed callback of your Logout button. Once the session cookie has been cleared, delete the user's credentials.<!-- link to the section on deleting the stored credentials -->

-
await auth0.webAuthentication.logout();
-
-

SSO Alert Box (iOS)

-

ios-sso-alert

-

Check the FAQ for more information about the alert box that pops up by default when using Web Auth on iOS.

-
-

๐Ÿ’ก See also this blog post for a detailed overview of Single Sign-On (SSO) on iOS.

-
-

Go up โคด

-

Next Steps

-

Web Auth

- -

Web Auth signup

-

You can make users land directly on the Signup page instead of the Login page by specifying the 'screen_hint': 'signup' parameter. Note that this can be combined with 'prompt': 'login', which indicates whether you want to always show the authentication page or you want to skip if there's an existing session.

-
ParametersNo existing sessionExisting session
No extra parametersShows the login pageRedirects to the callback url
'screen_hint': 'signup'Shows the signup pageRedirects to the callback url
'prompt': 'login'Shows the login pageShows the login page
'prompt': 'login', 'screen_hint': 'signup'Shows the signup pageShows the signup page
-
final result = await auth0.webAuthentication
-    .login(parameters: {'screen_hint': 'signup'});
-
-
-

โš ๏ธ The screen_hint parameter will work with the New Universal Login Experience without any further configuration. If you are using the Classic Universal Login Experience, you need to customize the login template to look for this parameter and set the initialScreen option of the Auth0Lock constructor.

-
-

ID Token validation

-

auth0_flutter automatically validates the ID Token obtained from Web Auth login, following the OpenID Connect specification. This ensures the contents of the ID Token have not been tampered with and can be safely used.

-
Custom Domains
-

Users of Auth0 Private Cloud with Custom Domains still on the legacy behavior need to specify a custom issuer to match the Auth0 Domain when performing Web Auth login. Otherwise, the ID Token validation will fail.

-
final config = IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/');
-final result =
-    await auth0.webAuthentication.login(idTokenValidationConfig: config);
-
-

Web Auth errors

-

Web Auth will only throw WebAuthException exceptions.<!-- Check the API documentation link to API documentation to learn more about the available WebAuthException properties. -->

-
try {
-  final result = await auth0.webAuthentication.login();
-  // ...
-} on WebAuthException catch (e) {
-  print(e.toString())
-}
-
-

API

- -

The Authentication API exposes the AuthN/AuthZ functionality of Auth0, as well as the supported identity protocols like OpenID Connect, OAuth 2.0, and SAML. -We recommend using Universal Login, but if you prefer to build your own UI you can use our API endpoints to do so. However, some Auth flows (grant types) are disabled by default so you must enable them in the settings page of your Auth0 application, as explained in Update Grant Types.

-

For login or signup with username/password, the Password grant type needs to be enabled in your app. If you set the grants via the Management API you should activate both http://auth0.com/oauth/grant-type/password-realm and Password. Otherwise, the Auth0 Dashboard will take care of activating both when enabling Password.

-
-

๐Ÿ’ก If your Auth0 account has the Bot Detection feature enabled, your requests might be flagged for verification. Check how to handle this scenario in the Bot Detection section.

-
-
-

โš ๏ธ The ID Tokens obtained from Web Auth login are automatically validated by auth0_flutter, ensuring their contents have not been tampered with. This is not the case for the ID Tokens obtained from the Authentication API client. You must validate any ID Tokens received from the Authentication API client before using the information they contain.

-
-

Login with database connection

-
final result = await auth0.api.login(
-    usernameOrEmail: 'jane.smith@example.com',
-    password: 'secret-password',
-    connectionOrRealm: 'Username-Password-Authentication');
-
- Add an audience value -

Specify an audience to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the API Identifier of your Auth0 API, e.g. https://example.com/api.

-
  final result = await auth0.api.login(
-      usernameOrEmail: 'jane.smith@example.com',
-      password: 'secret-password',
-      connectionOrRealm: 'Username-Password-Authentication',
-      audience: 'YOUR_AUTH0_API_IDENTIFIER');
-
- Add scope values -

Specify scopes to request permission to access protected resources, like the user profile. The default scope values are openid, profile and email. Regardless of the values specified, openid is always included.

-
  final result = await auth0.api.login(
-      usernameOrEmail: 'jane.smith@example.com',
-      password: 'secret-password',
-      connectionOrRealm: 'Username-Password-Authentication',
-      scopes: {'profile', 'email', 'offline_access', 'read:todos'});
-
-

Sign up with database connection

-
final user = await auth0.api.signup(
-    email: 'jane.smith@example.com',
-    password: 'secret-password',
-    connection: 'Username-Password-Authentication',
-    userMetadata: {'first_name': 'Jane', 'last_name': 'Smith'});
-
-
-

๐Ÿ’ก You might want to log the user in after signup. See Login with database connection above for an example.

-
-

Retrieve user information

-

Fetch the latest user information from the /userinfo endpoint.

-

This method will yield a UserProfile instance.<!--Check the API documentation link to API documentation to learn more about its available properties. -->

-
final userProfile = await auth0.api.userInfo(accessToken: accessToken);
-
-

Renew credentials

-

Use a Refresh Token to renew the user's credentials. It's recommended that you read and understand the Refresh Token process beforehand.

-
final result = await auth0.api.renewCredentials(refreshToken: refreshToken);
-
-
-

๐Ÿ’ก To obtain a Refresh Token, make sure your Auth0 application has the Refresh Token grant enabled. If you are also specifying an audience value, make sure that the corresponding Auth0 API has the Allow Offline Access setting enabled.

-
-

API client errors

-

The Authentication API client will only throw ApiException exceptions. You can find more information in the details property of the exception.<!--Check the API documentation link to API documentation to learn more about the available ApiException properties. -->

-
try {
-  final result = await auth0.api.login(
-    usernameOrEmail: email,
-    password: password,
-    connectionOrRealm: connection);
-  // ...
-} on ApiException catch (e) {
-  print(e.toString())
-}
-
-

Go up โคด

-

Advanced Features

-

Organizations

-

Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.

-

Using Organizations, you can:

-
    -
  • Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations.
  • -
  • Manage their membership in a variety of ways, including user invitation.
  • -
  • Configure branded, federated login flows for each organization.
  • -
  • Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations.
  • -
  • Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations.
  • -
-
-

๐Ÿ’ก Organizations is currently only available to customers on our Enterprise and Startup subscription plans.

-
-

Log in to an organization

-
final result = await auth0.webAuthentication
-    .login(organizationId: 'YOUR_AUTH0_ORGANIZATION_ID');
-
-

Accept user invitations

-

To accept organization invitations your app needs to support deep linking, as invitation links are HTTPS-only. Tapping on the invitation link should open your app.

-

When your app gets opened by an invitation link, grab the invitation URL and pass it to the login() method.

-
final result = await auth0.webAuthentication.login(invitationUrl: url);
-
-

Bot Detection

-

If you are performing database login/signup via the Authentication API and would like to use the Bot Detection feature, you need to handle the isVerificationRequired error. It indicates that the request was flagged as suspicious and an additional verification step is necessary to log the user in. That verification step is web-based, so you need to use Web Auth to complete it.

-
try {
-  final result = await auth0.api.login(
-      usernameOrEmail: email,
-      password: password,
-      connectionOrRealm: connection,
-      scopes: scopes);
-  // ...
-} on ApiException catch (e) {
-  if (e.isVerificationRequired) {
-    final result = await auth0.webAuthentication.login(
-        scopes: scopes,
-        useEphemeralSession: true, // Otherwise a session cookie will remain (iOS-only)
-        parameters: {
-          'connection': connection,
-          'login_hint': email // So the user doesn't have to type it again
-        });
-    // ...
-  }
-}
-
-

Issue Reporting

-

For general support or usage questions, use the Auth0 Community forums or raise a support ticket. Only raise an issue if you have found a bug or want to request a feature.

-

Do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

-

What is Auth0?

-

Auth0 helps you to:

-
    -
  • Add authentication with multiple sources, either social identity providers such as Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce (amongst others), or enterprise identity systems like Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider.
  • -
  • Add authentication through more traditional username/password databases.
  • -
  • Add support for linking different user accounts with the same user.
  • -
  • Support for generating signed JSON Web Tokens to call your APIs and flow the user identity securely.
  • -
  • Analytics of how, when, and where users are logging in.
  • -
  • Pull data from other sources and add it to the user profile through JavaScript Actions.
  • -
-

Why Auth0? Because you should save time, be happy, and focus on what really matters: building your product.

-

License

-

This project is licensed under the MIT license. See the LICENSE file for more information.

-
-

Go up โคด

-
- - -
-

Libraries

-
-
- auth0_flutter - -
-
-
- -
-
- -
- - - - - -
- -
- - auth0_flutter - 1.0.0-beta.0 - - - -
- - - - - - - - - - - - diff --git a/auth0_flutter/doc/api/index.json b/auth0_flutter/doc/api/index.json deleted file mode 100644 index 98e3f3f4..00000000 --- a/auth0_flutter/doc/api/index.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"auth0_flutter","qualifiedName":"auth0_flutter","href":"auth0_flutter/auth0_flutter-library.html","type":"library","overriddenDepth":0,"packageName":"auth0_flutter"},{"name":"ApiException","qualifiedName":"auth0_flutter.ApiException","href":"auth0_flutter/ApiException-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"ApiException","qualifiedName":"auth0_flutter.ApiException.ApiException","href":"auth0_flutter/ApiException/ApiException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"code","qualifiedName":"auth0_flutter.ApiException.code","href":"auth0_flutter/ApiException/code.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"details","qualifiedName":"auth0_flutter.ApiException.details","href":"auth0_flutter/ApiException/details.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"ApiException.fromPlatformException","qualifiedName":"auth0_flutter.ApiException.fromPlatformException","href":"auth0_flutter/ApiException/ApiException.fromPlatformException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isAccessDenied","qualifiedName":"auth0_flutter.ApiException.isAccessDenied","href":"auth0_flutter/ApiException/isAccessDenied.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isBrowserAppNotAvailable","qualifiedName":"auth0_flutter.ApiException.isBrowserAppNotAvailable","href":"auth0_flutter/ApiException/isBrowserAppNotAvailable.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isCanceled","qualifiedName":"auth0_flutter.ApiException.isCanceled","href":"auth0_flutter/ApiException/isCanceled.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidAuthorizeURL","qualifiedName":"auth0_flutter.ApiException.isInvalidAuthorizeURL","href":"auth0_flutter/ApiException/isInvalidAuthorizeURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidConfiguration","qualifiedName":"auth0_flutter.ApiException.isInvalidConfiguration","href":"auth0_flutter/ApiException/isInvalidConfiguration.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isInvalidCredentials","qualifiedName":"auth0_flutter.ApiException.isInvalidCredentials","href":"auth0_flutter/ApiException/isInvalidCredentials.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isLoginRequired","qualifiedName":"auth0_flutter.ApiException.isLoginRequired","href":"auth0_flutter/ApiException/isLoginRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorCodeInvalid","qualifiedName":"auth0_flutter.ApiException.isMultifactorCodeInvalid","href":"auth0_flutter/ApiException/isMultifactorCodeInvalid.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorEnrollRequired","qualifiedName":"auth0_flutter.ApiException.isMultifactorEnrollRequired","href":"auth0_flutter/ApiException/isMultifactorEnrollRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorRequired","qualifiedName":"auth0_flutter.ApiException.isMultifactorRequired","href":"auth0_flutter/ApiException/isMultifactorRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isMultifactorTokenInvalid","qualifiedName":"auth0_flutter.ApiException.isMultifactorTokenInvalid","href":"auth0_flutter/ApiException/isMultifactorTokenInvalid.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isNetworkError","qualifiedName":"auth0_flutter.ApiException.isNetworkError","href":"auth0_flutter/ApiException/isNetworkError.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPKCENotAvailable","qualifiedName":"auth0_flutter.ApiException.isPKCENotAvailable","href":"auth0_flutter/ApiException/isPKCENotAvailable.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordAlreadyUsed","qualifiedName":"auth0_flutter.ApiException.isPasswordAlreadyUsed","href":"auth0_flutter/ApiException/isPasswordAlreadyUsed.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordLeaked","qualifiedName":"auth0_flutter.ApiException.isPasswordLeaked","href":"auth0_flutter/ApiException/isPasswordLeaked.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isPasswordNotStrongEnough","qualifiedName":"auth0_flutter.ApiException.isPasswordNotStrongEnough","href":"auth0_flutter/ApiException/isPasswordNotStrongEnough.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isRefreshTokenDeleted","qualifiedName":"auth0_flutter.ApiException.isRefreshTokenDeleted","href":"auth0_flutter/ApiException/isRefreshTokenDeleted.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isRuleError","qualifiedName":"auth0_flutter.ApiException.isRuleError","href":"auth0_flutter/ApiException/isRuleError.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isTooManyAttempts","qualifiedName":"auth0_flutter.ApiException.isTooManyAttempts","href":"auth0_flutter/ApiException/isTooManyAttempts.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"isVerificationRequired","qualifiedName":"auth0_flutter.ApiException.isVerificationRequired","href":"auth0_flutter/ApiException/isVerificationRequired.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"message","qualifiedName":"auth0_flutter.ApiException.message","href":"auth0_flutter/ApiException/message.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"statusCode","qualifiedName":"auth0_flutter.ApiException.statusCode","href":"auth0_flutter/ApiException/statusCode.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"toString","qualifiedName":"auth0_flutter.ApiException.toString","href":"auth0_flutter/ApiException/toString.html","type":"method","overriddenDepth":1,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"ApiException.unknown","qualifiedName":"auth0_flutter.ApiException.unknown","href":"auth0_flutter/ApiException/ApiException.unknown.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"ApiException","type":"class"}},{"name":"Auth0","qualifiedName":"auth0_flutter.Auth0","href":"auth0_flutter/Auth0-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"Auth0","qualifiedName":"auth0_flutter.Auth0.Auth0","href":"auth0_flutter/Auth0/Auth0.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"api","qualifiedName":"auth0_flutter.Auth0.api","href":"auth0_flutter/Auth0/api.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"webAuthentication","qualifiedName":"auth0_flutter.Auth0.webAuthentication","href":"auth0_flutter/Auth0/webAuthentication.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Auth0","type":"class"}},{"name":"AuthenticationApi","qualifiedName":"auth0_flutter.AuthenticationApi","href":"auth0_flutter/AuthenticationApi-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"AuthenticationApi","qualifiedName":"auth0_flutter.AuthenticationApi.AuthenticationApi","href":"auth0_flutter/AuthenticationApi/AuthenticationApi.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"login","qualifiedName":"auth0_flutter.AuthenticationApi.login","href":"auth0_flutter/AuthenticationApi/login.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"renewCredentials","qualifiedName":"auth0_flutter.AuthenticationApi.renewCredentials","href":"auth0_flutter/AuthenticationApi/renewCredentials.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"resetPassword","qualifiedName":"auth0_flutter.AuthenticationApi.resetPassword","href":"auth0_flutter/AuthenticationApi/resetPassword.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"signup","qualifiedName":"auth0_flutter.AuthenticationApi.signup","href":"auth0_flutter/AuthenticationApi/signup.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"userProfile","qualifiedName":"auth0_flutter.AuthenticationApi.userProfile","href":"auth0_flutter/AuthenticationApi/userProfile.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"AuthenticationApi","type":"class"}},{"name":"Credentials","qualifiedName":"auth0_flutter.Credentials","href":"auth0_flutter/Credentials-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"Credentials","qualifiedName":"auth0_flutter.Credentials.Credentials","href":"auth0_flutter/Credentials/Credentials.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"accessToken","qualifiedName":"auth0_flutter.Credentials.accessToken","href":"auth0_flutter/Credentials/accessToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"expiresAt","qualifiedName":"auth0_flutter.Credentials.expiresAt","href":"auth0_flutter/Credentials/expiresAt.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"Credentials.fromMap","qualifiedName":"auth0_flutter.Credentials.fromMap","href":"auth0_flutter/Credentials/Credentials.fromMap.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"idToken","qualifiedName":"auth0_flutter.Credentials.idToken","href":"auth0_flutter/Credentials/idToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"refreshToken","qualifiedName":"auth0_flutter.Credentials.refreshToken","href":"auth0_flutter/Credentials/refreshToken.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"scopes","qualifiedName":"auth0_flutter.Credentials.scopes","href":"auth0_flutter/Credentials/scopes.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"userProfile","qualifiedName":"auth0_flutter.Credentials.userProfile","href":"auth0_flutter/Credentials/userProfile.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"Credentials","type":"class"}},{"name":"IdTokenValidationConfig","qualifiedName":"auth0_flutter.IdTokenValidationConfig","href":"auth0_flutter/IdTokenValidationConfig-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"IdTokenValidationConfig","qualifiedName":"auth0_flutter.IdTokenValidationConfig.IdTokenValidationConfig","href":"auth0_flutter/IdTokenValidationConfig/IdTokenValidationConfig.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"issuer","qualifiedName":"auth0_flutter.IdTokenValidationConfig.issuer","href":"auth0_flutter/IdTokenValidationConfig/issuer.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"leeway","qualifiedName":"auth0_flutter.IdTokenValidationConfig.leeway","href":"auth0_flutter/IdTokenValidationConfig/leeway.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"maxAge","qualifiedName":"auth0_flutter.IdTokenValidationConfig.maxAge","href":"auth0_flutter/IdTokenValidationConfig/maxAge.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"IdTokenValidationConfig","type":"class"}},{"name":"UserProfile","qualifiedName":"auth0_flutter.UserProfile","href":"auth0_flutter/UserProfile-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"UserProfile","qualifiedName":"auth0_flutter.UserProfile.UserProfile","href":"auth0_flutter/UserProfile/UserProfile.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"address","qualifiedName":"auth0_flutter.UserProfile.address","href":"auth0_flutter/UserProfile/address.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"birthdate","qualifiedName":"auth0_flutter.UserProfile.birthdate","href":"auth0_flutter/UserProfile/birthdate.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"customClaims","qualifiedName":"auth0_flutter.UserProfile.customClaims","href":"auth0_flutter/UserProfile/customClaims.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"email","qualifiedName":"auth0_flutter.UserProfile.email","href":"auth0_flutter/UserProfile/email.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"familyName","qualifiedName":"auth0_flutter.UserProfile.familyName","href":"auth0_flutter/UserProfile/familyName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"UserProfile.fromMap","qualifiedName":"auth0_flutter.UserProfile.fromMap","href":"auth0_flutter/UserProfile/UserProfile.fromMap.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"gender","qualifiedName":"auth0_flutter.UserProfile.gender","href":"auth0_flutter/UserProfile/gender.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"givenName","qualifiedName":"auth0_flutter.UserProfile.givenName","href":"auth0_flutter/UserProfile/givenName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"isEmailVerified","qualifiedName":"auth0_flutter.UserProfile.isEmailVerified","href":"auth0_flutter/UserProfile/isEmailVerified.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"isPhoneNumberVerified","qualifiedName":"auth0_flutter.UserProfile.isPhoneNumberVerified","href":"auth0_flutter/UserProfile/isPhoneNumberVerified.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"locale","qualifiedName":"auth0_flutter.UserProfile.locale","href":"auth0_flutter/UserProfile/locale.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"middleName","qualifiedName":"auth0_flutter.UserProfile.middleName","href":"auth0_flutter/UserProfile/middleName.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"name","qualifiedName":"auth0_flutter.UserProfile.name","href":"auth0_flutter/UserProfile/name.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"nickname","qualifiedName":"auth0_flutter.UserProfile.nickname","href":"auth0_flutter/UserProfile/nickname.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"phoneNumber","qualifiedName":"auth0_flutter.UserProfile.phoneNumber","href":"auth0_flutter/UserProfile/phoneNumber.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"pictureURL","qualifiedName":"auth0_flutter.UserProfile.pictureURL","href":"auth0_flutter/UserProfile/pictureURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"preferredUsername","qualifiedName":"auth0_flutter.UserProfile.preferredUsername","href":"auth0_flutter/UserProfile/preferredUsername.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"profileURL","qualifiedName":"auth0_flutter.UserProfile.profileURL","href":"auth0_flutter/UserProfile/profileURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"sub","qualifiedName":"auth0_flutter.UserProfile.sub","href":"auth0_flutter/UserProfile/sub.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"updatedAt","qualifiedName":"auth0_flutter.UserProfile.updatedAt","href":"auth0_flutter/UserProfile/updatedAt.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"websiteURL","qualifiedName":"auth0_flutter.UserProfile.websiteURL","href":"auth0_flutter/UserProfile/websiteURL.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"zoneinfo","qualifiedName":"auth0_flutter.UserProfile.zoneinfo","href":"auth0_flutter/UserProfile/zoneinfo.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"UserProfile","type":"class"}},{"name":"WebAuthException","qualifiedName":"auth0_flutter.WebAuthException","href":"auth0_flutter/WebAuthException-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"WebAuthException","qualifiedName":"auth0_flutter.WebAuthException.WebAuthException","href":"auth0_flutter/WebAuthException/WebAuthException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"code","qualifiedName":"auth0_flutter.WebAuthException.code","href":"auth0_flutter/WebAuthException/code.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"details","qualifiedName":"auth0_flutter.WebAuthException.details","href":"auth0_flutter/WebAuthException/details.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthException.fromPlatformException","qualifiedName":"auth0_flutter.WebAuthException.fromPlatformException","href":"auth0_flutter/WebAuthException/WebAuthException.fromPlatformException.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"message","qualifiedName":"auth0_flutter.WebAuthException.message","href":"auth0_flutter/WebAuthException/message.html","type":"property","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"toString","qualifiedName":"auth0_flutter.WebAuthException.toString","href":"auth0_flutter/WebAuthException/toString.html","type":"method","overriddenDepth":1,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthException.unknown","qualifiedName":"auth0_flutter.WebAuthException.unknown","href":"auth0_flutter/WebAuthException/WebAuthException.unknown.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthException","type":"class"}},{"name":"WebAuthentication","qualifiedName":"auth0_flutter.WebAuthentication","href":"auth0_flutter/WebAuthentication-class.html","type":"class","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"auth0_flutter","type":"library"}},{"name":"WebAuthentication","qualifiedName":"auth0_flutter.WebAuthentication.WebAuthentication","href":"auth0_flutter/WebAuthentication/WebAuthentication.html","type":"constructor","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}},{"name":"login","qualifiedName":"auth0_flutter.WebAuthentication.login","href":"auth0_flutter/WebAuthentication/login.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}},{"name":"logout","qualifiedName":"auth0_flutter.WebAuthentication.logout","href":"auth0_flutter/WebAuthentication/logout.html","type":"method","overriddenDepth":0,"packageName":"auth0_flutter","enclosedBy":{"name":"WebAuthentication","type":"class"}}] diff --git a/auth0_flutter/doc/api/static-assets/favicon.png b/auth0_flutter/doc/api/static-assets/favicon.png deleted file mode 100644 index 43d2ffa079ca147a221437817dbc694d66a2a302..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1767 zcmVr1gM)#AhSs$=eK0WK)CF2vH5m*T78Vv7 zOqGGvxA(cvvG46mUuvh$T1!8DmE**HzxO9;TsuQliJN|J!pK@zgpAc6W;K`ZbSrnoP`wF$fl7_5*8Ivypwf=W;~ z;08%MQORYPC_tGHZSh$O#Av43|^d-UX&HM!T~7!)g1(@JfEf{VV=B< z1V2h$vz|_)(42Iv;nMQ6gnaC=x-iE)V9>bg95MTIge3HB2W~Qqm*!+BpztvG$qKPZI96W} zvtB&GrNG5*kOai6|CR7-+*88m$TiE!O#Aqvg{$I60STah90fcj;bJTAHe50;DvqB` zEg>!%3Dgd1>303*qUn95wS&WE(*hLuC37)V?aQjQ(>?on4V>`^}$4&P2qUwF63p3!p z6R>6i5YrB(Dm-K?OMsE#XJVfc&SVMlTc3)@NKU0J3269ELe@xN0Za64hocS>SoY(& zL%m;r$g#En;{)>X$|7Ng63+K0K^DLzXfDCDx@#YPVSI{DxIP(XJHy#-j`B3b#X_yixgMa&bn3s?yPcssC4`0@Pr z>UDqkrA2oMvH(^Il;ArzoKINx_2)YKwKcf{c=joHgRLFHM+xq^ZVMp3+9h+pM_8DNoMAB-dVobWmYAS9rt1as~o-UgNSX!>_*0eKDx64<-L zsr_Sf&ksWK5X_wO=HsvVW@R@4avN{~b`kO)Q2hp=EFi=-pa;L0N~k1s7QiKN5q3y| z{H02#@|Qmd>8SNrVChicf`ASZgo+R(>{|f;A|&P#WC45@h!O<2gp5n*5WLs|%h5Io z&-zA4k|2tpV}-BR_;rW=0{Hbbr8g2rC_$(INdgxkz-9uI;7AhAx(eXe)2I^YTj5fu z07-%@V%uQ+#@-^?#TPmIvVf-~Xcr}rfKnDf$id05c9_^NzK{etcv%3Kz^)CFfYM7u z0sTc>5&YuI)(f)z1qhX(H3Ggi0-)qG;MpQ%*z;uxJkb6E_~m7Pp-})}1w7y{P|87X zMF?8JdR00$fprxiY?Jv$f)^#)PoTa$P7;P^(nEroXQBYUjX$q968u%Jy_6(e-Iwpz z`wQ&juE(vPtb`I*EA&`h0mZHYjw%V!O;ZVLl+daK6k%2i_w{N+cwBf+b515f%gmO% z0;CNdCA9us9ZyP?@Hi6?I4mR~j0z_-S>8&HnB#ImfGojJKnEEBu4V8D90ETn>T?(4 zMG`tr=$)vA?}qayISJ<{js z)mqSPcf)OyC94E3VQ2vf2>>`6^tPFngqTYhz5-+c150@O0%QqqUjRvn1qp9gfGmM1 zUw{G;1RSy*Qj(CpFloi)@B(OKcajFkv|3YK_es*=t)6!)-Mumr002ov JPDHLkV1ksy9Tflo diff --git a/auth0_flutter/doc/api/static-assets/github.css b/auth0_flutter/doc/api/static-assets/github.css deleted file mode 100644 index 791932b8..00000000 --- a/auth0_flutter/doc/api/static-assets/github.css +++ /dev/null @@ -1,99 +0,0 @@ -/* - -github.com style (c) Vasily Polovnyov - -*/ - -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - color: #333; - background: #f8f8f8; -} - -.hljs-comment, -.hljs-quote { - color: #998; - font-style: italic; -} - -.hljs-keyword, -.hljs-selector-tag, -.hljs-subst { - color: #333; - font-weight: bold; -} - -.hljs-number, -.hljs-literal, -.hljs-variable, -.hljs-template-variable, -.hljs-tag .hljs-attr { - color: #008080; -} - -.hljs-string, -.hljs-doctag { - color: #d14; -} - -.hljs-title, -.hljs-section, -.hljs-selector-id { - color: #900; - font-weight: bold; -} - -.hljs-subst { - font-weight: normal; -} - -.hljs-type, -.hljs-class .hljs-title { - color: #458; - font-weight: bold; -} - -.hljs-tag, -.hljs-name, -.hljs-attribute { - color: #000080; - font-weight: normal; -} - -.hljs-regexp, -.hljs-link { - color: #009926; -} - -.hljs-symbol, -.hljs-bullet { - color: #990073; -} - -.hljs-built_in, -.hljs-builtin-name { - color: #0086b3; -} - -.hljs-meta { - color: #999; - font-weight: bold; -} - -.hljs-deletion { - background: #fdd; -} - -.hljs-addition { - background: #dfd; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/auth0_flutter/doc/api/static-assets/highlight.pack.js b/auth0_flutter/doc/api/static-assets/highlight.pack.js deleted file mode 100644 index dabdd3c0..00000000 --- a/auth0_flutter/doc/api/static-assets/highlight.pack.js +++ /dev/null @@ -1,775 +0,0 @@ -/*! - Highlight.js v11.0.1 (git: 1cf31f015d) - (c) 2006-2021 Ivan Sagalaev and other contributors - License: BSD-3-Clause - */ -var hljs=function(){"use strict";var e={exports:{}};function t(e){ -return e instanceof Map?e.clear=e.delete=e.set=()=>{ -throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{ -throw Error("set is read-only") -}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((n=>{var i=e[n] -;"object"!=typeof i||Object.isFrozen(i)||t(i)})),e} -e.exports=t,e.exports.default=t;var n=e.exports;class i{constructor(e){ -void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} -ignoreMatch(){this.isMatchIgnored=!0}}function r(e){ -return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") -}function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t] -;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const o=e=>!!e.kind -;class a{constructor(e,t){ -this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){ -this.buffer+=r(e)}openNode(e){if(!o(e))return;let t=e.kind -;t=e.sublanguage?"language-"+t:((e,{prefix:t})=>{if(e.includes(".")){ -const n=e.split(".") -;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ") -}return`${t}${e}`})(t,{prefix:this.classPrefix}),this.span(t)}closeNode(e){ -o(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ -this.buffer+=``}}class l{constructor(){this.rootNode={ -children:[]},this.stack=[this.rootNode]}get top(){ -return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ -this.top.children.push(e)}openNode(e){const t={kind:e,children:[]} -;this.add(t),this.stack.push(t)}closeNode(){ -if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ -for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} -walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){ -return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t), -t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){ -"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ -l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e} -addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())} -addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root -;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){ -return new a(this,this.options).value()}finalize(){return!0}}function g(e){ -return e?"string"==typeof e?e:e.source:null}function d(...e){ -return e.map((e=>g(e))).join("")}function u(...e){return"("+((e=>{ -const t=e[e.length-1] -;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{} -})(e).capture?"":"?:")+e.map((e=>g(e))).join("|")+")"}function h(e){ -return RegExp(e.toString()+"|").exec("").length-1} -const f=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ -;function p(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n -;let i=g(e),r="";for(;i.length>0;){const e=f.exec(i);if(!e){r+=i;break} -r+=i.substring(0,e.index), -i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0], -"("===e[0]&&n++)}return r})).map((e=>`(${e})`)).join(t)} -const b="[a-zA-Z]\\w*",m="[a-zA-Z_]\\w*",E="\\b\\d+(\\.\\d+)?",x="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",y="\\b(0b[01]+)",w={ -begin:"\\\\[\\s\\S]",relevance:0},_={scope:"string",begin:"'",end:"'", -illegal:"\\n",contains:[w]},v={scope:"string",begin:'"',end:'"',illegal:"\\n", -contains:[w]},O=(e,t,n={})=>{const i=s({scope:"comment",begin:e,end:t, -contains:[]},n);i.contains.push({scope:"doctag", -begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", -end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) -;const r=u("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) -;return i.contains.push({begin:d(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i -},k=O("//","$"),N=O("/\\*","\\*/"),S=O("#","$");var M=Object.freeze({ -__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:b,UNDERSCORE_IDENT_RE:m, -NUMBER_RE:E,C_NUMBER_RE:x,BINARY_NUMBER_RE:y, -RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", -SHEBANG:(e={})=>{const t=/^#![ ]*\// -;return e.binary&&(e.begin=d(t,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:t, -end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)}, -BACKSLASH_ESCAPE:w,APOS_STRING_MODE:_,QUOTE_STRING_MODE:v,PHRASAL_WORDS_MODE:{ -begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ -},COMMENT:O,C_LINE_COMMENT_MODE:k,C_BLOCK_COMMENT_MODE:N,HASH_COMMENT_MODE:S, -NUMBER_MODE:{scope:"number",begin:E,relevance:0},C_NUMBER_MODE:{scope:"number", -begin:x,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:y,relevance:0}, -REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//, -end:/\/[gimuy]*/,illegal:/\n/,contains:[w,{begin:/\[/,end:/\]/,relevance:0, -contains:[w]}]}]},TITLE_MODE:{scope:"title",begin:b,relevance:0}, -UNDERSCORE_TITLE_MODE:{scope:"title",begin:m,relevance:0},METHOD_GUARD:{ -begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{ -"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{ -t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function R(e,t){ -"."===e.input[e.index-1]&&t.ignoreMatch()}function j(e,t){ -void 0!==e.className&&(e.scope=e.className,delete e.className)}function A(e,t){ -t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", -e.__beforeBegin=R,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, -void 0===e.relevance&&(e.relevance=0))}function I(e,t){ -Array.isArray(e.illegal)&&(e.illegal=u(...e.illegal))}function B(e,t){ -if(e.match){ -if(e.begin||e.end)throw Error("begin & end are not supported with match") -;e.begin=e.match,delete e.match}}function T(e,t){ -void 0===e.relevance&&(e.relevance=1)}const L=(e,t)=>{if(!e.beforeMatch)return -;if(e.starts)throw Error("beforeMatch cannot be used with starts") -;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t] -})),e.keywords=n.keywords, -e.begin=d(n.beforeMatch,d("(?=",n.begin,")")),e.starts={relevance:0, -contains:[Object.assign(n,{endsParent:!0})]},e.relevance=0,delete n.beforeMatch -},D=["of","and","for","in","not","or","if","then","parent","list","value"] -;function P(e,t,n="keyword"){const i=Object.create(null) -;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{ -Object.assign(i,P(e[n],t,n))})),i;function r(e,n){ -t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|") -;i[n[0]]=[e,C(n[0],n[1])]}))}}function C(e,t){ -return t?Number(t):(e=>D.includes(e.toLowerCase()))(e)?0:1}const H={},$=e=>{ -console.error(e)},U=(e,...t)=>{console.log("WARN: "+e,...t)},z=(e,t)=>{ -H[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),H[`${e}/${t}`]=!0) -},K=Error();function W(e,t,{key:n}){let i=0;const r=e[n],s={},o={} -;for(let e=1;e<=t.length;e++)o[e+i]=r[e],s[e+i]=!0,i+=h(t[e-1]) -;e[n]=o,e[n]._emit=s,e[n]._multi=!0}function X(e){(e=>{ -e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, -delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ -_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope -}),(e=>{if(Array.isArray(e.begin)){ -if(e.skip||e.excludeBegin||e.returnBegin)throw $("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), -K -;if("object"!=typeof e.beginScope||null===e.beginScope)throw $("beginScope must be object"), -K;W(e,e.begin,{key:"beginScope"}),e.begin=p(e.begin,{joinWith:""})}})(e),(e=>{ -if(Array.isArray(e.end)){ -if(e.skip||e.excludeEnd||e.returnEnd)throw $("skip, excludeEnd, returnEnd not compatible with endScope: {}"), -K -;if("object"!=typeof e.endScope||null===e.endScope)throw $("endScope must be object"), -K;W(e,e.end,{key:"endScope"}),e.end=p(e.end,{joinWith:""})}})(e)}function G(e){ -function t(t,n){return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(n?"g":""))} -class n{constructor(){ -this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} -addRule(e,t){ -t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]), -this.matchAt+=h(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) -;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(p(e,{joinWith:"|" -}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex -;const t=this.matcherRe.exec(e);if(!t)return null -;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n] -;return t.splice(0,n),Object.assign(t,i)}}class i{constructor(){ -this.rules=[],this.multiRegexes=[], -this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ -if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n -;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))), -t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){ -return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){ -this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){ -const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex -;let n=t.exec(e) -;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{ -const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)} -return n&&(this.regexIndex+=n.position+1, -this.regexIndex===this.count&&this.considerAll()),n}} -if(e.compilerExtensions||(e.compilerExtensions=[]), -e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") -;return e.classNameAliases=s(e.classNameAliases||{}),function n(r,o){const a=r -;if(r.isCompiled)return a -;[j,B,X,L].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))), -r.__beforeBegin=null,[A,I,T].forEach((e=>e(r,o))),r.isCompiled=!0;let l=null -;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), -l=r.keywords.$pattern, -delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=P(r.keywords,e.case_insensitive)), -a.keywordPatternRe=t(l,!0), -o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(r.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), -r.end&&(a.endRe=t(r.end)), -a.terminatorEnd=g(r.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)), -r.illegal&&(a.illegalRe=t(r.illegal)), -r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{ -variants:null},t)))),e.cachedVariants?e.cachedVariants:Z(e)?s(e,{ -starts:e.starts?s(e.starts):null -}):Object.isFrozen(e)?s(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a) -})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new i -;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin" -}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end" -}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function Z(e){ -return!!e&&(e.endsWithParent||Z(e.starts))}const F=r,V=s,q=Symbol("nomatch") -;var J=(e=>{const t=Object.create(null),r=Object.create(null),s=[];let o=!0 -;const a="Could not find the language '{}', did you forget to load/include a language module?",l={ -disableAutodetect:!0,name:"Plain text",contains:[]};let g={ -ignoreUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, -languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", -cssSelector:"pre code",languages:null,__emitter:c};function d(e){ -return g.noHighlightRe.test(e)}function u(e,t,n,i){let r="",s="" -;"object"==typeof t?(r=e, -n=t.ignoreIllegals,s=t.language,i=void 0):(z("10.7.0","highlight(lang, code, ...args) has been deprecated."), -z("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), -s=e,r=t),void 0===n&&(n=!0);const o={code:r,language:s};w("before:highlight",o) -;const a=o.result?o.result:h(o.language,o.code,n,i) -;return a.code=o.code,w("after:highlight",a),a}function h(e,n,r,s){ -const l=Object.create(null);function c(){if(!k.keywords)return void S.addText(M) -;let e=0;k.keywordPatternRe.lastIndex=0;let t=k.keywordPatternRe.exec(M),n="" -;for(;t;){n+=M.substring(e,t.index) -;const r=_.case_insensitive?t[0].toLowerCase():t[0],s=(i=r,k.keywords[i]);if(s){ -const[e,i]=s -;if(S.addText(n),n="",l[r]=(l[r]||0)+1,l[r]<=7&&(R+=i),e.startsWith("_"))n+=t[0];else{ -const n=_.classNameAliases[e]||e;S.addKeyword(t[0],n)}}else n+=t[0] -;e=k.keywordPatternRe.lastIndex,t=k.keywordPatternRe.exec(M)}var i -;n+=M.substr(e),S.addText(n)}function d(){null!=k.subLanguage?(()=>{ -if(""===M)return;let e=null;if("string"==typeof k.subLanguage){ -if(!t[k.subLanguage])return void S.addText(M) -;e=h(k.subLanguage,M,!0,N[k.subLanguage]),N[k.subLanguage]=e._top -}else e=f(M,k.subLanguage.length?k.subLanguage:null) -;k.relevance>0&&(R+=e.relevance),S.addSublanguage(e._emitter,e.language) -})():c(),M=""}function u(e,t){let n=1;for(;void 0!==t[n];){if(!e._emit[n]){n++ -;continue}const i=_.classNameAliases[e[n]]||e[n],r=t[n] -;i?S.addKeyword(r,i):(M=r,c(),M=""),n++}}function p(e,t){ -return e.scope&&"string"==typeof e.scope&&S.openNode(_.classNameAliases[e.scope]||e.scope), -e.beginScope&&(e.beginScope._wrap?(S.addKeyword(M,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), -M=""):e.beginScope._multi&&(u(e.beginScope,t),M="")),k=Object.create(e,{parent:{ -value:k}}),k}function b(e,t,n){let r=((e,t)=>{const n=e&&e.exec(t) -;return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){const n=new i(e) -;e["on:end"](t,n),n.isMatchIgnored&&(r=!1)}if(r){ -for(;e.endsParent&&e.parent;)e=e.parent;return e}} -if(e.endsWithParent)return b(e.parent,t,n)}function m(e){ -return 0===k.matcher.regexIndex?(M+=e[0],1):(I=!0,0)}function x(e){ -const t=e[0],i=n.substr(e.index),r=b(k,e,i);if(!r)return q;const s=k -;k.endScope&&k.endScope._wrap?(d(), -S.addKeyword(t,k.endScope._wrap)):k.endScope&&k.endScope._multi?(d(), -u(k.endScope,e)):s.skip?M+=t:(s.returnEnd||s.excludeEnd||(M+=t), -d(),s.excludeEnd&&(M=t));do{ -k.scope&&!k.isMultiClass&&S.closeNode(),k.skip||k.subLanguage||(R+=k.relevance), -k=k.parent}while(k!==r.parent) -;return r.starts&&p(r.starts,e),s.returnEnd?0:t.length}let y={};function w(t,s){ -const a=s&&s[0];if(M+=t,null==a)return d(),0 -;if("begin"===y.type&&"end"===s.type&&y.index===s.index&&""===a){ -if(M+=n.slice(s.index,s.index+1),!o){const t=Error(`0 width match regex (${e})`) -;throw t.languageName=e,t.badRule=y.rule,t}return 1} -if(y=s,"begin"===s.type)return(e=>{ -const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]] -;for(const n of s)if(n&&(n(e,r),r.isMatchIgnored))return m(t) -;return n.skip?M+=t:(n.excludeBegin&&(M+=t), -d(),n.returnBegin||n.excludeBegin||(M=t)),p(n,e),n.returnBegin?0:t.length})(s) -;if("illegal"===s.type&&!r){ -const e=Error('Illegal lexeme "'+a+'" for mode "'+(k.scope||"")+'"') -;throw e.mode=k,e}if("end"===s.type){const e=x(s);if(e!==q)return e} -if("illegal"===s.type&&""===a)return 1 -;if(A>1e5&&A>3*s.index)throw Error("potential infinite loop, way more iterations than matches") -;return M+=a,a.length}const _=E(e) -;if(!_)throw $(a.replace("{}",e)),Error('Unknown language: "'+e+'"') -;const v=G(_);let O="",k=s||v;const N={},S=new g.__emitter(g);(()=>{const e=[] -;for(let t=k;t!==_;t=t.parent)t.scope&&e.unshift(t.scope) -;e.forEach((e=>S.openNode(e)))})();let M="",R=0,j=0,A=0,I=!1;try{ -for(k.matcher.considerAll();;){ -A++,I?I=!1:k.matcher.considerAll(),k.matcher.lastIndex=j -;const e=k.matcher.exec(n);if(!e)break;const t=w(n.substring(j,e.index),e) -;j=e.index+t}return w(n.substr(j)),S.closeAllNodes(),S.finalize(),O=S.toHTML(),{ -language:e,value:O,relevance:R,illegal:!1,_emitter:S,_top:k}}catch(t){ -if(t.message&&t.message.includes("Illegal"))return{language:e,value:F(n), -illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j, -context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:O},_emitter:S};if(o)return{ -language:e,value:F(n),illegal:!1,relevance:0,errorRaised:t,_emitter:S,_top:k} -;throw t}}function f(e,n){n=n||g.languages||Object.keys(t);const i=(e=>{ -const t={value:F(e),illegal:!1,relevance:0,_top:l,_emitter:new g.__emitter(g)} -;return t._emitter.addText(e),t})(e),r=n.filter(E).filter(y).map((t=>h(t,e,!1))) -;r.unshift(i);const s=r.sort(((e,t)=>{ -if(e.relevance!==t.relevance)return t.relevance-e.relevance -;if(e.language&&t.language){if(E(e.language).supersetOf===t.language)return 1 -;if(E(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=s,c=o -;return c.secondBest=a,c}function p(e){let t=null;const n=(e=>{ -let t=e.className+" ";t+=e.parentNode?e.parentNode.className:"" -;const n=g.languageDetectRe.exec(t);if(n){const t=E(n[1]) -;return t||(U(a.replace("{}",n[1])), -U("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"} -return t.split(/\s+/).find((e=>d(e)||E(e)))})(e);if(d(n))return -;w("before:highlightElement",{el:e,language:n -}),!g.ignoreUnescapedHTML&&e.children.length>0&&(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), -console.warn("https://github.com/highlightjs/highlight.js/issues/2886"), -console.warn(e)),t=e;const i=t.textContent,s=n?u(i,{language:n,ignoreIllegals:!0 -}):f(i);e.innerHTML=s.value,((e,t,n)=>{const i=t&&r[t]||n -;e.classList.add("hljs"),e.classList.add("language-"+i) -})(e,n,s.language),e.result={language:s.language,re:s.relevance, -relevance:s.relevance},s.secondBest&&(e.secondBest={ -language:s.secondBest.language,relevance:s.secondBest.relevance -}),w("after:highlightElement",{el:e,result:s,text:i})}let b=!1;function m(){ -"loading"!==document.readyState?document.querySelectorAll(g.cssSelector).forEach(p):b=!0 -}function E(e){return e=(e||"").toLowerCase(),t[e]||t[r[e]]} -function x(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ -r[e.toLowerCase()]=t}))}function y(e){const t=E(e) -;return t&&!t.disableAutodetect}function w(e,t){const n=e;s.forEach((e=>{ -e[n]&&e[n](t)}))} -"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ -b&&m()}),!1),Object.assign(e,{highlight:u,highlightAuto:f,highlightAll:m, -highlightElement:p, -highlightBlock:e=>(z("10.7.0","highlightBlock will be removed entirely in v12.0"), -z("10.7.0","Please use highlightElement now."),p(e)),configure:e=>{g=V(g,e)}, -initHighlighting:()=>{ -m(),z("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, -initHighlightingOnLoad:()=>{ -m(),z("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") -},registerLanguage:(n,i)=>{let r=null;try{r=i(e)}catch(e){ -if($("Language definition for '{}' could not be registered.".replace("{}",n)), -!o)throw e;$(e),r=l} -r.name||(r.name=n),t[n]=r,r.rawDefinition=i.bind(null,e),r.aliases&&x(r.aliases,{ -languageName:n})},unregisterLanguage:e=>{delete t[e] -;for(const t of Object.keys(r))r[t]===e&&delete r[t]}, -listLanguages:()=>Object.keys(t),getLanguage:E,registerAliases:x, -autoDetection:y,inherit:V,addPlugin:e=>{(e=>{ -e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{ -e["before:highlightBlock"](Object.assign({block:t.el},t)) -}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{ -e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)} -}),e.debugMode=()=>{o=!1},e.safeMode=()=>{o=!0},e.versionString="11.0.1" -;for(const e in M)"object"==typeof M[e]&&n(M[e]);return Object.assign(e,M),e -})({}),Y=Object.freeze({__proto__:null});const Q=J -;for(const e of Object.keys(Y)){const t=e.replace("grmr_","") -;Q.registerLanguage(t,Y[e])}return Q}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("xml",(()=>{"use strict";function e(e){ -return e?"string"==typeof e?e:e.source:null}function n(e){return a("(?=",e,")")} -function a(...n){return n.map((n=>e(n))).join("")}function s(...n){ -return"("+((e=>{const n=e[e.length-1] -;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} -})(n).capture?"":"?:")+n.map((n=>e(n))).join("|")+")"}return e=>{ -const t=a(/[A-Z_]/,a("(?:",/[A-Z0-9_.-]*:/,")?"),/[A-Z0-9_.-]*/),i={ -className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},c={begin:/\s/, -contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] -},r=e.inherit(c,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{ -className:"string"}),g=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),m={ -endsWithParent:!0,illegal:/`]+/}]}]}]};return{ -name:"HTML, XML", -aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], -case_insensitive:!0,contains:[{className:"meta",begin://, -relevance:10,contains:[c,g,l,r,{begin:/\[/,end:/\]/,contains:[{className:"meta", -begin://,contains:[c,r,g,l]}]}]},e.COMMENT(//,{ -relevance:10}),{begin://,relevance:10},i,{ -className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"style"},contains:[m],starts:{ -end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"script"},contains:[m],starts:{ -end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ -className:"tag",begin:/<>|<\/>/},{className:"tag", -begin:a(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name", -begin:t,relevance:0,starts:m}]},{className:"tag",begin:a(/<\//,n(a(t,/>/))), -contains:[{className:"name",begin:t,relevance:0},{begin:/>/,relevance:0, -endsParent:!0}]}]}}})());hljs.registerLanguage("markdown",(()=>{"use strict";function n(...n){ -return n.map((n=>{return(e=n)?"string"==typeof e?e:e.source:null;var e -})).join("")}return e=>{const a={begin:/<\/?[A-Za-z_]/,end:">", -subLanguage:"xml",relevance:0},i={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0 -},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, -relevance:2},{begin:n(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), -relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ -begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{ -className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, -returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", -excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", -end:"\\]",excludeBegin:!0,excludeEnd:!0}]},s={className:"strong",contains:[], -variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},c={ -className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{ -begin:/_(?!_)/,end:/_/,relevance:0}]};s.contains.push(c),c.contains.push(s) -;let t=[a,i] -;return s.contains=s.contains.concat(t),c.contains=c.contains.concat(t), -t=t.concat(s,c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ -className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:t},{ -begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", -contains:t}]}]},a,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", -end:"\\s+",excludeEnd:!0},s,c,{className:"quote",begin:"^>\\s+",contains:t, -end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ -begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ -begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", -contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ -begin:"^[-\\*]{3,}",end:"$"},i,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ -className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ -className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}})());hljs.registerLanguage("css",(()=>{"use strict" -;const e=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],t=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],i=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],o=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],r=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse() -;return n=>{const a=(e=>({IMPORTANT:{scope:"meta",begin:"!important"},HEXCOLOR:{ -scope:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"}, -ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ -scope:"number", -begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", -relevance:0}}))(n),l=[n.APOS_STRING_MODE,n.QUOTE_STRING_MODE];return{name:"CSS", -case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"}, -classNameAliases:{keyframePosition:"selector-tag"}, -contains:[n.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ -},a.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 -},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 -},a.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ -begin:":("+i.join("|")+")"},{begin:"::("+o.join("|")+")"}]},{ -className:"attribute",begin:"\\b("+r.join("|")+")\\b"},{begin:":",end:"[;}]", -contains:[a.HEXCOLOR,a.IMPORTANT,a.CSS_NUMBER_MODE,...l,{ -begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" -},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}] -},{className:"built_in",begin:/[\w-]+(?=\()/}]},{ -begin:(s=/@/,((...e)=>e.map((e=>(e=>e?"string"==typeof e?e:e.source:null)(e))).join(""))("(?=",s,")")), -end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword", -begin:/@-?\w[\w]*(-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0, -relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:"and or not only", -attribute:t.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute" -},...l,a.CSS_NUMBER_MODE]}]},{className:"selector-tag", -begin:"\\b("+e.join("|")+")\\b"}]};var s}})());hljs.registerLanguage("plaintext",(()=>{"use strict";return t=>({ -name:"Plain text",aliases:["text","txt"],disableAutodetect:!0})})());hljs.registerLanguage("bash",(()=>{"use strict";function e(...e){ -return e.map((e=>{return(s=e)?"string"==typeof s?s:s.source:null;var s -})).join("")}return s=>{const n={},t={begin:/\$\{/,end:/\}/,contains:["self",{ -begin:/:-/,contains:[n]}]};Object.assign(n,{className:"variable",variants:[{ -begin:e(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={ -className:"subst",begin:/\$\(/,end:/\)/,contains:[s.BACKSLASH_ESCAPE]},i={ -begin:/<<-?\s*(?=\w+)/,starts:{contains:[s.END_SAME_AS_BEGIN({begin:/(\w+)/, -end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/, -contains:[s.BACKSLASH_ESCAPE,n,a]};a.contains.push(c);const o={begin:/\$\(\(/, -end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},s.NUMBER_MODE,n] -},r=s.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 -}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, -contains:[s.inherit(s.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ -name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/, -keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"], -literal:["true","false"], -built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp" -},contains:[r,s.SHEBANG(),l,o,s.HASH_COMMENT_MODE,i,c,{className:"",begin:/\\"/ -},{className:"string",begin:/'/,end:/'/},n]}}})());hljs.registerLanguage("kotlin",(()=>{"use strict" -;var e="\\.([0-9](_*[0-9])*)",n="[0-9a-fA-F](_*[0-9a-fA-F])*",a={ -className:"number",variants:[{ -begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` -},{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ -begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{ -begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` -},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};return e=>{const n={ -keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", -built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", -literal:"true false null"},i={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" -},s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={ -className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", -variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'", -illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, -contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={ -className:"meta", -begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" -},c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, -end:/\)/,contains:[e.inherit(r,{className:"string"})]}] -},o=a,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={ -variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, -contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d], -{name:"Kotlin",aliases:["kt","kts"],keywords:n, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", -begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword", -begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", -begin:/@\w+/}]}},i,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$", -returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, -keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, -endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, -endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0 -},e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{className:"class", -beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, -illegal:"extends implements",contains:[{ -beginKeywords:"public protected internal private constructor" -},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, -excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/, -excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env", -end:"$",illegal:"\n"},o]}}})());hljs.registerLanguage("diff",(()=>{"use strict";function e(...e){ -return"("+((e=>{const n=e[e.length-1] -;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} -})(e).capture?"":"?:")+e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null -;var n})).join("|")+")"}return n=>({name:"Diff",aliases:["patch"],contains:[{ -className:"meta",relevance:10, -match:e(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) -},{className:"comment",variants:[{ -begin:e(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), -end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ -className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, -end:/$/}]})})());hljs.registerLanguage("shell",(()=>{"use strict";return s=>({ -name:"Shell Session",aliases:["console","shellsession"],contains:[{ -className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{ -end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]})})());hljs.registerLanguage("json",(()=>{"use strict";return e=>({name:"JSON", -contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01 -},{match:/[{}[\],:]/,className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{ -beginKeywords:"true false null" -},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}) -})());hljs.registerLanguage("java",(()=>{"use strict" -;var e="\\.([0-9](_*[0-9])*)",a="[0-9a-fA-F](_*[0-9a-fA-F])*",n={ -className:"number",variants:[{ -begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` -},{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ -begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{ -begin:`\\b0[xX]((${a})\\.?|(${a})?\\.(${a}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` -},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${a})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};function s(e,a,n){return-1===n?"":e.replace(a,(t=>s(e,a,n-1)))} -return e=>{ -const a="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",t=a+s("(?:<"+a+"~~~(?:\\s*,\\s*"+a+"~~~)*>)?",/~~~/g,2),i={ -keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"], -literal:["false","true","null"], -type:["char","boolean","long","float","int","byte","short","double"], -built_in:["super","this"]},r={className:"meta",begin:"@"+a,contains:[{ -begin:/\(/,end:/\)/,contains:["self"]}]},l={className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} -;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, -relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ -begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ -match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,a],className:{ -1:"keyword",3:"title.class"}},{begin:[a,/\s+/,a,/\s+/,/=/],className:{1:"type", -3:"variable",5:"operator"}},{begin:[/record/,/\s+/,a],className:{1:"keyword", -3:"title.class"},contains:[l,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"new throw return else",relevance:0},{ -begin:["(?:"+t+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ -2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0, -contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,n,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},n,r]}}})());hljs.registerLanguage("objectivec",(()=>{"use strict";return e=>{ -const n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n, -keyword:["@interface","@class","@protocol","@implementation"]};return{ -name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], -keywords:{$pattern:n, -keyword:["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], -literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], -built_in:["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"] -},illegal:"/,end:/$/,illegal:"\\n" -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", -begin:"("+_.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:_, -contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, -relevance:0}]}}})());hljs.registerLanguage("dart",(()=>{"use strict";return e=>{const n={ -className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"}]},a={className:"subst", -variants:[{begin:/\$\{/,end:/\}/}],keywords:"true false null this is new super" -},t={className:"string",variants:[{begin:"r'''",end:"'''"},{begin:'r"""', -end:'"""'},{begin:"r'",end:"'",illegal:"\\n"},{begin:'r"',end:'"',illegal:"\\n" -},{begin:"'''",end:"'''",contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"""', -end:'"""',contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:"'",end:"'",illegal:"\\n", -contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"',end:'"',illegal:"\\n", -contains:[e.BACKSLASH_ESCAPE,n,a]}]};a.contains=[e.C_NUMBER_MODE,t] -;const i=["Comparable","DateTime","Duration","Function","Iterable","Iterator","List","Map","Match","Object","Pattern","RegExp","Set","Stopwatch","String","StringBuffer","StringSink","Symbol","Type","Uri","bool","double","int","num","Element","ElementList"],r=i.map((e=>e+"?")) -;return{name:"Dart",keywords:{ -keyword:["abstract","as","assert","async","await","break","case","catch","class","const","continue","covariant","default","deferred","do","dynamic","else","enum","export","extends","extension","external","factory","false","final","finally","for","Function","get","hide","if","implements","import","in","inferface","is","late","library","mixin","new","null","on","operator","part","required","rethrow","return","set","show","static","super","switch","sync","this","throw","true","try","typedef","var","void","while","with","yield"], -built_in:i.concat(r).concat(["Never","Null","dynamic","print","document","querySelector","querySelectorAll","window"]), -$pattern:/[A-Za-z][A-Za-z0-9_]*\??/}, -contains:[t,e.COMMENT(/\/\*\*(?!\/)/,/\*\//,{subLanguage:"markdown",relevance:0 -}),e.COMMENT(/\/{3,} ?/,/$/,{contains:[{subLanguage:"markdown",begin:".", -end:"$",relevance:0}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{ -className:"class",beginKeywords:"class interface",end:/\{/,excludeEnd:!0, -contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE] -},e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"},{begin:"=>"}]}}})());hljs.registerLanguage("ruby",(()=>{"use strict";function e(e){ -return n("(?=",e,")")}function n(...e){return e.map((e=>{ -return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return a=>{ -const i="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",s={ -keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__", -built_in:"proc lambda",literal:"true false nil"},r={className:"doctag", -begin:"@[A-Za-z]+"},b={begin:"#<",end:">"},c=[a.COMMENT("#","$",{contains:[r] -}),a.COMMENT("^=begin","^=end",{contains:[r],relevance:10 -}),a.COMMENT("^__END__","\\n$")],t={className:"subst",begin:/#\{/,end:/\}/, -keywords:s},g={className:"string",contains:[a.BACKSLASH_ESCAPE,t],variants:[{ -begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/, -end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{ -begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/, -end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{ -begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{ -begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ -begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ -begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ -begin:n(/<<[-~]?'?/,e(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), -contains:[a.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, -contains:[a.BACKSLASH_ESCAPE,t]})]}]},d="[0-9](_?[0-9])*",l={className:"number", -relevance:0,variants:[{ -begin:`\\b([1-9](_?[0-9])*|0)(\\.(${d}))?([eE][+-]?(${d})|r)?i?\\b`},{ -begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" -},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ -begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ -begin:"\\b0(_?[0-7])+r?i?\\b"}]},o={className:"params",begin:"\\(",end:"\\)", -endsParent:!0,keywords:s},_=[g,{className:"class",beginKeywords:"class module", -end:"$|;",illegal:/=/,contains:[a.inherit(a.TITLE_MODE,{ -begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{ -begin:"("+a.IDENT_RE+"::)?"+a.IDENT_RE,relevance:0}]}].concat(c)},{ -className:"function",begin:n(/def\s+/,e(i+"\\s*(\\(|;|$)")),relevance:0, -keywords:"def",end:"$|;",contains:[a.inherit(a.TITLE_MODE,{begin:i -}),o].concat(c)},{begin:a.IDENT_RE+"::"},{className:"symbol", -begin:a.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", -begin:":(?!\\s)",contains:[g,{begin:i}],relevance:0},l,{className:"variable", -begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ -className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:s},{ -begin:"("+a.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{ -className:"regexp",contains:[a.BACKSLASH_ESCAPE,t],illegal:/\n/,variants:[{ -begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(", -end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}] -}].concat(b,c),relevance:0}].concat(b,c);t.contains=_,o.contains=_;const E=[{ -begin:/^\s*=>/,starts:{end:"$",contains:_}},{className:"meta", -begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", -starts:{end:"$",contains:_}}];return c.unshift(b),{name:"Ruby", -aliases:["rb","gemspec","podspec","thor","irb"],keywords:s,illegal:/\/\*/, -contains:[a.SHEBANG({binary:"ruby"})].concat(E).concat(c).concat(_)}}})());hljs.registerLanguage("yaml",(()=>{"use strict";return e=>{ -const n="true false yes no null",a="[\\w#;/?:@&=+$,.~*'()[\\]]+",s={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(s,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={ -end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},t={begin:/\{/, -end:/\}/,contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]", -contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{ -begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ -begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", -relevance:10},{className:"string", -begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type", -begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},t,g,s],c=[...b] -;return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0, -aliases:["yml"],contains:b}}})());hljs.registerLanguage("javascript",(()=>{"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],s=["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],i=["arguments","this","super","console","window","document","localStorage","module","global"],c=[].concat(r,t,s) -;function o(e){return l("(?=",e,")")}function l(...e){return e.map((e=>{ -return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return b=>{ -const g=e,d={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/, -isTrulyOpeningTag:(e,n)=>{const a=e[0].length+e.index,t=e.input[a] -;"<"!==t?">"===t&&(((e,{after:n})=>{const a="",B={ -match:[/const|var|let/,/\s+/,g,/\s*/,/=\s*/,o(C)],className:{1:"keyword", -3:"title.function"},contains:[w]};return{name:"Javascript", -aliases:["js","jsx","mjs","cjs"],keywords:u,exports:{PARAMS_CONTAINS:S}, -illegal:/#(?![$_A-z])/,contains:[b.SHEBANG({label:"shebang",binary:"node", -relevance:5}),{label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},b.APOS_STRING_MODE,b.QUOTE_STRING_MODE,N,f,A,v,y,O,{className:"attr", -begin:g+o(":"),relevance:0},B,{ -begin:"("+b.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",relevance:0,contains:[v,b.REGEXP_MODE,{ -className:"function",begin:C,returnBegin:!0,end:"\\s*=>",contains:[{ -className:"params",variants:[{begin:b.UNDERSCORE_IDENT_RE,relevance:0},{ -className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, -excludeEnd:!0,keywords:u,contains:S}]}]},{begin:/,/,relevance:0},{match:/\s+/, -relevance:0},{variants:[{begin:"<>",end:""},{begin:d.begin, -"on:begin":d.isTrulyOpeningTag,end:d.end}],subLanguage:"xml",contains:[{ -begin:d.begin,end:d.end,skip:!0,contains:["self"]}]}]},I,{ -beginKeywords:"while if switch catch for"},{ -begin:"\\b(?!function)"+b.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", -returnBegin:!0,label:"func.def",contains:[w,b.inherit(b.TITLE_MODE,{begin:g, -className:"title.function"})]},{match:/\.\.\./,relevance:0},M,{match:"\\$"+g, -relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, -contains:[w]},T,{relevance:0,match:/\b[A-Z][A-Z_]+\b/, -className:"variable.constant"},R,k,{match:/\$[(.]/}]}}})());hljs.registerLanguage("c",(()=>{"use strict";function e(e){ -return((...e)=>e.map((e=>(e=>e?"string"==typeof e?e:e.source:null)(e))).join(""))("(?:",e,")?") -}return n=>{const t=n.COMMENT("//","$",{contains:[{begin:/\\\n/}] -}),s="[a-zA-Z_]\\w*::",r="(decltype\\(auto\\)|"+e(s)+"[a-zA-Z_]\\w*"+e("<[^<>]+>")+")",a={ -className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ -match:/\batomic_[a-z]{3,6}\b/}]},i={className:"string",variants:[{ -begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[n.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},n.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" -},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},n.inherit(i,{className:"string"}),{ -className:"string",begin:/<.*?>/},t,n.C_BLOCK_COMMENT_MODE]},o={ -className:"title",begin:e(s)+n.IDENT_RE,relevance:0 -},d=e(s)+n.IDENT_RE+"\\s*\\(",u={ -keyword:["asm","auto","break","case","const","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","static","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], -type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","complex","bool","imaginary"], -literal:"true false NULL", -built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" -},g=[c,a,t,n.C_BLOCK_COMMENT_MODE,l,i],m={variants:[{begin:/=/,end:/;/},{ -begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], -keywords:u,contains:g.concat([{begin:/\(/,end:/\)/,keywords:u, -contains:g.concat(["self"]),relevance:0}]),relevance:0},_={ -begin:"("+r+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, -keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)", -keywords:u,relevance:0},{begin:d,returnBegin:!0,contains:[n.inherit(o,{ -className:"title.function"})],relevance:0},{relevance:0,match:/,/},{ -className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, -contains:[t,n.C_BLOCK_COMMENT_MODE,i,l,a,{begin:/\(/,end:/\)/,keywords:u, -relevance:0,contains:["self",t,n.C_BLOCK_COMMENT_MODE,i,l,a]}] -},a,t,n.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, -disableAutodetect:!0,illegal:"=]/,contains:[{ -beginKeywords:"final class struct"},n.TITLE_MODE]}]),exports:{preprocessor:c, -strings:i,keywords:u}}}})());hljs.registerLanguage("swift",(()=>{"use strict";function e(e){ -return e?"string"==typeof e?e:e.source:null}function a(e){return t("(?=",e,")")} -function t(...a){return a.map((a=>e(a))).join("")}function n(...a){ -return"("+((e=>{const a=e[e.length-1] -;return"object"==typeof a&&a.constructor===Object?(e.splice(e.length-1,1),a):{} -})(a).capture?"":"?:")+a.map((a=>e(a))).join("|")+")"} -const i=e=>t(/\b/,e,/\w$/.test(e)?/\b/:/\B/),s=["Protocol","Type"].map(i),u=["init","self"].map(i),c=["Any","Self"],r=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],o=["false","nil","true"],l=["assignment","associativity","higherThan","left","lowerThan","none","right"],m=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],p=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],F=n(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),d=n(F,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),b=t(F,d,"*"),h=n(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),f=n(h,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),w=t(h,f,"*"),y=t(/[A-Z]/,f,"*"),g=["autoclosure",t(/convention\(/,n("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",t(/objc\(/,w,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],E=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] -;return e=>{const F={match:/\s+/,relevance:0},h=e.COMMENT("/\\*","\\*/",{ -contains:["self"]}),v=[e.C_LINE_COMMENT_MODE,h],A={match:[/\./,n(...s,...u)], -className:{2:"keyword"}},N={match:t(/\./,n(...r)),relevance:0 -},C=r.filter((e=>"string"==typeof e)).concat(["_|0"]),D={variants:[{ -className:"keyword", -match:n(...r.filter((e=>"string"!=typeof e)).concat(c).map(i),...u)}]},k={ -$pattern:n(/\b\w+/,/#\w+/),keyword:C.concat(m),literal:o},B=[A,N,D],_=[{ -match:t(/\./,n(...p)),relevance:0},{className:"built_in", -match:t(/\b/,n(...p),/(?=\()/)}],S={match:/->/,relevance:0},M=[S,{ -className:"operator",relevance:0,variants:[{match:b},{match:`\\.(\\.|${d})+`}] -}],x="([0-9a-fA-F]_*)+",I={className:"number",relevance:0,variants:[{ -match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{ -match:`\\b0x(${x})(\\.(${x}))?([pP][+-]?(([0-9]_*)+))?\\b`},{ -match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},L=(e="")=>({ -className:"subst",variants:[{match:t(/\\/,e,/[0\\tnr"']/)},{ -match:t(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),O=(e="")=>({className:"subst", -match:t(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),T=(e="")=>({className:"subst", -label:"interpol",begin:t(/\\/,e,/\(/),end:/\)/}),$=(e="")=>({begin:t(e,/"""/), -end:t(/"""/,e),contains:[L(e),O(e),T(e)]}),j=(e="")=>({begin:t(e,/"/), -end:t(/"/,e),contains:[L(e),T(e)]}),P={className:"string", -variants:[$(),$("#"),$("##"),$("###"),j(),j("#"),j("##"),j("###")]},K={ -match:t(/`/,w,/`/)},z=[K,{className:"variable",match:/\$\d+/},{ -className:"variable",match:`\\$${f}+`}],q=[{match:/(@|#)available/, -className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:E, -contains:[...M,I,P]}]}},{className:"keyword",match:t(/@/,n(...g))},{ -className:"meta",match:t(/@/,w)}],U={match:a(/\b[A-Z]/),relevance:0,contains:[{ -className:"type", -match:t(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,f,"+") -},{className:"type",match:y,relevance:0},{match:/[?!]+/,relevance:0},{ -match:/\.\.\./,relevance:0},{match:t(/\s+&\s+/,a(y)),relevance:0}]},Z={ -begin://,keywords:k,contains:[...v,...B,...q,S,U]};U.contains.push(Z) -;const V={begin:/\(/,end:/\)/,relevance:0,keywords:k,contains:["self",{ -match:t(w,/\s*:/),keywords:"_|0",relevance:0 -},...v,...B,..._,...M,I,P,...z,...q,U]},W={begin://,contains:[...v,U] -},G={begin:/\(/,end:/\)/,keywords:k,contains:[{ -begin:n(a(t(w,/\s*:/)),a(t(w,/\s+/,w,/\s*:/))),end:/:/,relevance:0,contains:[{ -className:"keyword",match:/\b_\b/},{className:"params",match:w}] -},...v,...B,...M,I,P,...q,U,V],endsParent:!0,illegal:/["']/},R={ -match:[/func/,/\s+/,n(K.match,w,b)],className:{1:"keyword",3:"title.function"}, -contains:[W,G,F],illegal:[/\[/,/%/]},X={ -match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, -contains:[W,G,F],illegal:/\[|%/},H={match:[/operator/,/\s+/,b],className:{ -1:"keyword",3:"title"}},J={begin:[/precedencegroup/,/\s+/,y],className:{ -1:"keyword",3:"title"},contains:[U],keywords:[...l,...o],end:/}/} -;for(const e of P.variants){const a=e.contains.find((e=>"interpol"===e.label)) -;a.keywords=k;const t=[...B,..._,...M,I,P,...z];a.contains=[...t,{begin:/\(/, -end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:k, -contains:[...v,R,X,{beginKeywords:"struct protocol class extension enum actor", -end:"\\{",excludeEnd:!0,keywords:k,contains:[e.inherit(e.TITLE_MODE,{ -className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...B] -},H,J,{beginKeywords:"import",end:/$/,contains:[...v],relevance:0 -},...B,..._,...M,I,P,...z,...q,U,V]}}})()); \ No newline at end of file diff --git a/auth0_flutter/doc/api/static-assets/play_button.svg b/auth0_flutter/doc/api/static-assets/play_button.svg deleted file mode 100644 index c39a2f4a..00000000 --- a/auth0_flutter/doc/api/static-assets/play_button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/auth0_flutter/doc/api/static-assets/readme.md b/auth0_flutter/doc/api/static-assets/readme.md deleted file mode 100644 index 357c11ca..00000000 --- a/auth0_flutter/doc/api/static-assets/readme.md +++ /dev/null @@ -1,22 +0,0 @@ -# highlight.js - -Generated from https://highlightjs.org/download/ on 2021-07-13 - -**Included languages:** - -* bash -* c -* css -* dart -* diff -* html, xml -* java -* javascript -* json -* kotlin -* markdown -* objective-c -* plaintext -* shell -* swift -* yaml diff --git a/auth0_flutter/doc/api/static-assets/script.js b/auth0_flutter/doc/api/static-assets/script.js deleted file mode 100644 index e88f0306..00000000 --- a/auth0_flutter/doc/api/static-assets/script.js +++ /dev/null @@ -1,501 +0,0 @@ -/* - * - * Update script.js versions in all lib/templates when modifying this file! - * - */ -function initSideNav() { - const leftNavToggle = document.getElementById('sidenav-left-toggle'); - const leftDrawer = document.querySelector('.sidebar-offcanvas-left'); - const overlay = document.getElementById('overlay-under-drawer'); - - function toggleBoth() { - if (leftDrawer) { - leftDrawer.classList.toggle('active'); - } - - if (overlay) { - overlay.classList.toggle('active'); - } - } - - if (overlay) { - overlay.addEventListener('click', toggleBoth); - } - - if (leftNavToggle) { - leftNavToggle.addEventListener('click', toggleBoth); - } -} - -function saveLeftScroll() { - const leftSidebar = document.getElementById('dartdoc-sidebar-left'); - sessionStorage.setItem('dartdoc-sidebar-left-scrollt' + window.location.pathname, leftSidebar.scrollTop.toString()); - sessionStorage.setItem('dartdoc-sidebar-left-scrolll' + window.location.pathname, leftSidebar.scrollLeft.toString()); -} - -function saveMainContentScroll() { - const mainContent = document.getElementById('dartdoc-main-content'); - sessionStorage.setItem('dartdoc-main-content-scrollt' + window.location.pathname, mainContent.scrollTop.toString()); - sessionStorage.setItem('dartdoc-main-content-scrolll' + window.location.pathname, mainContent.scrollLeft.toString()); -} - -function saveRightScroll() { - const rightSidebar = document.getElementById('dartdoc-sidebar-right'); - sessionStorage.setItem('dartdoc-sidebar-right-scrollt' + window.location.pathname, rightSidebar.scrollTop.toString()); - sessionStorage.setItem('dartdoc-sidebar-right-scrolll' + window.location.pathname, rightSidebar.scrollLeft.toString()); -} - -function restoreScrolls() { - const leftSidebar = document.getElementById('dartdoc-sidebar-left'); - const mainContent = document.getElementById('dartdoc-main-content'); - const rightSidebar = document.getElementById('dartdoc-sidebar-right'); - - try { - const leftSidebarX = sessionStorage.getItem('dartdoc-sidebar-left-scrolll' + window.location.pathname); - const leftSidebarY = sessionStorage.getItem('dartdoc-sidebar-left-scrollt' + window.location.pathname); - - const mainContentX = sessionStorage.getItem('dartdoc-main-content-scrolll' + window.location.pathname); - const mainContentY = sessionStorage.getItem('dartdoc-main-content-scrollt' + window.location.pathname); - - const rightSidebarX = sessionStorage.getItem('dartdoc-sidebar-right-scrolll' + window.location.pathname); - const rightSidebarY = sessionStorage.getItem('dartdoc-sidebar-right-scrollt' + window.location.pathname); - - leftSidebar.scrollTo(parseFloat(leftSidebarX), parseFloat(leftSidebarY)); - mainContent.scrollTo(parseFloat(mainContentX), parseFloat(mainContentY)); - rightSidebar.scrollTo(parseFloat(rightSidebarX), parseFloat(rightSidebarY)); - } finally { - // Set visibility to visible after scroll to prevent the brief appearance of the - // panel in the wrong position. - leftSidebar.style.visibility = 'visible'; - mainContent.style.visibility = 'visible'; - rightSidebar.style.visibility = 'visible'; - } -} - -function initScrollSave() { - const leftSidebar = document.getElementById('dartdoc-sidebar-left'); - const mainContent = document.getElementById('dartdoc-main-content'); - const rightSidebar = document.getElementById('dartdoc-sidebar-right'); - - leftSidebar.addEventListener("scroll", saveLeftScroll, true); - mainContent.addEventListener("scroll", saveMainContentScroll, true); - rightSidebar.addEventListener("scroll", saveRightScroll, true); -} - -const weights = { - 'library' : 2, - 'class' : 2, - 'mixin' : 3, - 'extension' : 3, - 'typedef' : 3, - 'method' : 4, - 'accessor' : 4, - 'operator' : 4, - 'constant' : 4, - 'property' : 4, - 'constructor' : 4 -}; - -function findMatches(index, query) { - if (query === '') { - return []; - } - - const allMatches = []; - - index.forEach(element => { - function score(value) { - value -= element.overriddenDepth * 10; - const weightFactor = weights[element.type] || 4; - allMatches.push({element: element, score: (value / weightFactor) >> 0}); - } - - const name = element.name; - const qualifiedName = element.qualifiedName; - const lowerName = name.toLowerCase(); - const lowerQualifiedName = qualifiedName.toLowerCase(); - const lowerQuery = query.toLowerCase(); - - if (name === query || qualifiedName === query || name === `dart:${query}`) { - score(2000); - } else if (lowerName === `dart:${lowerQuery}`) { - score(1800); - } else if (lowerName === lowerQuery || lowerQualifiedName === lowerQuery) { - score(1700); - } else if (query.length > 1) { - if (name.startsWith(query) || qualifiedName.startsWith(query)) { - score(750); - } else if (lowerName.startsWith(lowerQuery) || lowerQualifiedName.startsWith(lowerQuery)) { - score(650); - } else if (name.includes(query) || qualifiedName.includes(query)) { - score(500); - } else if (lowerName.includes(lowerQuery) || lowerQualifiedName.includes(query)) { - score(400); - } - } - }); - - allMatches.sort((a, b) => { - const x = b.score - a.score; - if (x === 0) { - return a.element.name.length - b.element.name.length; - } - return x; - }); - - const justElements = []; - - for (let i = 0; i < allMatches.length; i++) { - justElements.push(allMatches[i].element); - } - - return justElements; -} - -let baseHref = ''; - -const minLength = 1; -const suggestionLimit = 10; - -function initializeSearch(input, index) { - input.disabled = false; - input.setAttribute('placeholder', 'Search API Docs'); - - // Handle grabbing focus when the users types / outside of the input - document.addEventListener('keypress', (event) => { - if (event.code === 'Slash' && !(document.activeElement instanceof HTMLInputElement)) { - event.preventDefault(); - input.focus(); - } - }); - - // Prepare elements - - const parentForm = input.parentNode; - const wrapper = document.createElement('div'); - wrapper.classList.add('tt-wrapper'); - - parentForm.replaceChild(wrapper, input); - - const inputHint = document.createElement('input'); - inputHint.setAttribute('type', 'text'); - inputHint.setAttribute('autocomplete', 'off'); - inputHint.setAttribute('readonly', 'true'); - inputHint.setAttribute('spellcheck', 'false'); - inputHint.setAttribute('tabindex', '-1'); - inputHint.classList.add('typeahead', 'tt-hint'); - - wrapper.appendChild(inputHint); - - input.setAttribute('autocomplete', 'off'); - input.setAttribute('spellcheck', 'false'); - input.classList.add('tt-input'); - - wrapper.appendChild(input); - - const listBox = document.createElement('div'); - listBox.setAttribute('role', 'listbox'); - listBox.setAttribute('aria-expanded', 'false'); - listBox.style.display = 'none'; - listBox.classList.add('tt-menu'); - - const presentation = document.createElement('div'); - presentation.classList.add('tt-elements'); - - listBox.appendChild(presentation); - - wrapper.appendChild(listBox); - - // Set up various search functionality - - function highlight(text, query) { - query = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - return text.replace(new RegExp(query, 'gi'), (matched) => { - return `${matched}`; - }); - } - - function createSuggestion(query, match) { - const suggestion = document.createElement('div'); - suggestion.setAttribute('data-href', match.href); - suggestion.classList.add('tt-suggestion'); - - const suggestionTitle = document.createElement('span'); - suggestionTitle.classList.add('tt-suggestion-title'); - suggestionTitle.innerHTML = highlight(`${match.name} ${match.type.toLowerCase()}`, query); - - suggestion.appendChild(suggestionTitle); - - if (match.enclosedBy) { - const fromLib = document.createElement('div'); - fromLib.classList.add('search-from-lib'); - fromLib.innerHTML = `from ${highlight(match.enclosedBy.name, query)}`; - - suggestion.appendChild(fromLib); - } - - suggestion.addEventListener('mousedown', event => { - event.preventDefault(); - }); - - suggestion.addEventListener('click', event => { - if (match.href) { - window.location = baseHref + match.href; - event.preventDefault(); - } - }); - - return suggestion; - } - - let storedValue = null; - let actualValue = ''; - let hint = null; - - let suggestionElements = []; - let suggestionsInfo = []; - let selectedElement = null; - - function setHint(value) { - hint = value; - inputHint.value = value || ''; - } - - function updateSuggestions(query, suggestions) { - suggestionsInfo = []; - suggestionElements = []; - presentation.textContent = ''; - - if (suggestions.length < minLength) { - setHint(null) - hideSuggestions(); - return; - } - - for (let i = 0; i < suggestions.length; i++) { - const element = createSuggestion(query, suggestions[i]); - suggestionElements.push(element); - presentation.appendChild(element); - } - - suggestionsInfo = suggestions; - - setHint(query + suggestions[0].name.slice(query.length)); - selectedElement = null; - - showSuggestions(); - } - - function handle(newValue, forceUpdate) { - if (actualValue === newValue && !forceUpdate) { - return; - } - - if (newValue === null || newValue.length === 0) { - updateSuggestions('', []); - return; - } - - const suggestions = findMatches(index, newValue).slice(0, suggestionLimit); - actualValue = newValue; - - updateSuggestions(newValue, suggestions); - } - - function showSuggestions() { - if (presentation.hasChildNodes()) { - listBox.style.display = 'block'; - listBox.setAttribute('aria-expanded', 'true'); - } - } - - function hideSuggestions() { - listBox.style.display = 'none'; - listBox.setAttribute('aria-expanded', 'false'); - } - - // Hook up events - - input.addEventListener('focus', () => { - handle(input.value, true); - }); - - input.addEventListener('blur', () => { - selectedElement = null; - if (storedValue !== null) { - input.value = storedValue; - storedValue = null; - } - hideSuggestions(); - setHint(null); - }); - - input.addEventListener('input', event => { - handle(event.target.value); - }); - - input.addEventListener('keydown', event => { - if (suggestionElements.length === 0) { - return; - } - - if (event.code === 'Enter') { - const selectingElement = selectedElement || 0; - const href = suggestionElements[selectingElement].dataset.href; - if (href) { - window.location = baseHref + href; - } - return; - } - - if (event.code === 'Tab') { - if (selectedElement === null) { - // The user wants to fill the field with the hint - if (hint !== null) { - input.value = hint; - handle(hint); - event.preventDefault(); - } - } else { - // The user wants to fill the input field with their currently selected suggestion - handle(suggestionsInfo[selectedElement].name); - storedValue = null; - selectedElement = null; - event.preventDefault(); - } - return; - } - - const lastIndex = suggestionElements.length - 1; - const previousSelectedElement = selectedElement; - - if (event.code === 'ArrowUp') { - if (selectedElement === null) { - selectedElement = lastIndex; - } else if (selectedElement === 0) { - selectedElement = null; - } else { - selectedElement--; - } - } else if (event.code === 'ArrowDown') { - if (selectedElement === null) { - selectedElement = 0; - } else if (selectedElement === lastIndex) { - selectedElement = null; - } else { - selectedElement++; - } - } else { - if (storedValue !== null) { - storedValue = null; - handle(input.value); - } - return; - } - - if (previousSelectedElement !== null) { - suggestionElements[previousSelectedElement].classList.remove('tt-cursor'); - } - - if (selectedElement !== null) { - const selected = suggestionElements[selectedElement]; - selected.classList.add('tt-cursor'); - - // Guarantee the selected element is visible - if (selectedElement === 0) { - listBox.scrollTop = 0; - } else if (selectedElement === lastIndex) { - listBox.scrollTop = listBox.scrollHeight; - } else { - const offsetTop = selected.offsetTop; - const parentOffsetHeight = listBox.offsetHeight; - if (offsetTop < parentOffsetHeight || parentOffsetHeight < (offsetTop + selected.offsetHeight)) { - selected.scrollIntoView({behavior: 'auto', block: 'nearest'}); - } - } - - if (storedValue === null) { - // Store the actual input value to display their currently selected item - storedValue = input.value; - } - input.value = suggestionsInfo[selectedElement].name; - setHint(''); - } else if (storedValue !== null && previousSelectedElement !== null) { - // They are moving back to the input field, so return the stored value - input.value = storedValue; - setHint(storedValue + suggestionsInfo[0].name.slice(storedValue.length)); - storedValue = null; - } - - event.preventDefault(); - }); -} - -document.addEventListener('DOMContentLoaded', () => { - // Place this first so that unexpected exceptions in other JavaScript do not block page visibility. - restoreScrolls(); - hljs.highlightAll(); - initSideNav(); - initScrollSave(); - - const searchBox = document.getElementById('search-box'); - const searchBody = document.getElementById('search-body'); - const searchSidebar = document.getElementById('search-sidebar'); - - if (document.body.getAttribute('data-using-base-href') === 'false') { - // If dartdoc did not add a base-href tag, we will need to add the relative - // path ourselves. - baseHref = document.body.getAttribute('data-base-href'); - } - - function disableSearch() { - console.log('Could not activate search functionality.'); - if (searchBox) { - searchBox.placeholder = 'Failed to initialize search'; - } - - if (searchBody) { - searchBody.placeholder = 'Failed to initialize search'; - } - - if (searchSidebar) { - searchSidebar.placeholder = 'Failed to initialize search'; - } - } - - if ('fetch' in window) { - fetch(baseHref + 'index.json', {method: 'GET'}) - .then(response => response.json()) - .then(index => { - // Handle if the user specified a `search` parameter in the URL - if ('URLSearchParams' in window) { - const search = new URLSearchParams(window.location.search).get('search'); - if (search) { - const matches = findMatches(search); - if (matches.length !== 0) { - window.location = baseHref + matches[0].href; - return; - } - } - } - - // Initialize all three search fields - if (searchBox) { - initializeSearch(searchBox, index); - } - - if (searchBody) { - initializeSearch(searchBody, index); - } - - if (searchSidebar) { - initializeSearch(searchSidebar, index); - } - }) - .catch(() => { - disableSearch(); - }); - } else { - disableSearch(); - } -}); diff --git a/auth0_flutter/doc/api/static-assets/styles.css b/auth0_flutter/doc/api/static-assets/styles.css deleted file mode 100644 index 7ea04df3..00000000 --- a/auth0_flutter/doc/api/static-assets/styles.css +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * - * Update styles.css versions in all lib/templates when modifying this file! - * - */ - -/* Palette generated by Material Palette - materialpalette.com/blue/cyan */ - -.dark-primary-color { background: #1976D2; } -.default-primary-color { background: #2196F3; } -.light-primary-color { background: #BBDEFB; } -.text-primary-color { color: #FFFFFF; } -.accent-color { background: #00BCD4; } -.primary-text-color { color: #212121; } -.secondary-text-color { color: #727272; } -.divider-color { border-color: #B6B6B6; } - -/* for layout */ -html, -body { - margin: 0; - padding: 0; - height: 100%; - width: 100%; - overflow: hidden; - box-sizing: border-box; -} - -*, *:before, *:after { - box-sizing: inherit; -} - -body { - display: flex; - flex-direction: column; - -webkit-overflow-scrolling: touch; -} - -header { - flex: 0 0 50px; - display: flex; - flex-direction: row; - align-items: center; - padding-left: 30px; -} - -header ol { - list-style: none; - margin: 0; - padding: 0; -} - -header ol li { - display: inline; -} - -header form { - display: flex; - flex: 1; - justify-content: flex-end; - padding-right: 30px; -} - -header#header-search-sidebar { - height: 50px; - margin-bottom: 25px; -} - -footer { - flex: 0 0 16px; - text-align: center; - padding: 16px 20px; -} - -main { - flex: 1; - display: flex; - flex-direction: row; - padding: 20px; - min-height: 0; -} - -.sidebar-offcanvas-left { - flex: 0 1 230px; - order: 1; - overflow-y: scroll; - padding: 20px 0 15px 30px; - margin: 5px 20px 0 0; - visibility: hidden; /* shown by Javascript after scroll position restore */ -} - -::-webkit-scrollbar-button{ display: none; height: 13px; border-radius: 0px; background-color: #AAA; } -::-webkit-scrollbar-button:hover{ background-color: #AAA; } -::-webkit-scrollbar-thumb{ background-color: #CCC; } -::-webkit-scrollbar-thumb:hover{ background-color: #CCC; } -::-webkit-scrollbar{ width: 4px; } - -.main-content::-webkit-scrollbar{ width: 8px; } - -.main-content { - flex: 1; - order: 2; - overflow-y: scroll; - padding: 10px 20px 0 20px; - visibility: hidden; /* shown by Javascript after scroll position restore */ -} - -.sidebar-offcanvas-right { - flex: 0 1 12em; - order: 3; - overflow-y: scroll; - padding: 20px 15px 15px 15px; - margin-top: 5px; - margin-right: 20px; - visibility: hidden; /* shown by Javascript after scroll position restore */ -} -/* end for layout */ - -body { - -webkit-text-size-adjust: 100%; - overflow-x: hidden; - font-family: Roboto, sans-serif; - font-size: 16px; - line-height: 1.42857143; - color: #111111; - background-color: #fff; -} - -/* some of this is to reset bootstrap */ -nav.navbar { - background-color: inherit; - min-height: 50px; - border: 0; -} - -@media (max-width: 768px) { - .hidden-xs { - display: none !important; - } -} - -@media (min-width: 769px) { - .hidden-l { - display: none !important; - } -} - -nav.navbar .row { - padding-top: 8px; -} - -nav .container { - white-space: nowrap; -} - -header { - background-color: #eeeeee; - box-shadow: 0 3px 5px rgba(0,0,0,0.1); -} - -header.header-fixed nav.navbar-fixed-top { - box-shadow: 0 3px 5px rgba(0,0,0,0.1); -} - -header.container-fluid { - padding: 0; -} - -header .masthead { - padding-top: 64px; -} - -header .contents { - padding: 0; -} - -@media screen and (max-width:768px) { - header .contents { - padding-left: 15px; - padding-right: 15px; - } -} - -a { - text-decoration: none; -} - -.body { - margin-top: 90px; -} - -section { - margin-bottom: 36px; -} - -dl { - margin: 0; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: Roboto, sans-serif; - font-weight: 400; - margin-top: 1.5em; - color: #111111; -} - -h1.title { - overflow: hidden; - text-overflow: ellipsis; -} - -h1 { - font-size: 37px; - margin-top: 0; - margin-bottom: 0.67em; -} - -h2 { - font-size: 28px; -} - -h5 { - font-size: 16px; -} - -.subtitle { - font-size: 17px; - min-height: 1.4em; -} - -.title-description .subtitle { - white-space: nowrap; - overflow-x: hidden; - text-overflow: ellipsis; -} - -p { - margin-bottom: 1em; - margin-top: 0; -} - -a { - color: #0175C2; -} - -a:hover { - color: #13B9FD; -} - -pre.prettyprint { - font-family: 'Roboto Mono', Menlo, monospace; - color: black; - border-radius: 0; - font-size: 15px; - word-wrap: normal; - line-height: 1.4; - border: 0; - margin: 16px 0 16px 0; - padding: 8px; -} - -pre code { - white-space: pre; - word-wrap: initial; - font-size: 100% -} - -.fixed { - white-space: pre; -} - -pre { - border: 1px solid #ddd; - background-color: #eee; - font-size: 14px; -} - -code { - font-family: 'Roboto Mono', Menlo, monospace; - /* overriding bootstrap */ - color: inherit; - padding: 0.2em 0.4em; - font-size: 85%; - background-color: rgba(27,31,35,0.05); - border-radius: 3px; -} - -@media(max-width: 768px) { - nav .container { - width: 100% - } - - h1 { - font-size: 24px; - } - - pre { - margin: 16px 0; - } -} - -@media (min-width: 768px) { - ul.subnav li { - font-size: 17px; - } -} - -header h1 { - font-weight: 400; - margin-bottom: 16px; -} - -header a, -header p, -header li { - color: #111111; -} - -header a:hover { - color: #0175C2; -} - -header h1 .kind { - color: #555; -} - -dt { - font-weight: normal; -} - -dd { - color: #212121; - margin-bottom: 1em; - margin-left: 0; -} - -dd.callable, dd.constant, dd.property { - margin-bottom: 24px; -} - -dd p { - overflow-x: hidden; - text-overflow: ellipsis; - margin-bottom: 0; -} - -/* Enum values do not have their own pages; their full docs are presented on the - * enum class's page. */ -dt.constant + dd p { - margin-bottom: 1em; -} - -/* indents wrapped lines */ -section.summary dt { - margin-left: 24px; - text-indent: -24px; -} - -.dl-horizontal dd { - margin-left: initial; -} - -dl.dl-horizontal dt { - font-style: normal; - text-align: left; - color: #727272; - margin-right: 20px; - width: initial; -} - -dt .name { - font-weight: 500; -} - -dl dt.callable .name { - float: none; - width: auto; -} - -.parameter { - white-space: nowrap; -} - -.type-parameter { - white-space: nowrap; -} - -.multi-line-signature .type-parameter .parameter { - margin-left: 0px; - display: unset; -} - -.parameter-list { - display: table-cell; - margin-left: 10px; - list-style-type: none; -} - -.signature { - color: #727272; -} - -.signature a { - /* 50% mix of default-primary-color and primary-text-color. */ - color: #4674a2; -} - -.optional { - font-style: italic; -} - -.undocumented { - font-style: italic; -} - -.is-const { - font-style: italic; -} - -.deprecated { - text-decoration: line-through; -} - -.category.linked { - font-weight: bold; - opacity: 1; -} - -/* Colors for category based on categoryOrder in dartdoc_options.config. */ -.category.cp-0 { - background-color: #54b7c4 -} - -.category.cp-1 { - background-color: #54c47f -} - -.category.cp-2 { - background-color: #c4c254 -} - -.category.cp-3 { - background-color: #c49f54 -} - -.category.cp-4 { - background-color: #c45465 -} - -.category.cp-5 { - background-color: #c454c4 -} - -.category a { - color: white; -} - -.category { - padding: 2px 4px; - font-size: 12px; - border-radius: 4px; - background-color: #999; - text-transform: uppercase; - color: white; - opacity: .5; -} - -h1 .category { - vertical-align: middle; -} - -.feature { - display: inline-block; - background: white; - border: 1px solid #0175c2; - border-radius: 20px; - color: #0175c2; - - font-size: 12px; - padding: 1px 6px; - margin: 0 8px 0 0; -} - -a.feature:hover { - border-color: #13B9FD; -} - -h1 .feature { - vertical-align: middle; -} - -.source-link { - padding: 18px 4px; - vertical-align: middle; -} - -.source-link .material-icons { - font-size: 18px; -} - -@media (max-width: 768px) { - .source-link { - padding: 7px 2px; - font-size: 10px; - } -} - -#external-links { - float: right; -} - -.btn-group { - position: relative; - display: inline-flex; - vertical-align: middle; -} - -p.firstline { - font-weight: bold; -} - -footer { - color: #fff; - background-color: #111111; - width: 100%; -} - -footer p { - margin: 0; -} - -footer .no-break { - white-space: nowrap; -} - -footer .container, -footer .container-fluid { - padding-left: 0; - padding-right: 0; -} - -footer a, footer a:hover { - color: #fff; -} - -.markdown.desc { - max-width: 700px; -} - -.markdown h1 { - font-size: 24px; - margin-bottom: 8px; -} - -.markdown h2 { - font-size: 20px; - margin-top: 24px; - margin-bottom: 8px; -} - -.markdown h3 { - font-size: 18px; - margin-bottom: 8px; -} - -.markdown h4 { - font-size: 16px; - margin-bottom: 0; -} - -.markdown li p { - margin: 0; -} - -.gt-separated { - list-style: none; - padding: 0; - margin: 0; -} - -.gt-separated li { - display: inline-block; -} - -.gt-separated li:before { - background-image: url("data:image/svg+xml;utf8,"); - background-position: center; - content: "\00a0"; - margin: 0 6px 0 4px; - padding: 0 3px 0 0; -} - -.gt-separated.dark li:before { - background-image: url("data:image/svg+xml;utf8,"); -} - -.gt-separated li:first-child:before { - background-image: none; - content: ""; - margin: 0; - padding: 0; -} - -/* The slug line under a declaration for things like "const", "read-only", etc. */ -.features { - font-style: italic; - color: #727272; -} - -.multi-line-signature { - font-size: 17px; - color: #727272; -} - -.multi-line-signature .parameter { - margin-left: 24px; - display: block; -} - -.breadcrumbs { - padding: 0; - margin: 8px 0 8px 0; - white-space: nowrap; - line-height: 1; -} - -@media screen and (min-width: 768px) { - nav ol.breadcrumbs { - float: left; - } -} - -@media screen and (max-width: 768px) { - .breadcrumbs { - margin: 0 0 24px 0; - overflow-x: hidden; - } -} - -.self-crumb { - color: #555; -} - -.self-name { - color: #555; - display: none; -} - -.annotation-list { - list-style: none; - padding: 0; - display: inline; -} - -.comma-separated { - list-style: none; - padding: 0; - display: inline; -} - -.comma-separated li { - display: inline; -} - -.comma-separated li:after { - content: ", "; -} - -.comma-separated li:last-child:after { - content: ""; -} - -.end-with-period li:last-child:after { - content: "."; -} - -.container > section:first-child { - border: 0; -} - -.constructor-modifier { - font-style: italic; -} - -section.multi-line-signature div.parameters { - margin-left: 24px; -} - -/* subnav styles */ - -ul.subnav { - overflow: auto; - white-space: nowrap; - padding-left: 0; - min-height: 25px; -} - -ul.subnav::-webkit-scrollbar { - display: none; -} - -ul.subnav li { - display: inline-block; - text-transform: uppercase; -} - -ul.subnav li a { - color: #111; -} - -ul.subnav li { - margin-right: 24px; -} - -ul.subnav li:last-of-type { - margin-right: 0; -} - -@media(max-width: 768px) { - ul.subnav li { - margin-right: 16px; - } -} - -/* sidebar styles */ - -.sidebar ol { - list-style: none; - line-height: 22px; - margin-top: 0; - margin-bottom: 0; - padding: 0 0 15px 0; -} - -.sidebar h5 a, -.sidebar h5 a:hover { - color: #727272; -} - -.sidebar h5, -.sidebar ol li { - text-overflow: ellipsis; - overflow: hidden; - padding: 3px 0 3px 3px; -} - -.sidebar h5 { - color: #727272; - font-size: 18px; - margin: 0 0 22px 0; - padding-top: 0; -} - -.sidebar ol li.section-title { - font-size: 18px; - font-weight: normal; - text-transform: uppercase; - padding-top: 25px; -} - -.sidebar ol li.section-subtitle a { - color: inherit; -} - -.sidebar ol li.section-subtitle { - font-weight: 400; - text-transform: uppercase; -} - -.sidebar ol li.section-subitem { - margin-left: 12px; -} - -.sidebar ol li:first-child { - padding-top: 3px; - margin-top: 0; -} - -button { - padding: 0; -} - -#sidenav-left-toggle { - display: none; - vertical-align: text-bottom; - padding: 0; -} - -/* left-nav disappears, and can transition in from the left */ -@media screen and (max-width:768px) { - #sidenav-left-toggle { - display: inline; - background: no-repeat url("data:image/svg+xml;utf8,"); - background-position: center; - width: 24px; - height: 24px; - border: none; - margin-right: 24px; - } - - #overlay-under-drawer.active { - opacity: 0.4; - height: 100%; - z-index: 1999; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: black; - display: block; - } - - .sidebar-offcanvas-left { - left: -100%; - position: fixed; - -webkit-transition:all .25s ease-out; - -o-transition:all .25s ease-out; - transition:all .25s ease-out; - z-index: 2000; - top: 0; - width: 280px; /* works all the way down to an iphone 4 */ - height: 90%; - background-color: white; - overflow-y: scroll; /* TODO: how to hide scroll bars? */ - padding: 10px; - margin: 10px 10px; - box-shadow: 5px 5px 5px 5px #444444; - visibility: hidden; /* shown by Javascript after scroll position restore */ - } - - ol#sidebar-nav { - font-size: 18px; - white-space: pre-line; - } - - .sidebar-offcanvas-left.active { - left: 0; /* this animates our drawer into the page */ - } - - .self-name { - display: inline-block; - } -} - -.sidebar-offcanvas-left h5 { - margin-bottom: 10px; -} - -.sidebar-offcanvas-left h5:last-of-type { - border: 0; - margin-bottom: 25px; -} - -/* the right nav disappears out of view when the window shrinks */ -@media screen and (max-width: 992px) { - .sidebar-offcanvas-right { - display: none; - } -} - -#overlay-under-drawer { - display: none; -} - -/* find-as-you-type search box */ - -/* override bootstrap defaults */ -.form-control { - border-radius: 0; - border: 0; -} - -@media screen and (max-width: 768px) { - form.search { - display: none; - } -} - -.typeahead, -.tt-query, -.tt-hint { - width: 200px; - height: 20px; - padding: 2px 7px 1px 7px; - line-height: 20px; - outline: none; -} - -.typeahead { - background-color: #fff; - border-radius: 2px; -} - -.tt-wrapper { - position: relative; - display: inline-block; -} - -.tt-input { - position: relative; - vertical-align: top; - background-color: transparent; -} - -.tt-query { - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.tt-hint { - position: absolute; - top: 0; - left: 0; - box-shadow: none; - background: none 0 0 / auto repeat scroll padding-box border-box rgb(255, 255, 255); - border-color: transparent; - color: #999; - border-width: 0; -} - -.navbar-right .tt-menu { - right:0; - left: inherit !important; - width: 422px; - max-height: 250px; - overflow-y: scroll; -} - -.tt-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 100; - font-size: 14px; - margin: 0; - padding: 8px 0; - background-color: #fff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); - box-shadow: 0 5px 10px rgba(0,0,0,.2); -} - -.tt-suggestion { - padding: 3px 20px; - color: #212121; -} - -.tt-suggestion:hover { - cursor: pointer; - color: #fff; - background-color: #0097cf; -} - -.tt-suggestion:hover .search-from-lib { - color: #ddd; -} - -.tt-suggestion.tt-cursor { - color: #fff; - background-color: #0097cf; -} - -.tt-suggestion.tt-cursor .search-from-lib { - color: #ddd; -} - -.tt-suggestion p { - margin: 0; -} - -.search-from-lib { - font-style: italic; - color: gray; -} - -.search-body { - border: 1px solid #7f7f7f; - max-width: 400px; - box-shadow: 3px 3px 5px rgba(0,0,0,0.1); -} - -section#setter { - border-top: 1px solid #ddd; - padding-top: 36px; -} - -li.inherited a { - opacity: 0.65; - font-style: italic; -} - -#instance-methods dt.inherited .name, -#instance-properties dt.inherited .name, -#operators dt.inherited .name { - font-weight: 300; - font-style: italic; -} - -#instance-methods dt.inherited .signature, -#instance-properties dt.inherited .signature, -#operators dt.inherited .signature { - font-weight: 300; -} - -@media print { - .subnav, .sidebar { - display:none; - } - - a[href]:after { - content:"" !important; - } -} From d5ad583c4b8f3446bb8ad0cf0bc852216a6f7547 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Wed, 13 Jul 2022 21:45:51 +0100 Subject: [PATCH 17/38] fix(android): hasValidCredentials accepts minTtl as int (#119) --- .../HasValidCredentialsRequestHandler.kt | 4 ++-- .../HasValidCredentialsRequestHandlerTest.kt | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt index 2204236f..6c325b7f 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt @@ -15,9 +15,9 @@ class HasValidCredentialsRequestHandler : CredentialsManagerRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - var minTtl = request.data.get("minTtl") as Long? ?: 0; + val minTtl = request.data.get("minTtl") as Int? ?: 0; - result.success(credentialsManager.hasValidCredentials(minTtl)); + result.success(credentialsManager.hasValidCredentials(minTtl.toLong())); } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt index 1f0c639e..c7a5fc99 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt @@ -17,13 +17,13 @@ class HasValidCredentialsRequestHandlerTest { @Test fun `should call hasValidCredentials with the correct parameters`() { val handler = HasValidCredentialsRequestHandler(); - var minTtl: Long = 30; + val minTtl = 30; val options = hashMapOf( "minTtl" to minTtl, ); val mockResult = mock(); val mockAccount = mock(); - var mockCredentialsManager = mock(); + val mockCredentialsManager = mock(); val request = MethodCallRequest(account = mockAccount, options); handler.handle( @@ -33,7 +33,7 @@ class HasValidCredentialsRequestHandlerTest { mockResult ); - verify(mockCredentialsManager).hasValidCredentials(minTtl); + verify(mockCredentialsManager).hasValidCredentials(minTtl.toLong()); } @Test @@ -41,7 +41,7 @@ class HasValidCredentialsRequestHandlerTest { val handler = HasValidCredentialsRequestHandler(); val mockResult = mock(); val mockAccount = mock(); - var mockCredentialsManager = mock(); + val mockCredentialsManager = mock(); val request = MethodCallRequest(account = mockAccount, mock()); handler.handle( @@ -57,13 +57,13 @@ class HasValidCredentialsRequestHandlerTest { @Test fun `should call result success on success`() { val handler = HasValidCredentialsRequestHandler(); - var minTtl: Long = 30; + val minTtl = 30; val options = hashMapOf( "minTtl" to minTtl, ); val mockResult = mock(); val mockAccount = mock(); - var mockCredentialsManager = mock(); + val mockCredentialsManager = mock(); val request = MethodCallRequest(account = mockAccount, options); From a52779689dbad13bc4537d5affa4b6d8065d23bd Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 14 Jul 2022 08:00:53 -0300 Subject: [PATCH 18/38] Enable the Credentials Manager in the example app (#121) --- auth0_flutter/example/lib/example_app.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth0_flutter/example/lib/example_app.dart b/auth0_flutter/example/lib/example_app.dart index 835c813d..79408269 100644 --- a/auth0_flutter/example/lib/example_app.dart +++ b/auth0_flutter/example/lib/example_app.dart @@ -26,7 +26,7 @@ class _ExampleAppState extends State { void initState() { super.initState(); auth0 = Auth0(dotenv.env['AUTH0_DOMAIN']!, dotenv.env['AUTH0_CLIENT_ID']!); - webAuth = auth0.webAuthentication(useCredentialsManager: false); + webAuth = auth0.webAuthentication(); } Future webAuthLogin() async { From b5fe40a7c1132d48923e94ab9121df4881e1ae03 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 14 Jul 2022 08:01:57 -0300 Subject: [PATCH 19/38] Have the Credentials Manager API follow the Dart design guidelines (#120) --- auth0_flutter/lib/src/credentials_manager.dart | 12 ++++++------ auth0_flutter/lib/src/web_authentication.dart | 4 ++-- auth0_flutter/test/credentials_manager_test.dart | 9 +++++---- auth0_flutter/test/web_authentication_test.dart | 10 ++++++---- .../test/web_authentication_test.mocks.dart | 7 ++++--- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/auth0_flutter/lib/src/credentials_manager.dart b/auth0_flutter/lib/src/credentials_manager.dart index 54f00e2e..bc06d4d4 100644 --- a/auth0_flutter/lib/src/credentials_manager.dart +++ b/auth0_flutter/lib/src/credentials_manager.dart @@ -2,19 +2,19 @@ import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interfac /// Abstract CredentialsManager that can be used to provide a custom CredentialManager. abstract class CredentialsManager { - Future get({ + Future credentials({ final int minTtl = 0, final Set scopes = const {}, final Map parameters = const {}, }); - Future set(final Credentials credentials); + Future storeCredentials(final Credentials credentials); Future hasValidCredentials({ final int minTtl = 0, }); - Future clear(); + Future clearCredentials(); } /// Default [CredentialsManager] implementation that passes calls to @@ -37,7 +37,7 @@ class DefaultCredentialsManager extends CredentialsManager { /// Use the [scopes] parameter to set the scope to request for the access token. If `null` is passed, the previous scope will be kept. /// Use the [parameters] parameter to send additional parameters in the request to refresh expired credentials. @override - Future get({ + Future credentials({ final int minTtl = 0, final Set scopes = const {}, final Map parameters = const {}, @@ -51,7 +51,7 @@ class DefaultCredentialsManager extends CredentialsManager { /// Stores the given credentials in the storage. Must have an `access_token` or `id_token` and a `expires_in` value. @override - Future set(final Credentials credentials) => + Future storeCredentials(final Credentials credentials) => CredentialsManagerPlatform.instance.saveCredentials( _createApiRequest(SaveCredentialsOptions(credentials: credentials))); @@ -67,7 +67,7 @@ class DefaultCredentialsManager extends CredentialsManager { /// Removes the credentials from the storage if present. @override - Future clear() => CredentialsManagerPlatform.instance + Future clearCredentials() => CredentialsManagerPlatform.instance .clearCredentials(_createApiRequest(null)); CredentialsManagerRequest diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index ddff7473..7c2f11c7 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -72,7 +72,7 @@ class WebAuthentication { scheme: scheme, useEphemeralSession: useEphemeralSession))); - await _credentialsManager?.set(credentials); + await _credentialsManager?.storeCredentials(credentials); return credentials; } @@ -88,7 +88,7 @@ class WebAuthentication { await Auth0FlutterWebAuthPlatform.instance.logout(_createWebAuthRequest( WebAuthLogoutOptions(returnTo: returnTo, scheme: scheme), )); - await _credentialsManager?.clear(); + await _credentialsManager?.clearCredentials(); } WebAuthRequest diff --git a/auth0_flutter/test/credentials_manager_test.dart b/auth0_flutter/test/credentials_manager_test.dart index c94dbca8..0b294860 100644 --- a/auth0_flutter/test/credentials_manager_test.dart +++ b/auth0_flutter/test/credentials_manager_test.dart @@ -43,7 +43,7 @@ void main() { .thenAnswer((final _) async => TestPlatform.credentials); await DefaultCredentialsManager(account, userAgent) - .get(minTtl: 30, scopes: {'a', 'b'}, parameters: {'a': 'b'}); + .credentials(minTtl: 30, scopes: {'a', 'b'}, parameters: {'a': 'b'}); final verificationResult = verify(mockedPlatform.getCredentials(captureAny)).captured.single @@ -60,7 +60,7 @@ void main() { when(mockedPlatform.getCredentials(any)) .thenAnswer((final _) async => TestPlatform.credentials); - await DefaultCredentialsManager(account, userAgent).get(); + await DefaultCredentialsManager(account, userAgent).credentials(); final verificationResult = verify(mockedPlatform.getCredentials(captureAny)).captured.single @@ -77,7 +77,8 @@ void main() { when(mockedPlatform.saveCredentials(any)) .thenAnswer((final _) async => true); - await DefaultCredentialsManager(account, userAgent).set(TestPlatform.credentials); + await DefaultCredentialsManager(account, userAgent) + .storeCredentials(TestPlatform.credentials); final verificationResult = verify(mockedPlatform.saveCredentials(captureAny)).captured.single @@ -152,7 +153,7 @@ void main() { when(mockedPlatform.clearCredentials(any)) .thenAnswer((final _) async => true); - await DefaultCredentialsManager(account, userAgent).clear(); + await DefaultCredentialsManager(account, userAgent).clearCredentials(); final verificationResult = verify(mockedPlatform.clearCredentials(captureAny)).captured.single diff --git a/auth0_flutter/test/web_authentication_test.dart b/auth0_flutter/test/web_authentication_test.dart index 19be8d94..52b34d5b 100644 --- a/auth0_flutter/test/web_authentication_test.dart +++ b/auth0_flutter/test/web_authentication_test.dart @@ -125,7 +125,7 @@ void main() { .thenAnswer((final _) async => true); final mockCm = MockCredentialsManager(); - when(mockCm.set(any)) + when(mockCm.storeCredentials(any)) .thenAnswer((final _) async => true); await Auth0('test-domain', 'test-clientId') @@ -142,7 +142,9 @@ void main() { verifyNever(mockedCMPlatform.saveCredentials(any)); final verificationResult = - verify(mockCm.set(captureAny)).captured.single as Credentials; + verify(mockCm.storeCredentials(captureAny)) + .captured + .single as Credentials; expect( verificationResult.accessToken, TestPlatform.loginResult.accessToken); @@ -240,7 +242,7 @@ void main() { when(mockedCMPlatform.clearCredentials(any)) .thenAnswer((final _) async => true); final mockCm = MockCredentialsManager(); - when(mockCm.clear()) + when(mockCm.clearCredentials()) .thenAnswer((final _) async => true); await Auth0('test-domain', 'test-clientId') @@ -250,7 +252,7 @@ void main() { // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager verifyNever(mockedCMPlatform.clearCredentials(any)); - verify(mockCm.clear()).called(1); + verify(mockCm.clearCredentials()).called(1); }); }); } diff --git a/auth0_flutter/test/web_authentication_test.mocks.dart b/auth0_flutter/test/web_authentication_test.mocks.dart index 295ca9df..9ae6cf19 100644 --- a/auth0_flutter/test/web_authentication_test.mocks.dart +++ b/auth0_flutter/test/web_authentication_test.mocks.dart @@ -87,7 +87,7 @@ class MockCredentialsManager extends _i1.Mock } @override - _i4.Future<_i2.Credentials> get( + _i4.Future<_i2.Credentials> credentials( {int? minTtl = 0, Set? scopes = const {}, Map? parameters = const {}}) => @@ -97,7 +97,7 @@ class MockCredentialsManager extends _i1.Mock returnValue: Future<_i2.Credentials>.value(_FakeCredentials_0())) as _i4.Future<_i2.Credentials>); @override - _i4.Future set(_i2.Credentials? credentials) => + _i4.Future storeCredentials(_i2.Credentials? credentials) => (super.noSuchMethod(Invocation.method(#set, [credentials]), returnValue: Future.value(true), returnValueForMissingStub: Future.value()) as _i4.Future); @@ -107,7 +107,8 @@ class MockCredentialsManager extends _i1.Mock Invocation.method(#hasValidCredentials, [], {#minTtl: minTtl}), returnValue: Future.value(false)) as _i4.Future); @override - _i4.Future clear() => (super.noSuchMethod(Invocation.method(#clear, []), + _i4.Future clearCredentials() => + (super.noSuchMethod(Invocation.method(#clear, []), returnValue: Future.value(true), returnValueForMissingStub: Future.value()) as _i4.Future); } From 2164c36c0dd1379e7305e936c1055b8eb03df290 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 15 Jul 2022 06:10:13 -0300 Subject: [PATCH 20/38] Have the iOS `hasvalidCredentials()` match the behavior of the Android one (#125) Match behavior of Android hasValidCredentials() --- ...ntialsManagerHasValidMethodHandlerTests.swift | 16 ++++++++++++++++ ...CredentialsManagerHasValidMethodHandler.swift | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift index a2af7f6e..058ca343 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift @@ -50,6 +50,22 @@ extension CredentialsManagerHasValidMethodHandlerTests { wait(for: [expectation]) } + func testProducesTrueWithRefreshToken() { + let credentials = Credentials(refreshToken: "foo") + let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) + let expectation = self.expectation(description: "Produced true") + let emptyStorage = SpyCredentialsStorage() + emptyStorage.getEntryReturnValue = nil + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: emptyStorage) + sut = CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager, credentialsStorage: spy) + spy.getEntryReturnValue = data + sut.handle(with: arguments()) { result in + XCTAssertEqual(result as? Bool, true) + expectation.fulfill() + } + wait(for: [expectation]) + } + func testProducesFalseWithNoValidCredentials() { let expectation = self.expectation(description: "Produced false") spy.getEntryReturnValue = nil diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift index ece8fbec..251a5591 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift @@ -1,5 +1,6 @@ import Flutter import Auth0 +import SimpleKeychain struct CredentialsManagerHasValidMethodHandler: MethodHandler { enum Argument: String { @@ -7,12 +8,26 @@ struct CredentialsManagerHasValidMethodHandler: MethodHandler { } let credentialsManager: CredentialsManager + let credentialsStorage: CredentialsStorage + let credentialsKey = "credentials" + + init(credentialsManager: CredentialsManager, credentialsStorage: CredentialsStorage = A0SimpleKeychain()) { + self.credentialsManager = credentialsManager + self.credentialsStorage = credentialsStorage + } func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { guard let minTTL = arguments[Argument.minTtl] as? Int else { return callback(FlutterError(from: .requiredArgumentMissing(Argument.minTtl.rawValue))) } + // So it behaves the same as the Credentials Manager from Auth0.Android + if let data = self.credentialsStorage.getEntry(forKey: credentialsKey), + let credentials = try? NSKeyedUnarchiver.unarchivedObject(ofClass: Credentials.self, from: data), + credentials.refreshToken != nil { + return callback(true) + } + callback(credentialsManager.hasValid(minTTL: minTTL)) } } From a46e568283849ae23443449f6ea921f827e4fb60 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 15 Jul 2022 06:34:30 -0300 Subject: [PATCH 21/38] Remove `Auth0APIError` extension [SDK-3498] (#123) Remove `Auth0APIError` extension --- auth0_flutter/ios/Classes/Extensions.swift | 14 -------------- auth0_flutter/ios/auth0_flutter.podspec | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/auth0_flutter/ios/Classes/Extensions.swift b/auth0_flutter/ios/Classes/Extensions.swift index fb881f85..7e35996d 100644 --- a/auth0_flutter/ios/Classes/Extensions.swift +++ b/auth0_flutter/ios/Classes/Extensions.swift @@ -55,20 +55,6 @@ extension Auth0APIError { } } -extension Auth0APIError { - var isPasswordLeaked: Bool { - return self.code == "password_leaked" - } - - var isLoginRequired: Bool { - return self.code == "login_required" - } - - var isNetworkError: Bool { - return (self.cause as? URLError)?.code == URLError.Code.notConnectedToInternet - } -} - extension Credentials { convenience init?(from dictionary: [String: Any]) { guard let accessToken = dictionary[CredentialsProperty.accessToken] as? String, diff --git a/auth0_flutter/ios/auth0_flutter.podspec b/auth0_flutter/ios/auth0_flutter.podspec index 356acb80..5e317412 100644 --- a/auth0_flutter/ios/auth0_flutter.podspec +++ b/auth0_flutter/ios/auth0_flutter.podspec @@ -15,7 +15,7 @@ A new flutter plugin project. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'Auth0', '~> 2.0' + s.dependency 'Auth0', '~> 2.2' s.platform = :ios, '12.0' # Flutter.framework does not contain a i386 slice. From b4751c8e99736f2bd45fa23eb5a17226bed53767 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Mon, 18 Jul 2022 10:14:47 -0300 Subject: [PATCH 22/38] Update READMEs for FA [SDK-3495] (#126) * Update READMEs for FA * Put Web Auth information in a note * Add section on disabling the Credentials Manager --- .github/ISSUE_TEMPLATE/config.yml | 9 +- README.md | 18 +- auth0_flutter/README.md | 248 +++++++++++++++------ auth0_flutter_platform_interface/README.md | 8 + 4 files changed, 204 insertions(+), 79 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 24ac1e1d..1fd5898b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,10 +2,13 @@ blank_issues_enabled: false contact_links: - name: ๐Ÿค” Help & Questions url: https://community.auth0.com/c/sdks/5 - about: Ask general support or usage questions in the Auth0 Community forums. + about: Ask general support or usage questions in the Auth0 Community forums - name: ๐Ÿ“‘ FAQ url: https://github.com/auth0/auth0-flutter/blob/main/auth0_flutter/FAQ.md - about: Check some commonly asked questions. + about: Check some commonly asked questions + - name: ๐Ÿš€ Common Tasks + url: https://github.com/auth0/auth0-flutter/tree/main/auth0_flutter#common-tasks + about: Check the Common Tasks section of the README to get up to speed with auth0_flutter - name: ๐Ÿ“– API Documentation url: https://pub.dev/documentation/auth0_flutter/latest/ - about: Check the public API documentation for in-depth overview of all the available features. + about: Check the public API documentation for in-depth overview of all the available features diff --git a/README.md b/README.md index 149eb7d4..f73487c5 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,18 @@ -![Stage: Beta Release](https://img.shields.io/badge/stage-beta-orange) +![Stage: First Availability Release](https://img.shields.io/badge/stage-fa-yellow) [![CircleCI](https://img.shields.io/circleci/build/github/auth0/auth0-flutter)](https://circleci.com/gh/auth0/auth0-flutter) -[![Codecov](https://img.shields.io/codecov/c/github/auth0/auth0-flutter)](https://codecov.io/gh/auth0/auth0-flutter) +[![Codecov](https://codecov.io/gh/auth0/auth0-flutter/branch/main/graph/badge.svg)](https://codecov.io/gh/auth0/auth0-flutter) -# Auth0 SDK for Flutter (Beta) +# Auth0 SDK for Flutter (First Availability) Auth0 SDK for Android / iOS Flutter apps. -> โš ๏ธ This library is currently in Beta. We do not recommend using this library in production yet. As we move towards First Availaibility, please be aware that releases may contain breaking changes. +> โš ๏ธ This library is currently in First Availability. We do not recommend using this library in production yet. As we move toward General Availability, please be aware that releases may contain breaking changes. | Package | Description | |:------------------------------------------------------------------------|:----------------------------------------------| | [auth0_flutter](./auth0_flutter/) | SDK for Android / iOS Flutter applications | | [auth0_flutter_platform_interface](./auth0_flutter_platform_interface/) | Common interface for platform implementations | -## Features - -- Web Auth login and logout -- Authentication API operations: - + Login with username/email and password - + Signup - + Get user information from `/userinfo` - + Renew credentials - + Reset password - ## Getting Started See the README of the [auth0_flutter](./auth0_flutter#readme) package. diff --git a/auth0_flutter/README.md b/auth0_flutter/README.md index c77d0ce9..1bb1f386 100644 --- a/auth0_flutter/README.md +++ b/auth0_flutter/README.md @@ -1,16 +1,19 @@ # Auth0 SDK for Flutter (Beta) -[![CircleCI](https://img.shields.io/circleci/project/github/auth0/auth0-flutter.svg?style=flat-square)](https://circleci.com/gh/auth0/auth0-flutter/tree/main) +[![CircleCI](https://img.shields.io/circleci/project/github/auth0/auth0-flutter.svg)](https://circleci.com/gh/auth0/auth0-flutter/tree/main) +[![Codecov](https://codecov.io/gh/auth0/auth0-flutter/branch/main/graph/badge.svg)](https://codecov.io/gh/auth0/auth0-flutter) +[![Package](https://img.shields.io/pub/v/auth0_flutter.svg)](https://pub.dartlang.org/packages/auth0_flutter) Auth0 SDK for Android / iOS Flutter apps. -> โš ๏ธ This library is currently in Beta. We do not recommend using this library in production yet. As we move towards First Availability, please be aware that releases may contain breaking changes. +> โš ๏ธ This library is currently in First Availability. We do not recommend using this library in production yet. As we move toward General Availability, please be aware that releases may contain breaking changes. --- ## Table of Contents - +- [**Features**](#features) +- [**Documentation**](#documentation) - [**Requirements**](#requirements) - [**Installation**](#installation) - [**Getting Started**](#getting-started) @@ -20,8 +23,9 @@ Auth0 SDK for Android / iOS Flutter apps. + [Web Auth Logout](#web-auth-logout) + [SSO Alert Box (iOS)](#sso-alert-box-ios) - [**Next Steps**](#next-steps) - + + [Common Tasks](#common-tasks) + [Web Auth](#web-auth) + + [Credentials Manager](#credentials-manager) + [API](#api) - [**Advanced Features**](#advanced-features) + [Organizations](#organizations) @@ -30,11 +34,27 @@ Auth0 SDK for Android / iOS Flutter apps. - [**What is Auth0?**](#what-is-auth0) - [**License**](#license) - +- [**Quickstart**](https://auth0.com/docs/quickstart/native/flutter/interactive) +
Shows how to integrate auth0_flutter into an Android / iOS Flutter app from scratch. +- [**Sample app**](https://github.com/auth0-samples/auth0-flutter-samples/tree/main/sample) +
A complete, running Android / iOS Flutter app you can try. +- [**API documentation**](https://pub.dev/documentation/auth0_flutter/latest/) +
Documentation auto-generated from the code comments that explains all the available features. +- [**FAQ**](FAQ.md) +
Answers some common questions about flutter_auth0. ## Requirements @@ -46,20 +66,17 @@ TBD ## Installation -During the Beta stage the SDK will not be published to Pub.dev, but you can install it as a [path package](https://dart.dev/tools/pub/dependencies#path-packages). Extract the contents of the provided zip file and then add the following dependency in your `pubspec.yaml` file: +Add auth0_flutter into your project: -```yaml -auth0_flutter: - path: path/to/auth0_flutter +```sh +flutter pub add auth0_flutter ``` -Then, run `flutter pub get`. - ## Getting Started ### Configuration -auth0_flutter needs the **Client ID** and **Domain** of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). If you are using aย [Custom Domain](https://auth0.com/docs/brand-and-customize/custom-domains), use the value of your Custom Domain instead of the value from the settings page. +auth0_flutter needs the **Client ID** and **Domain** of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). If you are using aย [Custom Domain](https://auth0.com/docs/customize/custom-domains), use the value of your Custom Domain instead of the value from the settings page. > โš ๏ธ Make sure that the [application type](https://auth0.com/docs/configure/applications) of the Auth0 application is **Native**. If you donโ€™t have a Native Auth0 application already, [create one](https://auth0.com/docs/get-started/create-apps/native-apps) before continuing. @@ -87,7 +104,7 @@ Go to the settings page of your [Auth0 application](https://manage.auth0.com/#/a https://YOUR_AUTH0_DOMAIN/android/YOUR_APP_PACKAGE_NAME/callback ``` -E.g. if your Auth0 Domain was `company.us.auth0.com` and your Android app package name was `com.company.myapp`, then this value would be: +For example, if your Auth0 Domain was `company.us.auth0.com` and your Android app package name was `com.company.myapp`, then this value would be: ```text https://company.us.auth0.com/android/com.company.myapp/callback @@ -99,7 +116,7 @@ https://company.us.auth0.com/android/com.company.myapp/callback YOUR_BUNDLE_IDENTIFIER://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback ``` -E.g. if your iOS bundle identifier was `com.company.myapp` and your Auth0 Domain was `company.us.auth0.com`, then this value would be: +For example, if your iOS bundle identifier was `com.company.myapp` and your Auth0 Domain was `company.us.auth0.com`, then this value would be: ```text com.company.myapp://company.us.auth0.com/ios/com.company.myapp/callback @@ -114,16 +131,18 @@ Open the `android/build.gradle` file and add the following manifest placeholders android { // ... + defaultConfig { // ... // Add the following line manifestPlaceholders = [auth0Domain: "YOUR_AUTH0_DOMAIN", auth0Scheme: "${applicationId}"] } + // ... } ``` -E.g. if your Auth0 Domain was `company.us.auth0.com`, then the manifest placeholders line would be: +For example, if your Auth0 Domain was `company.us.auth0.com`, then the manifest placeholders line would be: ```groovy manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${applicationId}"] @@ -163,7 +182,7 @@ manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${app #### iOS configuration: custom URL scheme -Open the `ios/Runner/Info.plist` file and add the following snippet inside the top-level `` tag. This registers your iOS Bundle Identifier as a custom URL scheme, so the callback and logout URLs can reach your app. +Open the `ios/Runner/Info.plist` file and add the following snippet inside the top-level `` tag. This registers your iOS bundle identifier as a custom URL scheme, so the callback and logout URLs can reach your app. ```xml @@ -206,16 +225,24 @@ import 'package:auth0_flutter/auth0_flutter.dart'; Then, present the [Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) page in the `onPressed` callback of your **Login** button. ```dart -final result = await auth0.webAuthentication.login(); +final credentials = await auth0.webAuthentication().login(); +``` + +auth0_flutter will automatically store the user's credentials using the built-in [Credentials Manager](#credentials-manager) instance. You can access this instance through the `credentialsManager` property. + +```dart +final credentials = + await auth0.webAuthentication().credentialsManager?.credentials(); ```
Add an audience value - Specify an [audience](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience) to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the **API Identifier** of your [Auth0 API](https://auth0.com/docs/get-started/apis), e.g. `https://example.com/api`. + Specify an [audience](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience) to obtain an access token that can be used to make authenticated requests to a backend. The audience value is the **API Identifier** of your [Auth0 API](https://auth0.com/docs/get-started/apis), for example `https://example.com/api`. ```dart - final result = await auth0.webAuthentication + final credentials = await auth0 + .webAuthentication() .login(audience: 'YOUR_AUTH0_API_IDENTIFIER'); ```
@@ -226,7 +253,8 @@ final result = await auth0.webAuthentication.login(); Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile`, `email`, and `offline_access`. Regardless of the values specified, `openid` is always included. ```dart - final result = await auth0.webAuthentication + final credentials = await auth0 + .webAuthentication() .login(scopes: {'profile', 'email', 'offline_access', 'read:todos'}); ```
@@ -241,7 +269,7 @@ final result = await auth0.webAuthentication.login(); 3. Pass the scheme value to the `login()` method. ```dart - final result = await auth0.webAuthentication.login(scheme: {'demo'}); + final credentials = await auth0.webAuthentication().login(scheme: 'demo'); ```
@@ -249,10 +277,10 @@ final result = await auth0.webAuthentication.login(); Logging the user out involves clearing the Universal Login session cookie and then deleting the user's credentials from your app. -Call the `logout()` method in the in the `onPressed` callback of your **Logout** button. Once the session cookie has been cleared, delete the user's credentials. +Call the `logout()` method in the `onPressed` callback of your **Logout** button. Once the session cookie has been cleared, auth0_flutter will automatically delete the user's credentials. If you're using your own credentials storage, make sure to delete the credentials afterward. ```dart -await auth0.webAuthentication.logout(); +await auth0.webAuthentication().logout(); ``` ### SSO Alert Box (iOS) @@ -265,20 +293,22 @@ Check the [FAQ](FAQ.md) for more information about the alert box that pops up ** [Go up โคด](#table-of-contents) -## Next Steps - - +- [**Retrieve user information**](#retrieve-user-information) +
Fetch the latest user information from the `/userinfo` endpoint. +- [**Check for stored credentials**](#check-for-stored-credentials) +
Check if the user is already logged in when your app starts up. +- [**Retrieve stored credentials**](#retrieve-stored-credentials) +
Fetch the user's credentials from the storage, automatically renewing them if they have expired. ### Web Auth - [Web Auth signup](#web-auth-signup) -- [ID Token validation](#id-token-validation) +- [ID token validation](#id-token-validation) +- [Disable credentials storage](#disable-credentials-storage) - [Web Auth errors](#web-auth-errors) #### Web Auth signup @@ -293,36 +323,126 @@ You can make users land directly on the Signup page instead of the Login page by | `'prompt': 'login', 'screen_hint': 'signup'` | Shows the signup page | Shows the signup page | ```dart -final result = await auth0.webAuthentication +final credentials = await auth0 + .webAuthentication() .login(parameters: {'screen_hint': 'signup'}); ``` > โš ๏ธ The `screen_hint` parameter will work with the **New Universal Login Experience** without any further configuration. If you are using the **Classic Universal Login Experience**, you need to customize the [login template](https://manage.auth0.com/#/login_page) to look for this parameter and set the `initialScreen` [option](https://github.com/auth0/lock#database-options) of the `Auth0Lock` constructor. -#### ID Token validation +#### ID token validation + +auth0_flutter automatically [validates](https://auth0.com/docs/secure/tokens/id-tokens/validate-id-tokens) the ID token obtained from Web Auth login, following the [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html). This ensures the contents of the ID token have not been tampered with and can be safely used. -auth0_flutter automatically [validates](https://auth0.com/docs/secure/tokens/id-tokens/validate-id-tokens) the ID Token obtained from Web Auth login, following the [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html). This ensures the contents of the ID Token have not been tampered with and can be safely used. +You can configure the ID token validation by passing an `IdTokenValidationConfig` instance. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/IdTokenValidationConfig-class.html) to learn more about the available configuration options. + +```dart +const config = IdTokenValidationConfig(leeway: 10); +final credentials = + await auth0.webAuthentication().login(idTokenValidationConfig: config); +``` ##### Custom Domains -Users of Auth0 Private Cloud with Custom Domains still on the [legacy behavior](https://auth0.com/docs/deploy/private-cloud/private-cloud-migrations/migrate-private-cloud-custom-domains) need to specify a custom issuer to match the Auth0 Domain when performing Web Auth login. Otherwise, the ID Token validation will fail. +Users of Auth0 Private Cloud with Custom Domains still on the [legacy behavior](https://auth0.com/docs/deploy/private-cloud/private-cloud-migrations/migrate-private-cloud-custom-domains) need to specify a custom issuer to match the Auth0 Domain when performing Web Auth login. Otherwise, the ID token validation will fail. ```dart -final config = IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/'); -final result = - await auth0.webAuthentication.login(idTokenValidationConfig: config); +const config = + IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/'); +final credentials = + await auth0.webAuthentication().login(idTokenValidationConfig: config); +``` + +#### Disable credentials storage + +By default, auth0_flutter will automatically store the user's credentials after login and delete them after logout, using the built-in [Credentials Manager](#credentials-manager) instance. If you prefer to use your own credentials storage, you need to disable the built-in Credentials Manager. + +```dart +final credentials = + await auth0.webAuthentication(useCredentialsManager: false).login(); ``` #### Web Auth errors -Web Auth will only throw `WebAuthException` exceptions. +Web Auth will only throw `WebAuthException` exceptions. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/WebAuthException-class.html) to learn more about the available `WebAuthException` properties. ```dart try { - final result = await auth0.webAuthentication.login(); + final credentials = await auth0.webAuthentication().login(); // ... } on WebAuthException catch (e) { - print(e.toString()) + print(e.toString()); +} +``` + +### Credentials Manager + + + +- [Check for stored credentials](#check-for-stored-credentials) +- [Retrieve stored credentials](#retrieve-stored-credentials) +- [Local authentication](#local-authentication) +- [Credentials Manager errors](#credentials-manager-errors) + +The Credentials Manager utility allows you to securely store and retrieve the user's credentials. The credentials will be stored encrypted in Shared Preferences on Android, and in the Keychain on iOS. + +> ๐Ÿ’ก If you're using Web Auth, you do not need to manually store the credentials after login and delete them after logout; auth0_flutter does it automatically. + +#### Check for stored credentials + +When the users open your app, check for valid credentials. If they exist, you can retrieve them and redirect the users to the app's main flow without any additional login steps. + +```dart +final isLoggedIn = await auth0 + .webAuthentication() + .credentialsManager + ?.hasValidCredentials() ?? + false; + +if (isLoggedIn) { + // Retrieve the credentials and redirect to the main flow +} else { + // No valid credentials exist, present the login page +} +``` + +#### Retrieve stored credentials + +The credentials will be automatically renewed (if expired) using the [refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens). **This method is thread-safe.** + +```dart +final credentials = + await auth0.webAuthentication().credentialsManager?.credentials(); +``` + +> ๐Ÿ’ก You do not need to call `credentialsManager?.storeCredentials()` afterward. The Credentials Manager automatically persists the renewed credentials. + +#### Local authentication + +You can enable an additional level of user authentication before retrieving credentials using the local authentication supported by the device, for example PIN or fingerprint on Android, and Face ID or Touch ID on iOS. + +```dart +final localAuthentication = + LocalAuthenticationOptions(title: 'Please authenticate to continue'); + final credentials = await auth0 + .webAuthentication(localAuthentication: localAuthentication) + .credentialsManager + ?.credentials(); +``` + +Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/LocalAuthenticationOptions-class.html) to learn more about the available `LocalAuthenticationOptions` properties. + +#### Credentials Manager errors + +The Credentials Manager will only throw `CredentialsManagerException` exceptions. You can find more information in the `details` property of the exception. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/CredentialsManagerException-class.html) to learn more about the available `CredentialsManagerException` properties. + +```dart +try { + final credentials = + await auth0.webAuthentication().credentialsManager?.credentials(); + // ... +} on CredentialsManagerException catch (e) { + print(e.toString()); } ``` @@ -343,12 +463,12 @@ For login or signup with username/password, the `Password` grant type needs to b > ๐Ÿ’ก If your Auth0 account has the **Bot Detection** feature enabled, your requests might be flagged for verification. Check how to handle this scenario in the [Bot Detection](#bot-detection) section. -> โš ๏ธ The ID Tokens obtained from Web Auth login are automatically validated by auth0_flutter, ensuring their contents have not been tampered with. **This is not the case for the ID Tokens obtained from the Authentication API client.** You must [validate](https://auth0.com/docs/security/tokens/id-tokens/validate-id-tokens) any ID Tokens received from the Authentication API client before using the information they contain. +> โš ๏ธ The ID tokens obtained from Web Auth login are automatically validated by auth0_flutter, ensuring their contents have not been tampered with. **This is not the case for the ID tokens obtained from the Authentication API client.** You must [validate](https://auth0.com/docs/security/tokens/id-tokens/validate-id-tokens) any ID tokens received from the Authentication API client before using the information they contain. #### Login with database connection ```dart -final result = await auth0.api.login( +final credentials = await auth0.api.login( usernameOrEmail: 'jane.smith@example.com', password: 'secret-password', connectionOrRealm: 'Username-Password-Authentication'); @@ -357,10 +477,10 @@ final result = await auth0.api.login(
Add an audience value - Specify an [audience](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience) to obtain an Access Token that can be used to make authenticated requests to a backend. The audience value is the **API Identifier** of your [Auth0 API](https://auth0.com/docs/get-started/apis), e.g. `https://example.com/api`. + Specify an [audience](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience) to obtain an access token that can be used to make authenticated requests to a backend. The audience value is the **API Identifier** of your [Auth0 API](https://auth0.com/docs/get-started/apis), for example `https://example.com/api`. ```dart - final result = await auth0.api.login( + final credentials = await auth0.api.login( usernameOrEmail: 'jane.smith@example.com', password: 'secret-password', connectionOrRealm: 'Username-Password-Authentication', @@ -374,7 +494,7 @@ final result = await auth0.api.login( Specify [scopes](https://auth0.com/docs/get-started/apis/scopes) to request permission to access protected resources, like the user profile. The default scope values are `openid`, `profile`, `email`, and `offline_access`. Regardless of the values specified, `openid` is always included. ```dart - final result = await auth0.api.login( + final credentials = await auth0.api.login( usernameOrEmail: 'jane.smith@example.com', password: 'secret-password', connectionOrRealm: 'Username-Password-Authentication', @@ -385,7 +505,7 @@ final result = await auth0.api.login( #### Sign up with database connection ```dart -final user = await auth0.api.signup( +final credentials = await auth0.api.signup( email: 'jane.smith@example.com', password: 'secret-password', connection: 'Username-Password-Authentication', @@ -398,7 +518,7 @@ final user = await auth0.api.signup( Fetch the latest user information from the `/userinfo` endpoint. -This method will yield a `UserProfile` instance. +This method will yield a `UserProfile` instance. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/UserProfile-class.html) to learn more about its available properties. ```dart final userProfile = await auth0.api.userInfo(accessToken: accessToken); @@ -406,27 +526,28 @@ final userProfile = await auth0.api.userInfo(accessToken: accessToken); #### Renew credentials -Use a [Refresh Token](https://auth0.com/docs/secure/tokens/refresh-tokens) to renew the user's credentials. It's recommended that you read and understand the Refresh Token process beforehand. +Use a [refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens) to renew the user's credentials. It's recommended that you read and understand the refresh token process beforehand. ```dart -final result = await auth0.api.renewCredentials(refreshToken: refreshToken); +final credentials = + await auth0.api.renewCredentials(refreshToken: refreshToken); ``` -> ๐Ÿ’ก To obtain a Refresh Token, make sure your Auth0 application has the **Refresh Token** [grant enabled](https://auth0.com/docs/get-started/applications/update-grant-types). If you are also specifying an audience value, make sure that the corresponding Auth0 API has the **Allow Offline Access** [setting enabled](https://auth0.com/docs/get-started/apis/api-settings#access-settings). +> ๐Ÿ’ก To obtain a refresh token, make sure your Auth0 application has the **refresh token** [grant enabled](https://auth0.com/docs/get-started/applications/update-grant-types). If you are also specifying an audience value, make sure that the corresponding Auth0 API has the **Allow Offline Access** [setting enabled](https://auth0.com/docs/get-started/apis/api-settings#access-settings). #### API client errors -The Authentication API client will only throw `ApiException` exceptions. You can find more information in the `details` property of the exception. +The Authentication API client will only throw `ApiException` exceptions. You can find more information in the `details` property of the exception. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/ApiException-class.html) to learn more about the available `ApiException` properties. ```dart try { - final result = await auth0.api.login( - usernameOrEmail: email, - password: password, - connectionOrRealm: connection); + final credentials = await auth0.api.login( + usernameOrEmail: email, + password: password, + connectionOrRealm: connection); // ... } on ApiException catch (e) { - print(e.toString()) + print(e.toString()); } ``` @@ -451,7 +572,8 @@ Using Organizations, you can: #### Log in to an organization ```dart -final result = await auth0.webAuthentication +final credentials = await auth0 + .webAuthentication() .login(organizationId: 'YOUR_AUTH0_ORGANIZATION_ID'); ``` @@ -462,7 +584,8 @@ To accept organization invitations your app needs to support [deep linking](http When your app gets opened by an invitation link, grab the invitation URL and pass it to the `login()` method. ```dart -final result = await auth0.webAuthentication.login(invitationUrl: url); +final credentials = + await auth0.webAuthentication().login(invitationUrl: url); ``` ### Bot Detection @@ -471,7 +594,7 @@ If you are performing database login/signup via the Authentication API and would ```dart try { - final result = await auth0.api.login( + final credentials = await auth0.api.login( usernameOrEmail: email, password: password, connectionOrRealm: connection, @@ -479,9 +602,10 @@ try { // ... } on ApiException catch (e) { if (e.isVerificationRequired) { - final result = await auth0.webAuthentication.login( + final credentials = await auth0.webAuthentication().login( scopes: scopes, - useEphemeralSession: true, // Otherwise a session cookie will remain (iOS-only) + useEphemeralSession: + true, // Otherwise a session cookie will remain (iOS-only) parameters: { 'connection': connection, 'login_hint': email // So the user doesn't have to type it again diff --git a/auth0_flutter_platform_interface/README.md b/auth0_flutter_platform_interface/README.md index aeec3a86..7e360a10 100644 --- a/auth0_flutter_platform_interface/README.md +++ b/auth0_flutter_platform_interface/README.md @@ -1,7 +1,15 @@ # auth0_flutter_platform_interface +[![CircleCI](https://img.shields.io/circleci/project/github/auth0/auth0-flutter.svg)](https://circleci.com/gh/auth0/auth0-flutter/tree/main) +[![Codecov](https://codecov.io/gh/auth0/auth0-flutter/branch/main/graph/badge.svg?flag=auth0_flutter_platform_interface)](https://codecov.io/gh/auth0/auth0-flutter) +[![Package](https://img.shields.io/pub/v/auth0_flutter_platform_interface.svg)](https://pub.dartlang.org/packages/auth0_flutter_platform_interface) + This package provides the common interface for platform implementations. +**[API documentation โ†—](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/)** + +> โš ๏ธ This library is currently in First Availability. We do not recommend using this library in production yet. As we move toward General Availability, please be aware that releases may contain breaking changes. + ## Issue Reporting For general support or usage questions, use the [Auth0 Community](https://community.auth0.com/c/sdks/5) forums or raise a [support ticket](https://support.auth0.com/). Only [raise an issue](https://github.com/auth0/auth0_flutter/issues) if you have found a bug or want to request a feature. From 8d36a7523f7659989ee99f69ca0c8e46da61346d Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Tue, 19 Jul 2022 11:41:39 -0300 Subject: [PATCH 23/38] Move the Credentials Manager instance to `Auth0` (#124) * Move the Credentials Manager instance to `Auth0` * Reword API docs of `Auth0` constructor --- auth0_flutter/lib/auth0_flutter.dart | 49 ++++++++++--------- auth0_flutter/lib/src/web_authentication.dart | 2 - .../test/credentials_manager_test.dart | 6 +-- .../test/web_authentication_test.dart | 19 +++---- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/auth0_flutter/lib/auth0_flutter.dart b/auth0_flutter/lib/auth0_flutter.dart index 749631e0..362235fc 100644 --- a/auth0_flutter/lib/auth0_flutter.dart +++ b/auth0_flutter/lib/auth0_flutter.dart @@ -26,11 +26,29 @@ class Auth0 { final UserAgent _userAgent = UserAgent(name: 'auth0-flutter', version: version); + late final CredentialsManager _credentialsManager; + + /// Secure [Credentials] store. + CredentialsManager get credentialsManager => _credentialsManager; + /// Creates an intance of an Auth0 client with the provided [domain] and [clientId] properties. /// /// [domain] and [clientId] are both values that can be retrieved from the application in your [Auth0 Dashboard](https://manage.auth0.com). - Auth0(final String domain, final String clientId) - : _account = Account(domain, clientId); + /// If you want to use your own implementation to handle credential storage, provide your own [CredentialsManager] implementation + /// by setting [credentialsManager]. A [DefaultCredentialsManager] instance is used by default. + /// If you want to use biometrics or pass-phrase when using the [DefaultCredentialsManager], set [localAuthentication]` to an instance of [LocalAuthenticationOptions]. + /// Note however that this setting has no effect when specifying a custom [credentialsManager]. + Auth0(final String domain, final String clientId, + {final LocalAuthenticationOptions? localAuthentication, + final CredentialsManager? credentialsManager}) + : _account = Account(domain, clientId) { + _credentialsManager = credentialsManager ?? + DefaultCredentialsManager( + _account, + _userAgent, + localAuthentication: localAuthentication, + ); + } /// An instance of [AuthenticationApi], the primary interface for interacting with the Auth0 Authentication API /// @@ -59,25 +77,10 @@ class Auth0 { /// final result = await auth0.webAuthentication().login(); /// final accessToken = result.accessToken; /// ``` - /// - /// Uses the [DefaultCredentialsManager] by default. If you want to use your own implementation to handle credential storage, provide your own [CredentialsManager] implementation - /// by setting [customCredentialsManager]. - /// In case you want to opt-out of using any [CredentialsManager] alltogether, set [useCredentialsManager] to `false`. - /// If you want to use biometrics or pass-phrase when using the [DefaultCredentialsManager], set [localAuthentication]` to an instance of [LocalAuthenticationOptions]. - /// Note however that this setting has no effect when specifying a [customCredentialsManager]. - WebAuthentication webAuthentication({ - final bool useCredentialsManager = true, - final LocalAuthenticationOptions? localAuthentication, - final CredentialsManager? customCredentialsManager, - }) { - final credentialsManager = useCredentialsManager - ? (customCredentialsManager ?? - (DefaultCredentialsManager( - _account, - _userAgent, - localAuthentication: localAuthentication, - ))) - : null; - return WebAuthentication(_account, _userAgent, credentialsManager); - } + /// By default, the credentials will be stored in the [CredentialsManager]. + /// In case you want to opt-out of using the [CredentialsManager], set [useCredentialsManager] to `false`. + WebAuthentication webAuthentication( + {final bool useCredentialsManager = true}) => + WebAuthentication(_account, _userAgent, + useCredentialsManager ? credentialsManager : null); } diff --git a/auth0_flutter/lib/src/web_authentication.dart b/auth0_flutter/lib/src/web_authentication.dart index 7c2f11c7..7e780ebd 100644 --- a/auth0_flutter/lib/src/web_authentication.dart +++ b/auth0_flutter/lib/src/web_authentication.dart @@ -22,8 +22,6 @@ class WebAuthentication { final UserAgent _userAgent; final CredentialsManager? _credentialsManager; - CredentialsManager? get credentialsManager => _credentialsManager; - WebAuthentication(this._account, this._userAgent, this._credentialsManager); /// Redirects the user to the [Auth0 Universal Login page](https://auth0.com/docs/authenticate/login/auth0-universal-login) for authentication. If successful, it returns diff --git a/auth0_flutter/test/credentials_manager_test.dart b/auth0_flutter/test/credentials_manager_test.dart index 0b294860..9cfe5e8e 100644 --- a/auth0_flutter/test/credentials_manager_test.dart +++ b/auth0_flutter/test/credentials_manager_test.dart @@ -37,7 +37,7 @@ void main() { reset(mockedPlatform); }); - group('get', () { + group('credentials', () { test('passes through properties to the platform', () async { when(mockedPlatform.getCredentials(any)) .thenAnswer((final _) async => TestPlatform.credentials); @@ -72,7 +72,7 @@ void main() { }); }); - group('set', () { + group('storeCredentials', () { test('passes through properties to the platform', () async { when(mockedPlatform.saveCredentials(any)) .thenAnswer((final _) async => true); @@ -148,7 +148,7 @@ void main() { }); }); - group('clear', () { + group('clearCredentials', () { test('calls the platform', () async { when(mockedPlatform.clearCredentials(any)) .thenAnswer((final _) async => true); diff --git a/auth0_flutter/test/web_authentication_test.dart b/auth0_flutter/test/web_authentication_test.dart index 52b34d5b..84b4f2fb 100644 --- a/auth0_flutter/test/web_authentication_test.dart +++ b/auth0_flutter/test/web_authentication_test.dart @@ -125,11 +125,10 @@ void main() { .thenAnswer((final _) async => true); final mockCm = MockCredentialsManager(); - when(mockCm.storeCredentials(any)) - .thenAnswer((final _) async => true); + when(mockCm.storeCredentials(any)).thenAnswer((final _) async => true); - await Auth0('test-domain', 'test-clientId') - .webAuthentication(customCredentialsManager: mockCm) + await Auth0('test-domain', 'test-clientId', credentialsManager: mockCm) + .webAuthentication() .login( audience: 'test-audience', scopes: {'a', 'b'}, @@ -141,8 +140,7 @@ void main() { // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager verifyNever(mockedCMPlatform.saveCredentials(any)); - final verificationResult = - verify(mockCm.storeCredentials(captureAny)) + final verificationResult = verify(mockCm.storeCredentials(captureAny)) .captured .single as Credentials; @@ -170,7 +168,7 @@ void main() { expect(verificationResult.options.parameters, {}); expect(result, TestPlatform.loginResult); }); - + test('does not use EphemeralSession by default', () async { when(mockedPlatform.login(any)) .thenAnswer((final _) async => TestPlatform.loginResult); @@ -242,11 +240,10 @@ void main() { when(mockedCMPlatform.clearCredentials(any)) .thenAnswer((final _) async => true); final mockCm = MockCredentialsManager(); - when(mockCm.clearCredentials()) - .thenAnswer((final _) async => true); + when(mockCm.clearCredentials()).thenAnswer((final _) async => true); - await Auth0('test-domain', 'test-clientId') - .webAuthentication(customCredentialsManager: mockCm) + await Auth0('test-domain', 'test-clientId', credentialsManager: mockCm) + .webAuthentication() .logout(returnTo: 'abc'); // Verify it doesn't call our own Platform Interface when providing a custom CredentialsManager From 148d64e1729f7191e724949b6e7d518a1b80e3ae Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Tue, 19 Jul 2022 23:33:56 +0100 Subject: [PATCH 24/38] Merge branch main into first-availability (#129) * Merge branch main into first-availability * Temporarily reference local platform package interface --- .github/workflows/semgrep.yml | 24 +++ README.md | 2 +- auth0_flutter/CHANGELOG.md | 21 ++- auth0_flutter/README.md | 156 +++++++++--------- auth0_flutter/pubspec.yaml | 4 +- auth0_flutter_platform_interface/CHANGELOG.md | 21 ++- auth0_flutter_platform_interface/README.md | 2 +- auth0_flutter_platform_interface/pubspec.yaml | 2 +- 8 files changed, 144 insertions(+), 88 deletions(-) create mode 100644 .github/workflows/semgrep.yml diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 00000000..e0227e37 --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,24 @@ +name: Semgrep + +on: + pull_request: {} + + push: + branches: ["master", "main"] + + schedule: + - cron: '30 0 1,15 * *' + +jobs: + semgrep: + name: Scan + runs-on: ubuntu-latest + container: + image: returntocorp/semgrep + if: (github.actor != 'dependabot[bot]') + steps: + - uses: actions/checkout@v3 + + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/README.md b/README.md index f73487c5..470cd93c 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,4 @@ Auth0 helps you to: ## License -This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more information. +This project is licensed under Apache License 2.0. See the [LICENSE](LICENSE) file for more information. diff --git a/auth0_flutter/CHANGELOG.md b/auth0_flutter/CHANGELOG.md index d99d5b3c..5256b223 100644 --- a/auth0_flutter/CHANGELOG.md +++ b/auth0_flutter/CHANGELOG.md @@ -1,6 +1,25 @@ # Change Log -## [1.0.0-beta.0](https://github.com/auth0/Auth0.swift/tree/1.0.0-beta.0) (2022-05-05) +## [1.0.0-beta.1](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.1) (2022-07-08) + +This is the first public beta release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ + +> โš ๏ธ This release is not yet suitable for use in production + +The Auth0 Flutter SDK is a new SDK designed to make it quick and easy to integrate Auth0 into Flutter applications. Today, the SDK offers the following features: + +- Support for iOS and Android +- Integration with [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) +- Integration with the [Auth0 Authentication API](https://auth0.com/docs/api/authentication) for: + - username and password login + - signup + - refreshing access tokens + - password reset + - fetching user profile + +Check out [the Readme](https://github.com/auth0/auth0-flutter/blob/main/auth0_flutter/README.md) for a more detailed run through of the capabilities and API. + +## [1.0.0-beta.0](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.0) (2022-05-05) **Added** diff --git a/auth0_flutter/README.md b/auth0_flutter/README.md index 1bb1f386..4b666cfe 100644 --- a/auth0_flutter/README.md +++ b/auth0_flutter/README.md @@ -17,19 +17,19 @@ Auth0 SDK for Android / iOS Flutter apps. - [**Requirements**](#requirements) - [**Installation**](#installation) - [**Getting Started**](#getting-started) - + [Configuration](#configuration) - + [Web Auth Configuration](#web-auth-configuration) - + [Web Auth Login](#web-auth-login) - + [Web Auth Logout](#web-auth-logout) - + [SSO Alert Box (iOS)](#sso-alert-box-ios) + - [Configuration](#configuration) + - [Web Auth Configuration](#web-auth-configuration) + - [Web Auth Login](#web-auth-login) + - [Web Auth Logout](#web-auth-logout) + - [SSO Alert Box (iOS)](#sso-alert-box-ios) - [**Next Steps**](#next-steps) + [Common Tasks](#common-tasks) + [Web Auth](#web-auth) + [Credentials Manager](#credentials-manager) + [API](#api) - [**Advanced Features**](#advanced-features) - + [Organizations](#organizations) - + [Bot Detection](#bot-detection) + - [Organizations](#organizations) + - [Bot Detection](#bot-detection) - [**Issue Reporting**](#issue-reporting) - [**What is Auth0?**](#what-is-auth0) - [**License**](#license) @@ -58,8 +58,8 @@ Auth0 SDK for Android / iOS Flutter apps. ## Requirements -| Flutter | Android |iOS | -|:-----------|:----------------|:------------------| +| Flutter | Android | iOS | +| :--------- | :-------------- | :---------------- | | SDK 3.0+ | Android API 21+ | iOS 12+ | | Dart 2.17+ | Java 8+ | Swift 5.3+ | | | | Xcode 12.x / 13.x | @@ -76,7 +76,7 @@ flutter pub add auth0_flutter ### Configuration -auth0_flutter needs the **Client ID** and **Domain** of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). If you are using aย [Custom Domain](https://auth0.com/docs/customize/custom-domains), use the value of your Custom Domain instead of the value from the settings page. +`auth0_flutter` needs the **client ID** and **domain** of the Auth0 application to communicate with Auth0. You can find these details on the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). If you are using a [custom domain](https://auth0.com/docs/brand-and-customize/custom-domains), use the value of your custom domain instead of the value from the settings page. > โš ๏ธ Make sure that the [application type](https://auth0.com/docs/configure/applications) of the Auth0 application is **Native**. If you donโ€™t have a Native Auth0 application already, [create one](https://auth0.com/docs/get-started/create-apps/native-apps) before continuing. @@ -94,9 +94,9 @@ final auth0 = Auth0('YOUR_AUTH0_DOMAIN', 'YOUR_AUTH0_CLIENT_ID'); The callback and logout URLs are the URLs that Auth0 invokes to redirect back to your app. Auth0 invokes the callback URL after authenticating the user, and the logout URL after removing the session cookie. -Since callback and logout URLs can be manipulated, you will need to add your URLs to the **Allowed Callback URLs** and **Allowed Logout URLs**ย fields in the settings page of your Auth0 application. This will enable Auth0 to recognize these URLs as valid. If the callback and logout URLs are not set, users will be unable to log in and out of the app and will get an error. +Since callback and logout URLs can be manipulated, you will need to add your URLs to the **Allowed Callback URLs** and **Allowed Logout URLs** fields in the settings page of your Auth0 application. This will enable Auth0 to recognize these URLs as valid. If the callback and logout URLs are not set, users will be unable to log in and out of the app and will get an error. -Go to the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/) and add the corresponding URLs to **Allowed Callback URLs** and **Allowed Logout URLs**, according to the platforms used by your app. If you are using aย [Custom Domain](https://auth0.com/docs/brand-and-customize/custom-domains), replace `YOUR_AUTH0_DOMAIN` with the value of your Custom Domain instead of the value from the settings page. +Go to the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/) and add the corresponding URLs to **Allowed Callback URLs** and **Allowed Logout URLs**, according to the platforms used by your app. If you are using a [custom domain](https://auth0.com/docs/brand-and-customize/custom-domains), replace `YOUR_AUTH0_DOMAIN` with the value of your custom domain instead of the value from the settings page. ##### Android @@ -104,7 +104,7 @@ Go to the settings page of your [Auth0 application](https://manage.auth0.com/#/a https://YOUR_AUTH0_DOMAIN/android/YOUR_APP_PACKAGE_NAME/callback ``` -For example, if your Auth0 Domain was `company.us.auth0.com` and your Android app package name was `com.company.myapp`, then this value would be: +For example, if your Auth0 domain was `company.us.auth0.com` and your Android app package name was `com.company.myapp`, then this value would be: ```text https://company.us.auth0.com/android/com.company.myapp/callback @@ -116,7 +116,7 @@ https://company.us.auth0.com/android/com.company.myapp/callback YOUR_BUNDLE_IDENTIFIER://YOUR_AUTH0_DOMAIN/ios/YOUR_BUNDLE_IDENTIFIER/callback ``` -For example, if your iOS bundle identifier was `com.company.myapp` and your Auth0 Domain was `company.us.auth0.com`, then this value would be: +For example, if your iOS bundle identifier was `com.company.myapp` and your Auth0 domain was `company.us.auth0.com`, then this value would be: ```text com.company.myapp://company.us.auth0.com/ios/com.company.myapp/callback @@ -124,7 +124,7 @@ com.company.myapp://company.us.auth0.com/ios/com.company.myapp/callback #### Android configuration: manifest placeholders -Open the `android/build.gradle` file and add the following manifest placeholders inside `android > defaultConfig`. The `applicationId` value will be auto-replaced at runtime with your Android app package name. +Open the `android/build.gradle` file and add the following manifest placeholders inside `android > defaultConfig`. The `applicationId` value will be auto-replaced at runtime with your Android app package name. ```groovy // android/build.gradle @@ -142,7 +142,7 @@ android { } ``` -For example, if your Auth0 Domain was `company.us.auth0.com`, then the manifest placeholders line would be: +For example, if your Auth0 domain was `company.us.auth0.com`, then the manifest placeholders line would be: ```groovy manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${applicationId}"] @@ -153,31 +153,32 @@ manifestPlaceholders = [auth0Domain: "company.us.auth0.com", auth0Scheme: "${app
Skipping the Android Web Auth configuration - If you don't plan to use Web Auth, you will notice that the compiler will still prompt you to provide the `manifestPlaceholders` values, since the `RedirectActivity` included in this library will require them, and the Gradle tasks won't be able to run without them. - - Re-declare the activity manually using `tools:node="remove"` in the `android/src/main/AndroidManifest.xml` file to make the [manifest merger](https://developer.android.com/studio/build/manage-manifests#merge-manifests) remove it from the final manifest file. Additionally, one more unused activity can be removed from the final APK by using the same process. A complete snippet to achieve this is: - - ```xml - - - - - - - - - - - - - - ``` +If you don't plan to use Web Auth, you will notice that the compiler will still prompt you to provide the `manifestPlaceholders` values, since the `RedirectActivity` included in this library will require them, and the Gradle tasks won't be able to run without them. + +Re-declare the activity manually using `tools:node="remove"` in the `android/src/main/AndroidManifest.xml` file to make the [manifest merger](https://developer.android.com/studio/build/manage-manifests#merge-manifests) remove it from the final manifest file. Additionally, one more unused activity can be removed from the final APK by using the same process. A complete snippet to achieve this is: + +```xml + + + + + + + + + + + + + +``` +
#### iOS configuration: custom URL scheme @@ -206,7 +207,7 @@ Open the `ios/Runner/Info.plist` file and add the following snippet inside the t - + @@ -216,7 +217,7 @@ Open the `ios/Runner/Info.plist` file and add the following snippet inside the t ### Web Auth Login -Import auth0_flutter in the file where you want to present the login page. +Import `auth0_flutter` in the file where you want to present the login page. ```dart import 'package:auth0_flutter/auth0_flutter.dart'; @@ -262,22 +263,22 @@ final credentials =
Add a custom scheme value (Android-only) - On Android, auth0_flutter uses `https` by default as the callback URL scheme. This works best for Android API 23+ if you're using [Android App Links](https://auth0.com/docs/get-started/applications/enable-android-app-links-support), but in previous Android versions this _may_ show the intent chooser dialog prompting the user to choose either your app or the browser. You can change this behavior by using a custom unique scheme so that Android opens the link directly with your app. Note that schemes [can only have lowercase letters](https://developer.android.com/guide/topics/manifest/data-element). +On Android, `https` is used by default as the callback URL scheme. This works best for Android API 23+ if you're using [Android App Links](https://auth0.com/docs/get-started/applications/enable-android-app-links-support), but in previous Android versions, this \_may show the intent chooser dialog prompting the user to choose either your app or the browser. You can change this behavior by using a custom unique scheme so that Android opens the link directly with your app. Note that schemes [can only have lowercase letters](https://developer.android.com/guide/topics/manifest/data-element). - 1. Update the `auth0Scheme` manifest placeholder on the `android/build.gradle` file. - 2. Update the **Allowed Callback URLs** in the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). - 3. Pass the scheme value to the `login()` method. +1. Update the `auth0Scheme` manifest placeholder on the `android/build.gradle` file. +2. Update the **Allowed Callback URLs** in the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/). +3. Pass the scheme value to the `login()` method. - ```dart - final credentials = await auth0.webAuthentication().login(scheme: 'demo'); - ``` +```dart +final credentials = await auth0.webAuthentication().login(scheme: 'demo'); +```
### Web Auth Logout Logging the user out involves clearing the Universal Login session cookie and then deleting the user's credentials from your app. -Call the `logout()` method in the `onPressed` callback of your **Logout** button. Once the session cookie has been cleared, auth0_flutter will automatically delete the user's credentials. If you're using your own credentials storage, make sure to delete the credentials afterward. +Call the `logout()` method in the `onPressed` callback of your **Logout** button. Once the session cookie has been cleared, `auth0_flutter` will automatically delete the user's credentials. If you're using your own credentials storage, make sure to delete the credentials afterward. ```dart await auth0.webAuthentication().logout(); @@ -308,19 +309,18 @@ Check the [FAQ](FAQ.md) for more information about the alert box that pops up ** - [Web Auth signup](#web-auth-signup) - [ID token validation](#id-token-validation) -- [Disable credentials storage](#disable-credentials-storage) - [Web Auth errors](#web-auth-errors) #### Web Auth signup You can make users land directly on the Signup page instead of the Login page by specifying the `'screen_hint': 'signup'` parameter. Note that this can be combined with `'prompt': 'login'`, which indicates whether you want to always show the authentication page or you want to skip if there's an existing session. -| Parameters | No existing session | Existing session | -|:-----------------------------------------------|:----------------------|:------------------------------| -| No extra parameters | Shows the login page | Redirects to the callback url | -| `'screen_hint': 'signup'` | Shows the signup page | Redirects to the callback url | -| `'prompt': 'login'` | Shows the login page | Shows the login page | -| `'prompt': 'login', 'screen_hint': 'signup'` | Shows the signup page | Shows the signup page | +| Parameters | No existing session | Existing session | +| :------------------------------------------- | :-------------------- | :---------------------------- | +| No extra parameters | Shows the login page | Redirects to the callback URL | +| `'screen_hint': 'signup'` | Shows the signup page | Redirects to the callback URL | +| `'prompt': 'login'` | Shows the login page | Shows the login page | +| `'prompt': 'login', 'screen_hint': 'signup'` | Shows the signup page | Shows the signup page | ```dart final credentials = await auth0 @@ -332,30 +332,32 @@ final credentials = await auth0 #### ID token validation -auth0_flutter automatically [validates](https://auth0.com/docs/secure/tokens/id-tokens/validate-id-tokens) the ID token obtained from Web Auth login, following the [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html). This ensures the contents of the ID token have not been tampered with and can be safely used. +`auth0_flutter` automatically [validates](https://auth0.com/docs/secure/tokens/id-tokens/validate-id-tokens) the ID token obtained from Web Auth login, following the [OpenID Connect specification](https://openid.net/specs/openid-connect-core-1_0.html). This ensures the contents of the ID token have not been tampered with and can be safely used. You can configure the ID token validation by passing an `IdTokenValidationConfig` instance. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/IdTokenValidationConfig-class.html) to learn more about the available configuration options. ```dart const config = IdTokenValidationConfig(leeway: 10); + final credentials = await auth0.webAuthentication().login(idTokenValidationConfig: config); ``` -##### Custom Domains +##### Custom domains -Users of Auth0 Private Cloud with Custom Domains still on the [legacy behavior](https://auth0.com/docs/deploy/private-cloud/private-cloud-migrations/migrate-private-cloud-custom-domains) need to specify a custom issuer to match the Auth0 Domain when performing Web Auth login. Otherwise, the ID token validation will fail. +Users of Auth0 Private Cloud with custom domains still on the [legacy behavior](https://auth0.com/docs/deploy/private-cloud/private-cloud-migrations/migrate-private-cloud-custom-domains) need to specify a custom issuer to match the Auth0 domain when performing Web Auth login. Otherwise, the ID token validation will fail. ```dart const config = IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/'); + final credentials = await auth0.webAuthentication().login(idTokenValidationConfig: config); ``` #### Disable credentials storage -By default, auth0_flutter will automatically store the user's credentials after login and delete them after logout, using the built-in [Credentials Manager](#credentials-manager) instance. If you prefer to use your own credentials storage, you need to disable the built-in Credentials Manager. +By default, `auth0_flutter` will automatically store the user's credentials after login and delete them after logout, using the built-in [Credentials Manager](#credentials-manager) instance. If you prefer to use your own credentials storage, you need to disable the built-in Credentials Manager. ```dart final credentials = @@ -457,13 +459,13 @@ try { - [API client errors](#api-client-errors) The Authentication API exposes the AuthN/AuthZ functionality of Auth0, as well as the supported identity protocols like OpenID Connect, OAuth 2.0, and SAML. -We recommend using [Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login), but if you prefer to build your own UI you can use our API endpoints to do so. However, some Auth flows (grant types) are disabled by default so you must enable them in the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/), as explained in [Update Grant Types](https://auth0.com/docs/get-started/applications/update-grant-types). +We recommend using [Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login), but if you prefer to build your own UI you can use our API endpoints to do so. However, some Auth flows (grant types) are disabled by default so you must enable them on the settings page of your [Auth0 application](https://manage.auth0.com/#/applications/), as explained in [Update Grant Types](https://auth0.com/docs/get-started/applications/update-grant-types). -For login or signup with username/password, the `Password` grant type needs to be enabled in your app. If you set the grants via the Management API you should activate both `http://auth0.com/oauth/grant-type/password-realm` and `Password`. Otherwise, the Auth0 Dashboard will take care of activating both when enabling `Password`. +To log in or sign up with a username and password, the `Password` grant type needs to be enabled in your app. If you set the grants via the Management API you should activate both `http://auth0.com/oauth/grant-type/password-realm` and `Password`. Otherwise, the Auth0 Dashboard will take care of activating both when enabling `Password`. > ๐Ÿ’ก If your Auth0 account has the **Bot Detection** feature enabled, your requests might be flagged for verification. Check how to handle this scenario in the [Bot Detection](#bot-detection) section. -> โš ๏ธ The ID tokens obtained from Web Auth login are automatically validated by auth0_flutter, ensuring their contents have not been tampered with. **This is not the case for the ID tokens obtained from the Authentication API client.** You must [validate](https://auth0.com/docs/security/tokens/id-tokens/validate-id-tokens) any ID tokens received from the Authentication API client before using the information they contain. +> โš ๏ธ The ID tokens obtained from Web Auth login are automatically validated by `auth0_flutter`, ensuring their contents have not been tampered with. **This is not the case for the ID tokens obtained from the Authentication API client.** You must [validate](https://auth0.com/docs/security/tokens/id-tokens/validate-id-tokens) any ID tokens received from the Authentication API client before using the information they contain. #### Login with database connection @@ -557,15 +559,7 @@ try { ### Organizations -[Organizations](https://auth0.com/docs/manage-users/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. - -Using Organizations, you can: - -- Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations. -- Manage their membership in a variety of ways, including user invitation. -- Configure branded, federated login flows for each organization. -- Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations. -- Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations. +[Organizations](https://auth0.com/docs/manage-users/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. > ๐Ÿ’ก Organizations is currently only available to customers on our Enterprise and Startup subscription plans. @@ -625,18 +619,18 @@ For general support or usage questions, use the [Auth0 Community](https://commun Auth0 helps you to: -* Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. -* Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. -* Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. -* Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. -* Analytics of how, when, and where users are logging in. -* Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). +- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. +- Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. +- Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. +- Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. +- Analytics of how, when, and where users are logging in. +- Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). **Why Auth0?** Because you should save time, be happy, and focus on what really matters: building your product. ## License -This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more information. +This project is licensed under Apache License 2.0. See the [LICENSE](LICENSE) file for more information. --- diff --git a/auth0_flutter/pubspec.yaml b/auth0_flutter/pubspec.yaml index 57c11bba..dea79f26 100644 --- a/auth0_flutter/pubspec.yaml +++ b/auth0_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: auth0_flutter -description: A new flutter plugin project. -version: 1.0.0-beta.0 +description: Auth0 SDK for Flutter +version: 1.0.0-beta.1 homepage: https://github.com/auth0/auth0-flutter publish_to: none diff --git a/auth0_flutter_platform_interface/CHANGELOG.md b/auth0_flutter_platform_interface/CHANGELOG.md index d99d5b3c..5256b223 100644 --- a/auth0_flutter_platform_interface/CHANGELOG.md +++ b/auth0_flutter_platform_interface/CHANGELOG.md @@ -1,6 +1,25 @@ # Change Log -## [1.0.0-beta.0](https://github.com/auth0/Auth0.swift/tree/1.0.0-beta.0) (2022-05-05) +## [1.0.0-beta.1](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.1) (2022-07-08) + +This is the first public beta release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ + +> โš ๏ธ This release is not yet suitable for use in production + +The Auth0 Flutter SDK is a new SDK designed to make it quick and easy to integrate Auth0 into Flutter applications. Today, the SDK offers the following features: + +- Support for iOS and Android +- Integration with [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) +- Integration with the [Auth0 Authentication API](https://auth0.com/docs/api/authentication) for: + - username and password login + - signup + - refreshing access tokens + - password reset + - fetching user profile + +Check out [the Readme](https://github.com/auth0/auth0-flutter/blob/main/auth0_flutter/README.md) for a more detailed run through of the capabilities and API. + +## [1.0.0-beta.0](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.0) (2022-05-05) **Added** diff --git a/auth0_flutter_platform_interface/README.md b/auth0_flutter_platform_interface/README.md index 7e360a10..1f205090 100644 --- a/auth0_flutter_platform_interface/README.md +++ b/auth0_flutter_platform_interface/README.md @@ -31,4 +31,4 @@ Auth0 helps you to: ## License -This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more information. +This project is licensed under Apache License 2.0. See the [LICENSE](LICENSE) file for more information. diff --git a/auth0_flutter_platform_interface/pubspec.yaml b/auth0_flutter_platform_interface/pubspec.yaml index f97dfed7..28f1f95b 100644 --- a/auth0_flutter_platform_interface/pubspec.yaml +++ b/auth0_flutter_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: auth0_flutter_platform_interface description: A common platform interface for the auth0_flutter plugin. -version: 1.0.0-beta.0 +version: 1.0.0-beta.1 homepage: https://github.com/auth0/auth0-flutter environment: From 14d1112456987a20d9a93e7a2624c342e6e69b04 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 20 Jul 2022 08:01:03 -0300 Subject: [PATCH 25/38] Apply word list to READMEs and API docs (#133) --- README.md | 4 ++-- auth0_flutter/example/README.md | 4 ++-- auth0_flutter/lib/src/authentication_api.dart | 2 +- auth0_flutter_platform_interface/README.md | 4 ++-- auth0_flutter_platform_interface/lib/src/credentials.dart | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 470cd93c..ee6cd5ed 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ For general support or usage questions, use the [Auth0 Community](https://commun Auth0 helps you to: -- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. +- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML identity provider**. - Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. - Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. -- Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. +- Support for generating signed [JSON web tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. - Analytics of how, when, and where users are logging in. - Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). diff --git a/auth0_flutter/example/README.md b/auth0_flutter/example/README.md index 6b1e3e8d..dce62867 100644 --- a/auth0_flutter/example/README.md +++ b/auth0_flutter/example/README.md @@ -51,10 +51,10 @@ Configure the `com_auth0_scheme` entry with the correct value, if you require a Auth0 helps you to: -- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. +- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML identity provider**. - Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. - Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. -- Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. +- Support for generating signed [JSON web tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. - Analytics of how, when, and where users are logging in. - Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). diff --git a/auth0_flutter/lib/src/authentication_api.dart b/auth0_flutter/lib/src/authentication_api.dart index 2a50fa2c..b2263c04 100644 --- a/auth0_flutter/lib/src/authentication_api.dart +++ b/auth0_flutter/lib/src/authentication_api.dart @@ -130,7 +130,7 @@ class AuthenticationApi { /// * [scopes] can be specified if a reduced set of scopes is desired. /// /// ## Further reading - /// [Refresh Tokens on Auth0 docs](https://auth0.com/docs/secure/tokens/refresh-tokens) + /// [Refresh tokens on Auth0 docs](https://auth0.com/docs/secure/tokens/refresh-tokens) /// /// ## Usage example /// diff --git a/auth0_flutter_platform_interface/README.md b/auth0_flutter_platform_interface/README.md index 1f205090..5d15b07f 100644 --- a/auth0_flutter_platform_interface/README.md +++ b/auth0_flutter_platform_interface/README.md @@ -20,10 +20,10 @@ For general support or usage questions, use the [Auth0 Community](https://commun Auth0 helps you to: -- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. +- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML identity provider**. - Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. - Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. -- Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. +- Support for generating signed [JSON web tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. - Analytics of how, when, and where users are logging in. - Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). diff --git a/auth0_flutter_platform_interface/lib/src/credentials.dart b/auth0_flutter_platform_interface/lib/src/credentials.dart index 10194979..9e55662b 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials.dart @@ -2,7 +2,7 @@ import '../auth0_flutter_platform_interface.dart'; /// A collection of authentication artifacts obtained from Auth0 when a user logs in. class Credentials { - /// A [JSON Web Token](https://jwt.io/introduction) that contains the user information. + /// A [JSON web token](https://jwt.io/introduction) that contains the user information. /// /// **Important**: The [ID tokens](https://auth0.com/docs/security/tokens/id-tokens) obtained from Web Auth login are automatically validated by the underlying native SDK, ensuring their /// contents have not been tampered with. From c691a2c5d35ce491c056a220b9d16ca4c7f0becb Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 20 Jul 2022 08:01:35 -0300 Subject: [PATCH 26/38] Export `DatabaseUser` [SDK-3504] (#130) --- auth0_flutter/lib/auth0_flutter.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/auth0_flutter/lib/auth0_flutter.dart b/auth0_flutter/lib/auth0_flutter.dart index 362235fc..c6eb418b 100644 --- a/auth0_flutter/lib/auth0_flutter.dart +++ b/auth0_flutter/lib/auth0_flutter.dart @@ -12,6 +12,7 @@ export 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interfac IdTokenValidationConfig, Credentials, UserProfile, + DatabaseUser, CredentialsManagerException, LocalAuthenticationOptions; From dd89e0cae4f418222e4f53ebeac3fa0e24b1ef83 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 20 Jul 2022 08:02:10 -0300 Subject: [PATCH 27/38] Make `LocalAuthenticationOptions` constructor `const` (#131) --- .../options/local_authentication_options.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart index 3d1a65d0..6ba11c9c 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/options/local_authentication_options.dart @@ -12,6 +12,6 @@ class LocalAuthenticationOptions { /// (iOS only): Fallback message to display on the local authentication prompt after a failed match. final String? fallbackTitle; - LocalAuthenticationOptions( + const LocalAuthenticationOptions( {this.title, this.description, this.cancelTitle, this.fallbackTitle}); } From b38e776571fe2dd8c3282f5ddc0a9df33ee4a0b8 Mon Sep 17 00:00:00 2001 From: Frederik Prijck Date: Thu, 21 Jul 2022 00:26:27 +0200 Subject: [PATCH 28/38] [SDK-3502] Add Android Smoke Tests (#128) * Add PoC of Android smoke tests with UIAutomator * Update PoC * Run UIAutomator on Circle CI * Cleanup circle config * Rework config file * fix typo * add android orb to local-android * increase timeout * Uncomment custom scheme * Make sure to dismiss keyboard * clean up circle config * Remove external storage permissions * Remove requestLegacyExternalStorage * Remove appium tests * Update DEVELOPMENT.md * Only run smoke tests on non-forks * Remove iOS device from Android tests * Update auth0_flutter/example/android/app/src/androidTest/kotlin/com/auth0/auth0_flutter_example/SmokeTest.kt * Update .circleci/config.yml * Update .circleci/config.yml * Update .circleci/config.yml * Update .circleci/config.yml Co-authored-by: Rita Zerrizuela --- .circleci/config.yml | 93 +++++++++++++++++-- DEVELOPMENT.md | 40 +------- auth0_flutter/example/.env.example | 8 +- .../example/android/app/build.gradle | 14 ++- .../auth0/auth0_flutter_example/SmokeTest.kt | 88 ++++++++++++++++++ .../android/app/src/main/AndroidManifest.xml | 1 + .../src/main/res/values/strings.xml.example | 2 +- .../capabilities/android.dart | 8 -- .../capabilities/capabilities.dart | 7 -- .../integration_test/capabilities/ios.dart | 10 -- .../integration_test/pages/auth0_page.dart | 55 ----------- .../integration_test/pages/example_page.dart | 27 ------ .../integration_test/pages/system_page.dart | 10 -- .../example/integration_test/smoke_test.dart | 54 ----------- .../integration_test/utils/wait_for.dart | 25 ----- auth0_flutter/example/lib/main.dart | 4 - auth0_flutter/example/pubspec.yaml | 3 - 17 files changed, 194 insertions(+), 255 deletions(-) create mode 100644 auth0_flutter/example/android/app/src/androidTest/kotlin/com/auth0/auth0_flutter_example/SmokeTest.kt delete mode 100644 auth0_flutter/example/integration_test/capabilities/android.dart delete mode 100644 auth0_flutter/example/integration_test/capabilities/capabilities.dart delete mode 100644 auth0_flutter/example/integration_test/capabilities/ios.dart delete mode 100644 auth0_flutter/example/integration_test/pages/auth0_page.dart delete mode 100644 auth0_flutter/example/integration_test/pages/example_page.dart delete mode 100644 auth0_flutter/example/integration_test/pages/system_page.dart delete mode 100644 auth0_flutter/example/integration_test/smoke_test.dart delete mode 100644 auth0_flutter/example/integration_test/utils/wait_for.dart diff --git a/.circleci/config.yml b/.circleci/config.yml index 55d71032..3f404cb7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,10 +4,56 @@ orbs: macos: circleci/macos@2 flutter: circleci/flutter@1 codecov: codecov/codecov@3 + local-android: + orbs: + android: circleci/android@2 + commands: + prepare-config: + description: "Prepares the environment configuration files" + steps: + - run: + name: Prepare Environment Configuration + command: | + cp .env.example .env + sed -i "s/YOUR_AUTH0_DOMAIN/$AUTH0_DOMAIN/" .env + sed -i "s/YOUR_AUTH0_CLIENT_ID/$AUTH0_CLIENT_ID/" .env + sed -i "s/YOUR_AUTH0_CUSTOM_SCHEME/$AUTH0_CUSTOM_SCHEME/" .env + + mv android/app/src/main/res/values/strings.xml.example android/app/src/main/res/values/strings.xml + sed -i "s/YOUR_AUTH0_DOMAIN/$AUTH0_DOMAIN/" android/app/src/main/res/values/strings.xml + + mv android/local.properties.ci android/local.properties + working_directory: ./auth0_flutter/example + run-smoke-tests: + description: "Runs the Android smoke tests" + parameters: + android_simulator: + type: string + steps: + - android/accept-licenses + - android/create-avd: + avd-name: auth0_sample_avd + system-image: << parameters.android_simulator >> + install: true + - android/start-emulator: + avd-name: auth0_sample_avd + no-window: true + restore-gradle-cache-prefix: v1a + post-emulator-launch-assemble-command: "" + post-emulator-wait-steps: + - run: + name: Disable Chrome welcome prompt + command: adb shell 'echo "chrome --disable-fre --no-default-browser-check --no-first-run" > /data/local/tmp/chrome-command-line' + - run: + name: Enable ADB root + command: adb root + - android/run-tests: + max-tries: 1 + working-directory: ./auth0_flutter/example/android parameters: flutter_version: type: string - default: 3.0.0 + default: 3.0.5 jobs: test_flutter_package: docker: @@ -59,19 +105,14 @@ jobs: flutter_version: << pipeline.parameters.flutter_version >> - android/restore-gradle-cache - android/restore-build-cache + - local-android/prepare-config - run: name: Build Android Example App - command: | - cp .env.example .env - mv android/app/src/main/res/values/strings.xml.example android/app/src/main/res/values/strings.xml - flutter build apk + command: flutter build apk working_directory: ./auth0_flutter/example - run: - name: Run Android tests - command: | - mv local.properties.ci local.properties - mv ../.env.example ../.env - gradle clean jacocoTestReportDebug + name: Run Android Unit tests + command: gradle clean jacocoTestReportDebug working_directory: ./auth0_flutter/example/android - android/save-gradle-cache - android/save-build-cache @@ -89,6 +130,34 @@ jobs: file: ./auth0_flutter/example/build/auth0_flutter/reports/jacoco/debug/jacoco.xml upload_name: Auth0 Flutter Android flags: auth0_flutter_android + smoke_test_android: + parameters: + android_simulator: + type: string + executor: + name: android/android-machine + resource-class: xlarge + tag: "2022.06.1" + steps: + - run: + name: Guard Smoke Tests + command: | + if ! [[ -z "$CIRCLE_PR_NUMBER" ]]; then + circleci-agent step halt + fi + - checkout + - flutter/install_sdk_and_pub: + app-dir: ./auth0_flutter + flutter_version: << pipeline.parameters.flutter_version >> + - local-android/prepare-config + - run: + name: Build Android app + command: flutter build apk + working_directory: ./auth0_flutter/example + - local-android/run-smoke-tests: + android_simulator: << parameters.android_simulator >> + - android/save-gradle-cache: + cache-prefix: v1a test_ios: parameters: ios_simulator: @@ -145,6 +214,10 @@ workflows: - test_android: requires: - test_flutter_package + - smoke_test_android: + android_simulator: system-images;android-29;google_apis;x86 + requires: + - test_flutter_package - test_ios: ios_simulator: iPhone 13 requires: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 98916b3e..0f88c47a 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -10,38 +10,9 @@ Run the unit tests for both packages using `flutter test` in **/auth0_flutter** The example app can be run by executing `flutter run` in **/auth0_flutter/example**. -## Integration tests +## Android Integration tests -### Appium - -> โš ๏ธ If you haven't installed Node yet, be sure to install the latest LTS version from [https://nodejs.org/en/download/](https://nodejs.org/en/download/). - -The integration tests are configured to use [Appium](https://appium.io/), make sure it's is installed using npm: - -``` -npm i -g appium -``` - -As Appium needs to be able to communicate with the flutter example application, install the flutter driver using npm: - -``` -npm i -g appium-flutter-driver -``` - -Once the above dependencies are installed, verify the Appium installation by using [appium-doctor](https://github.com/appium/appium-doctor): - -``` -npx appium-doctor -``` - -If there appears to be some issues with any of the **necessary** dependencies, fix those and run `npx appium-doctor` again. -Once `npx appium-doctor` reports a succesful installation, appium can be started using the terminal: - -``` -appium -``` - -> โš ๏ธ Appium interacts with device emulators, ensure an emulator for Android or iOS is running and accessible from the Appium server before running the tests. +UIAutomator interacts with device emulators, ensure an emulator for Android is running and accessible before running the tests. ### Environment Variables @@ -51,15 +22,12 @@ The above tests rely on a couple of environment variables that can be defined in - `AUTH0_CLIENT_ID`: Auth0 Client Id - `USER_EMAIL`: Email to log into the configured Auth0 Domain and Client Id - `USER_PASSWORD`: Password to log into the configured Auth0 Domain and Client Id -- `APPIUM_URL`: The URL to the Appium (`/wd/hub`) Endpoint. - -When running Appium locally, the url for Appium typically is `http://127.0.0.1:4723/wd/hub/`. ### Running the tests -With Appium running succesfully, and the environment variables defined, we can execute the integration tests using the terminal from **/auth0_flutter/example**: +With the environment variables defined, we can execute the integration tests using the terminal from **/auth0_flutter/example/android**: ``` -dart integration_test/smoke_test.dart +./gradlew connectedDebugAndroidTest ``` diff --git a/auth0_flutter/example/.env.example b/auth0_flutter/example/.env.example index e4ca6413..99a2d408 100644 --- a/auth0_flutter/example/.env.example +++ b/auth0_flutter/example/.env.example @@ -1,11 +1,11 @@ # # Your Auth0 Domain. -# -AUTH0_DOMAIN= +# +AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN # # The Client Id of your Auth0 application. # -AUTH0_CLIENT_ID= +AUTH0_CLIENT_ID=YOUR_AUTH0_CLIENT_ID # # The custom scheme for the Android callback and logout URLs. # Only set a value if you prefer not to use the default scheme (https). @@ -14,4 +14,4 @@ AUTH0_CLIENT_ID= # settings page of your Auth0 application with the custom scheme value. # 2. Update the scheme value in android/app/src/main/res/values/strings.xml # -# AUTH0_CUSTOM_SCHEME= \ No newline at end of file +AUTH0_CUSTOM_SCHEME=YOUR_AUTH0_CUSTOM_SCHEME diff --git a/auth0_flutter/example/android/app/build.gradle b/auth0_flutter/example/android/app/build.gradle index 8cffab7b..1cfbb65f 100644 --- a/auth0_flutter/example/android/app/build.gradle +++ b/auth0_flutter/example/android/app/build.gradle @@ -43,6 +43,7 @@ android { sourceSets { main.java.srcDirs += 'src/main/kotlin' + androidTest.java.srcDirs += 'src/androidTest/kotlin' } defaultConfig { @@ -52,8 +53,15 @@ android { targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "@string/com_auth0_scheme"] + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + manifestPlaceholders = [auth0Domain: "$System.env.AUTH0_DOMAIN", + auth0Scheme: "$System.env.AUTH0_CUSTOM_SCHEME"] + testOptions { + animationsDisabled = true + buildConfigField "String", "USER_EMAIL", "\"$System.env.USER_EMAIL\"" + buildConfigField "String", "USER_PASSWORD", "\"$System.env.USER_PASSWORD\"" + } } buildTypes { @@ -74,4 +82,8 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' } diff --git a/auth0_flutter/example/android/app/src/androidTest/kotlin/com/auth0/auth0_flutter_example/SmokeTest.kt b/auth0_flutter/example/android/app/src/androidTest/kotlin/com/auth0/auth0_flutter_example/SmokeTest.kt new file mode 100644 index 00000000..864090c7 --- /dev/null +++ b/auth0_flutter/example/android/app/src/androidTest/kotlin/com/auth0/auth0_flutter_example/SmokeTest.kt @@ -0,0 +1,88 @@ +package com.auth0.auth0_flutter_example + +import android.app.UiAutomation +import android.content.Context +import android.content.Intent +import android.widget.Button +import android.widget.EditText +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until +import org.hamcrest.CoreMatchers.notNullValue +import org.hamcrest.MatcherAssert.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(AndroidJUnit4::class) +class SmokeTest { + + private val device: UiDevice + private val PACKAGE_NAME = "com.auth0.auth0_flutter_example" + private val CLASSIC_UL = true; + private val APP_TITLE = "Auth0 Example" + private val LOGIN_BUTTON = "Web Auth Login" + private val LOGOUT_BUTTON = "Web Auth Logout" + private val UL_BUTTON = if (CLASSIC_UL) "Log In" else "Continue" + private val TIMEOUT = 30000L + + init { + val instrumentation = InstrumentationRegistry.getInstrumentation() + device = UiDevice.getInstance(instrumentation) + } + + @Before + fun launchApp() { + device.pressHome() + + val launcherPackage: String = device.launcherPackageName + assertThat(launcherPackage, notNullValue()) + device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIMEOUT) + + // Launch the app + val context = ApplicationProvider.getApplicationContext() + val intent = context.packageManager.getLaunchIntentForPackage(PACKAGE_NAME)?.apply { + // Clear out any previous instances + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + } + context.startActivity(intent) + + // Wait for the app to appear + device.wait(Until.hasObject(By.pkg(PACKAGE_NAME).depth(0)), TIMEOUT) + device.wait(Until.hasObject(By.textContains(APP_TITLE)), TIMEOUT) + } + + @Test + fun loginAndLogout() { + // Start login + val loginButton = By.clazz(Button::class.qualifiedName).descContains(LOGIN_BUTTON) + device.wait(Until.hasObject(loginButton), TIMEOUT) + device.findObject(loginButton).click() + + // Fill login form + val ulButton = By.clazz(Button::class.qualifiedName).textContains(UL_BUTTON) + device.wait(Until.hasObject(ulButton), TIMEOUT) + val textInputs = By.clazz(EditText::class.qualifiedName) + device.wait(Until.hasObject(textInputs), TIMEOUT) + val emailInput = device.findObjects(textInputs).first() + emailInput.text = BuildConfig.USER_EMAIL + val passwordInput = device.findObjects(textInputs).last() + passwordInput.text = BuildConfig.USER_PASSWORD + device.pressEnter() + device.findObject(ulButton).click() + + // Logout + val logoutButton = By.clazz(Button::class.qualifiedName).descContains(LOGOUT_BUTTON) + device.wait(Until.hasObject(logoutButton), TIMEOUT) + device.findObject(logoutButton).click() + device.wait(Until.hasObject(loginButton), TIMEOUT) + + assertThat(device.findObject(loginButton), notNullValue()) + } + +} diff --git a/auth0_flutter/example/android/app/src/main/AndroidManifest.xml b/auth0_flutter/example/android/app/src/main/AndroidManifest.xml index 65e3c599..cce6c4b8 100644 --- a/auth0_flutter/example/android/app/src/main/AndroidManifest.xml +++ b/auth0_flutter/example/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + YOUR_AUTH0_DOMAIN - https + demo diff --git a/auth0_flutter/example/integration_test/capabilities/android.dart b/auth0_flutter/example/integration_test/capabilities/android.dart deleted file mode 100644 index 52856d5f..00000000 --- a/auth0_flutter/example/integration_test/capabilities/android.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'dart:io'; - -final Map androidCapabilities = { - 'platformName': 'Android', - 'app': File('build/app/outputs/flutter-apk/app-debug.apk').absolute.path, - 'deviceName': 'emulator-5554', - 'automationName': 'Flutter', -}; diff --git a/auth0_flutter/example/integration_test/capabilities/capabilities.dart b/auth0_flutter/example/integration_test/capabilities/capabilities.dart deleted file mode 100644 index 1299a39f..00000000 --- a/auth0_flutter/example/integration_test/capabilities/capabilities.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'android.dart'; -import 'ios.dart'; - -class Capabilities { - static Map android = androidCapabilities; - static Map ios = iosCapabilities; -} diff --git a/auth0_flutter/example/integration_test/capabilities/ios.dart b/auth0_flutter/example/integration_test/capabilities/ios.dart deleted file mode 100644 index 35af0cce..00000000 --- a/auth0_flutter/example/integration_test/capabilities/ios.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'dart:io'; - -final Map iosCapabilities = { - 'platformName': 'ios', - 'platformVersion': '15.4', - 'deviceName': 'iPhone 12 Pro', - 'automationName': 'Flutter', - 'reduceMotion': true, - 'app': File('build/ios/iphonesimulator/Runner.app').absolute.path, -}; diff --git a/auth0_flutter/example/integration_test/pages/auth0_page.dart b/auth0_flutter/example/integration_test/pages/auth0_page.dart deleted file mode 100644 index d505cc59..00000000 --- a/auth0_flutter/example/integration_test/pages/auth0_page.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:appium_driver/async_io.dart'; - -import '../utils/wait_for.dart'; - -class Auth0Page { - static const webViewClass = 'android.webkit.WebView'; - static const inputClass = 'android.widget.EditText'; - static const buttonClass = 'android.widget.Button'; - - AppiumWebDriver driver; - - Auth0Page({required this.driver}); - - Future enterCredentialsAndSubmit( - final String email, final String password) async { - await waitForBrowser(); - await waitForInputs(); - - final emailInput = await getEmailInput(); - final passwordInput = await getPasswordInput(); - - await emailInput.sendKeys(email); - await passwordInput.sendKeys(password); - - final loginButton = await getLoginButton(); - - await loginButton.click(); - } - - Future waitForBrowser() async { - await waitForElement( - driver, const AppiumBy.className(webViewClass)); - } - - Future waitForInputs() async { - await waitForElement(driver, const AppiumBy.className(inputClass)); - } - - Future getEmailInput() { - return driver - .findElements(const AppiumBy.className(inputClass)) - .elementAt(0); - } - - Future getPasswordInput() { - return driver - .findElements(const AppiumBy.className(inputClass)) - .elementAt(1); - } - - Future getLoginButton() { - return driver - .findElements(const AppiumBy.className(buttonClass)).last; - } -} diff --git a/auth0_flutter/example/integration_test/pages/example_page.dart b/auth0_flutter/example/integration_test/pages/example_page.dart deleted file mode 100644 index 81f4f46b..00000000 --- a/auth0_flutter/example/integration_test/pages/example_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:appium_driver/async_io.dart'; - -import '../utils/wait_for.dart'; - -class ExamplePage { - AppiumWebDriver driver; - - ExamplePage({required this.driver}); - - Future startLogin() async { - final element = await getLoginButton(); - await element.click(); - } - - Future startLogout() async { - final element = await getLogoutButton(); - await element.click(); - } - - Future getLoginButton() { - return waitForElement(driver, const AppiumBy.accessibilityId('Web Auth Login')); - } - - Future getLogoutButton() { - return waitForElement(driver, const AppiumBy.accessibilityId('Web Auth Logout')); - } -} diff --git a/auth0_flutter/example/integration_test/pages/system_page.dart b/auth0_flutter/example/integration_test/pages/system_page.dart deleted file mode 100644 index 5b43d4ee..00000000 --- a/auth0_flutter/example/integration_test/pages/system_page.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:appium_driver/async_io.dart'; - -class SystemPage { - AppiumWebDriver driver; - SystemPage({required this.driver}); - - Future useNativeContext() async { - await driver.contexts.setContext('NATIVE_APP'); - } -} diff --git a/auth0_flutter/example/integration_test/smoke_test.dart b/auth0_flutter/example/integration_test/smoke_test.dart deleted file mode 100644 index a1c8451b..00000000 --- a/auth0_flutter/example/integration_test/smoke_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:appium_driver/async_io.dart'; -import 'package:dotenv/dotenv.dart' as dart_dot_env; -import 'package:test/test.dart'; - -import 'capabilities/capabilities.dart'; -import 'pages/auth0_page.dart'; -import 'pages/example_page.dart'; -import 'pages/system_page.dart'; - -dart_dot_env.DotEnv env = dart_dot_env.DotEnv(includePlatformEnvironment: true) - ..load(); - -String email = env['USER_EMAIL'] ?? ''; -String password = env['USER_PASSWORD'] ?? ''; -String appiumUrl = env['APPIUM_URL'] ?? ''; - -void main() { - late AppiumWebDriver driver; - late SystemPage systemPage; - late ExamplePage examplePage; - late Auth0Page auth0Page; - - setUpAll(() async { - driver = await createDriver( - uri: Uri.parse(appiumUrl), desired: Capabilities.android); - examplePage = ExamplePage(driver: driver); - auth0Page = Auth0Page(driver: driver); - systemPage = SystemPage(driver: driver); - }); - - tearDownAll(() async { - await driver.quit(); - }); - - test('correctly handles the login and logout flow', () async { - // Ensure we are using the native context - await systemPage.useNativeContext(); - - // Start the login process by clicking the `Login` button, - // which will redirect to Auth0. - await examplePage.startLogin(); - - // Enter the user's credentials in Auth0 - await auth0Page.enterCredentialsAndSubmit(email, password); - - // Start the logout process by clicking the `Logout` button, - // which will redirect to Auth0 and redirect back. - await examplePage.startLogout(); - - final loginButton = await examplePage.getLoginButton(); - - expect(loginButton, isNotNull); - }); -} diff --git a/auth0_flutter/example/integration_test/utils/wait_for.dart b/auth0_flutter/example/integration_test/utils/wait_for.dart deleted file mode 100644 index bfbf8343..00000000 --- a/auth0_flutter/example/integration_test/utils/wait_for.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:appium_driver/async_io.dart'; - -Future waitForElement( - final AppiumWebDriver driver, final AppiumBy by, - {final int timeout = 5000}) async { - const delayDuration = Duration(milliseconds: 500); - final maxTries = timeout / delayDuration.inMilliseconds; - - var currentTry = 0; - - while (currentTry < maxTries) { - await Future.delayed(delayDuration); - currentTry++; // 2 - - try { - return await driver.findElement(by); - } on NoSuchElementException { - if (currentTry == maxTries) { - rethrow; - } - } - } - - throw Exception("Should't get here"); -} diff --git a/auth0_flutter/example/lib/main.dart b/auth0_flutter/example/lib/main.dart index ccbcd5fe..0471bff4 100644 --- a/auth0_flutter/example/lib/main.dart +++ b/auth0_flutter/example/lib/main.dart @@ -2,14 +2,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; -// ignore: depend_on_referenced_packages -import 'package:flutter_driver/driver_extension.dart'; import 'example_app.dart'; Future main() async { - enableFlutterDriverExtension(); - await dotenv.load(); runApp(const ExampleApp()); } diff --git a/auth0_flutter/example/pubspec.yaml b/auth0_flutter/example/pubspec.yaml index 4907c028..b38d6487 100644 --- a/auth0_flutter/example/pubspec.yaml +++ b/auth0_flutter/example/pubspec.yaml @@ -37,10 +37,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - appium_driver: ^0.5.2 dotenv: '^4.0.1' - flutter_driver: - sdk: flutter flutter_lints: ^2.0.1 flutter_test: sdk: flutter From d5adb076b303c6d28b21a4d0d353b9ffb533c324 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 21 Jul 2022 06:11:00 -0300 Subject: [PATCH 29/38] Fix most Android warnings (#136) Fix most innocuous warnings --- .../Auth0FlutterAuthMethodCallHandler.kt | 10 +++---- .../auth0/auth0_flutter/Auth0FlutterPlugin.kt | 2 +- .../Auth0FlutterWebAuthMethodCallHandler.kt | 4 +-- .../CredentialsManagerMethodCallHandler.kt | 29 +++++++++---------- .../auth0_flutter/UserProfileExtensions.kt | 3 +- .../request_handlers/MethodCallRequest.kt | 18 ++++++------ .../request_handlers/api/ApiRequestHandler.kt | 1 - .../api/LoginApiRequestHandler.kt | 12 ++++---- .../api/RenewApiRequestHandler.kt | 8 ++--- .../api/ResetPasswordApiRequestHandler.kt | 8 ++--- .../api/SignupApiRequestHandler.kt | 8 ++--- .../api/UserInfoApiRequestHandler.kt | 8 ++--- .../ClearCredentialsRequestHandler.kt | 6 ++-- .../GetCredentialsRequestHandler.kt | 14 ++++----- .../HasValidCredentialsRequestHandler.kt | 7 ++--- .../SaveCredentialsRequestHandler.kt | 20 ++++++------- .../web_auth/LoginWebAuthRequestHandler.kt | 4 +-- .../web_auth/LogoutWebAuthRequestHandler.kt | 10 +++---- .../utils/assertHasProperties.kt | 8 ++--- .../auth0_flutter/utils/getCustomClaims.kt | 2 +- 20 files changed, 88 insertions(+), 94 deletions(-) diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt index 1ed6e300..0e263a62 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt @@ -11,16 +11,16 @@ import io.flutter.plugin.common.MethodChannel.Result class Auth0FlutterAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { - lateinit var activity: Activity; + lateinit var activity: Activity override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - var requestHandler = requestHandlers.find { it.method == call.method }; + val requestHandler = requestHandlers.find { it.method == call.method } if (requestHandler != null) { - val request = MethodCallRequest.fromCall(call); - val api = AuthenticationAPIClient(request.account); + val request = MethodCallRequest.fromCall(call) + val api = AuthenticationAPIClient(request.account) - requestHandler.handle(api, request, result); + requestHandler.handle(api, request, result) } else { result.notImplemented() } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt index 8b50341f..14b000a6 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt @@ -66,7 +66,7 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { authCallHandler.activity = binding.activity credentialsManagerCallHandler.activity = binding.activity - binding.addActivityResultListener(credentialsManagerCallHandler); + binding.addActivityResultListener(credentialsManagerCallHandler) } override fun onDetachedFromActivityForConfigChanges() { diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt index fc8bb93a..db1bd095 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandler.kt @@ -12,10 +12,10 @@ class Auth0FlutterWebAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler, PluginRegistry.ActivityResultListener { - lateinit var activity: Activity; + lateinit var activity: Activity - var credentialsManager: SecureCredentialsManager? = null; + var credentialsManager: SecureCredentialsManager? = null override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - var requestHandler = requestHandlers.find { it.method == call.method }; + val requestHandler = requestHandlers.find { it.method == call.method } if (requestHandler != null) { - val request = MethodCallRequest.fromCall(call); + val request = MethodCallRequest.fromCall(call) - val api = AuthenticationAPIClient(request.account); - val storage = SharedPreferencesStorage(activity); - credentialsManager = credentialsManager ?: SecureCredentialsManager(activity, api, storage); + val api = AuthenticationAPIClient(request.account) + val storage = SharedPreferencesStorage(activity) + credentialsManager = credentialsManager ?: SecureCredentialsManager(activity, api, storage) - val credentialsManager = credentialsManager as SecureCredentialsManager; - - var localAuthentication = request.data.get("localAuthentication") as Map?; + val credentialsManager = credentialsManager as SecureCredentialsManager + val localAuthentication = request.data.get("localAuthentication") as Map? if (localAuthentication != null) { - val title = localAuthentication["title"]; - val description = localAuthentication["description"]; - credentialsManager.requireAuthentication(activity, RequestCodes.AUTH_REQ_CODE, title, description); + val title = localAuthentication["title"] + val description = localAuthentication["description"] + credentialsManager.requireAuthentication(activity, RequestCodes.AUTH_REQ_CODE, title, description) } - requestHandler.handle(credentialsManager, activity, request, result); + requestHandler.handle(credentialsManager, activity, request, result) } else { result.notImplemented() } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { - return credentialsManager?.checkAuthenticationResult(requestCode, resultCode) ?: true; + return credentialsManager?.checkAuthenticationResult(requestCode, resultCode) ?: true } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/UserProfileExtensions.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/UserProfileExtensions.kt index 23f10f8b..92e7b86d 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/UserProfileExtensions.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/UserProfileExtensions.kt @@ -3,7 +3,6 @@ package com.auth0.auth0_flutter import com.auth0.android.jwt.Claim import com.auth0.android.result.UserProfile import com.auth0.auth0_flutter.utils.getCustomClaims -import com.auth0.android.jwt.JWT fun UserProfile.toMap(): Map { return mapOf( @@ -51,7 +50,7 @@ fun createUserProfileFromClaims(claims: Map): UserProfile { appMetadata = mapOf(), userMetadata = mapOf(), createdAt = null - ); + ) } val UserProfile.sub: String diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/MethodCallRequest.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/MethodCallRequest.kt index bb9b568b..a038569b 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/MethodCallRequest.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/MethodCallRequest.kt @@ -6,18 +6,18 @@ import com.auth0.auth0_flutter.utils.assertHasProperties import io.flutter.plugin.common.MethodCall class MethodCallRequest { - var account: Auth0; - var data: HashMap<*, *>; + var account: Auth0 + var data: HashMap<*, *> constructor(account: Auth0, data: HashMap<*, *>) { - this.data = data; - this.account = account; + this.data = data + this.account = account } companion object { fun fromCall(call: MethodCall): MethodCallRequest { - val args = call.arguments as HashMap<*, *>; + val args = call.arguments as HashMap<*, *> assertHasProperties( listOf( @@ -28,21 +28,21 @@ class MethodCallRequest { "_userAgent.name", "_userAgent.version" ), args - ); + ) - val accountMap = args["_account"] as Map; + val accountMap = args["_account"] as Map val account = Auth0( accountMap["clientId"] as String, accountMap["domain"] as String ) - val userAgentMap = args["_userAgent"] as Map; + val userAgentMap = args["_userAgent"] as Map account.auth0UserAgent = Auth0UserAgent( name = userAgentMap["name"] as String, version = userAgentMap["version"] as String, ) - return MethodCallRequest(account, args); + return MethodCallRequest(account, args) } } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ApiRequestHandler.kt index fc666c1e..f61580eb 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ApiRequestHandler.kt @@ -8,4 +8,3 @@ interface ApiRequestHandler { val method: String fun handle(api: AuthenticationAPIClient, request: MethodCallRequest, result: MethodChannel.Result) } - diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt index e76c58c9..3617a994 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt @@ -1,6 +1,5 @@ package com.auth0.auth0_flutter.request_handlers.api -import com.auth0.android.Auth0 import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback @@ -13,7 +12,6 @@ import com.auth0.auth0_flutter.utils.assertHasProperties import io.flutter.plugin.common.MethodChannel import java.text.SimpleDateFormat import java.util.* -import kotlin.collections.HashMap private const val AUTH_LOGIN_METHOD = "auth#login" @@ -25,16 +23,16 @@ class LoginApiRequestHandler : ApiRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - val args = request.data; + val args = request.data - assertHasProperties(listOf("usernameOrEmail", "password", "connectionOrRealm"), args); + assertHasProperties(listOf("usernameOrEmail", "password", "connectionOrRealm"), args) val loginBuilder = api .login( args["usernameOrEmail"] as String, args["password"] as String, args["connectionOrRealm"] as String - ); + ) val scopes = args.getOrDefault("scopes", arrayListOf()) as ArrayList<*> loginBuilder.setScope(scopes.joinToString(separator = " ")) @@ -53,7 +51,7 @@ class LoginApiRequestHandler : ApiRequestHandler { exception.getCode(), exception.getDescription(), exception.toMap() - ); + ) } override fun onSuccess(credentials: Credentials) { @@ -76,6 +74,6 @@ class LoginApiRequestHandler : ApiRequestHandler { ) ) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt index 44bc3402..5ccdd2ee 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt @@ -23,9 +23,9 @@ class RenewApiRequestHandler : ApiRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - assertHasProperties(listOf("refreshToken"), request.data); + assertHasProperties(listOf("refreshToken"), request.data) - var renewAuthBuilder = api.renewAuth(request.data["refreshToken"] as String); + val renewAuthBuilder = api.renewAuth(request.data["refreshToken"] as String) val scopes = request.data.getOrDefault("scopes", arrayListOf()) as ArrayList<*> if (scopes.isNotEmpty()) { @@ -43,7 +43,7 @@ class RenewApiRequestHandler : ApiRequestHandler { exception.getCode(), exception.getDescription(), exception.toMap() - ); + ) } override fun onSuccess(credentials: Credentials) { @@ -67,6 +67,6 @@ class RenewApiRequestHandler : ApiRequestHandler { ) ) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandler.kt index a1457aab..afeb6ab5 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandler.kt @@ -19,7 +19,7 @@ class ResetPasswordApiRequestHandler : ApiRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - assertHasProperties(listOf("email", "connection"), request.data); + assertHasProperties(listOf("email", "connection"), request.data) val builder = api.resetPassword( email = request.data["email"] as String, @@ -36,12 +36,12 @@ class ResetPasswordApiRequestHandler : ApiRequestHandler { exception.getCode(), exception.getDescription(), exception.toMap() - ); + ) } override fun onSuccess(res: Void?) { - result.success(null); + result.success(null) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandler.kt index 80e08fa9..f010763a 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandler.kt @@ -15,7 +15,7 @@ class SignupApiRequestHandler : ApiRequestHandler { override val method: String = AUTH_SIGNUP_METHOD override fun handle(api: AuthenticationAPIClient, request: MethodCallRequest, result: MethodChannel.Result) { - assertHasProperties(listOf("email", "password", "connection"), request.data); + assertHasProperties(listOf("email", "password", "connection"), request.data) val builder = api.createUser( email = request.data["email"] as String, @@ -23,7 +23,7 @@ class SignupApiRequestHandler : ApiRequestHandler { username = request.data["username"] as String?, connection = request.data["connection"] as String, userMetadata = request.data["userMetadata"] as Map? - ); + ) if (request.data.getOrDefault("parameters", null) is HashMap<*, *>) { builder.addParameters(request.data["parameters"] as Map) @@ -35,7 +35,7 @@ class SignupApiRequestHandler : ApiRequestHandler { exception.getCode(), exception.getDescription(), exception.toMap() - ); + ) } override fun onSuccess(user: DatabaseUser) { @@ -47,6 +47,6 @@ class SignupApiRequestHandler : ApiRequestHandler { ) ) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandler.kt index ae4f3b5e..0df07cee 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandler.kt @@ -19,9 +19,9 @@ class UserInfoApiRequestHandler : ApiRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - assertHasProperties(listOf("accessToken"), request.data); + assertHasProperties(listOf("accessToken"), request.data) - val builder = api.userInfo(request.data["accessToken"] as String); + val builder = api.userInfo(request.data["accessToken"] as String) if (request.data.getOrDefault("parameters", null) is HashMap<*, *>) { builder.addParameters(request.data["parameters"] as Map) @@ -34,12 +34,12 @@ class UserInfoApiRequestHandler : ApiRequestHandler { exception.getCode(), exception.getDescription(), exception.toMap() - ); + ) } override fun onSuccess(res: UserProfile) { result.success(res.toMap()) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt index 1b7c97b5..2c69d7b3 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandler.kt @@ -6,7 +6,7 @@ import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel class ClearCredentialsRequestHandler : CredentialsManagerRequestHandler { - override val method: String = "credentialsManager#clearCredentials"; + override val method: String = "credentialsManager#clearCredentials" override fun handle( credentialsManager: SecureCredentialsManager, @@ -14,7 +14,7 @@ class ClearCredentialsRequestHandler : CredentialsManagerRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - credentialsManager.clearCredentials(); - result.success(true); + credentialsManager.clearCredentials() + result.success(true) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt index 5d75436d..e06412be 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt @@ -14,7 +14,7 @@ import java.text.SimpleDateFormat import java.util.* class GetCredentialsRequestHandler : CredentialsManagerRequestHandler { - override val method: String = "credentialsManager#getCredentials"; + override val method: String = "credentialsManager#getCredentials" override fun handle( credentialsManager: SecureCredentialsManager, @@ -22,20 +22,20 @@ class GetCredentialsRequestHandler : CredentialsManagerRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - var scope: String? = null; + var scope: String? = null val scopes = request.data.getOrDefault("scopes", arrayListOf()) as ArrayList<*> if (scopes.isNotEmpty()) { - scope = scopes.joinToString(separator = " "); + scope = scopes.joinToString(separator = " ") } - var minTtl = request.data.get("minTtl") as Int? ?: 0; - var parameters = request.data.get("parameters") as Map? ?: mapOf(); + val minTtl = request.data.get("minTtl") as Int? ?: 0 + val parameters = request.data.get("parameters") as Map? ?: mapOf() credentialsManager.getCredentials(scope, minTtl, parameters, object: Callback { override fun onFailure(exception: CredentialsManagerException) { - result.error(exception.message ?: "UNKNOWN ERROR", exception.message, exception); + result.error(exception.message ?: "UNKNOWN ERROR", exception.message, exception) } override fun onSuccess(credentials: Credentials) { @@ -59,6 +59,6 @@ class GetCredentialsRequestHandler : CredentialsManagerRequestHandler { ) ) } - }); + }) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt index 6c325b7f..2c2a928d 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandler.kt @@ -4,10 +4,9 @@ import android.content.Context import com.auth0.android.authentication.storage.SecureCredentialsManager import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel -import java.util.ArrayList class HasValidCredentialsRequestHandler : CredentialsManagerRequestHandler { - override val method: String = "credentialsManager#hasValidCredentials"; + override val method: String = "credentialsManager#hasValidCredentials" override fun handle( credentialsManager: SecureCredentialsManager, @@ -15,9 +14,9 @@ class HasValidCredentialsRequestHandler : CredentialsManagerRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - val minTtl = request.data.get("minTtl") as Int? ?: 0; + val minTtl = request.data.get("minTtl") as Int? ?: 0 - result.success(credentialsManager.hasValidCredentials(minTtl.toLong())); + result.success(credentialsManager.hasValidCredentials(minTtl.toLong())) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt index ffd3c57b..d0f69c1e 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt @@ -11,7 +11,7 @@ import java.util.* class SaveCredentialsRequestHandler : CredentialsManagerRequestHandler { - override val method: String = "credentialsManager#saveCredentials"; + override val method: String = "credentialsManager#saveCredentials" override fun handle( credentialsManager: SecureCredentialsManager, @@ -19,20 +19,20 @@ class SaveCredentialsRequestHandler : CredentialsManagerRequestHandler { request: MethodCallRequest, result: MethodChannel.Result ) { - assertHasProperties(listOf("credentials"), request.data); + assertHasProperties(listOf("credentials"), request.data) - val credentials = request.data.get("credentials") as HashMap<*, *>; + val credentials = request.data.get("credentials") as HashMap<*, *> - assertHasProperties(listOf("accessToken", "idToken" , "tokenType", "expiresAt"), credentials, "credentials"); + assertHasProperties(listOf("accessToken", "idToken" , "tokenType", "expiresAt"), credentials, "credentials") - var scope: String? = null; + var scope: String? = null val scopes = credentials.getOrDefault("scopes", arrayListOf()) as ArrayList<*> if (scopes.isNotEmpty()) { - scope = scopes.joinToString(separator = " "); + scope = scopes.joinToString(separator = " ") } - val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()); - var date = format.parse(credentials.get("expiresAt") as String); + val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) + val date = format.parse(credentials.get("expiresAt") as String) credentialsManager.saveCredentials(Credentials( credentials.get("idToken") as String, @@ -41,7 +41,7 @@ class SaveCredentialsRequestHandler : CredentialsManagerRequestHandler { credentials.get("refreshToken") as String?, date, scope, - )); - result.success(true); + )) + result.success(true) } } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt index a8f67300..3e7d6470 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt @@ -14,14 +14,14 @@ import java.text.SimpleDateFormat import java.util.* class LoginWebAuthRequestHandler(private val builderResolver: (MethodCallRequest) -> WebAuthProvider.Builder) : WebAuthRequestHandler { - override val method: String = "webAuth#login"; + override val method: String = "webAuth#login" override fun handle( context: Context, request: MethodCallRequest, result: MethodChannel.Result ) { - val builder = builderResolver(request); + val builder = builderResolver(request) val args = request.data val scopes = args.getOrDefault("scopes", arrayListOf()) as ArrayList<*> diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LogoutWebAuthRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LogoutWebAuthRequestHandler.kt index 5571b753..84f4f0b4 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LogoutWebAuthRequestHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LogoutWebAuthRequestHandler.kt @@ -8,11 +8,11 @@ import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel class LogoutWebAuthRequestHandler(private val builderResolver: (MethodCallRequest) -> WebAuthProvider.LogoutBuilder) : WebAuthRequestHandler { - override val method: String = "webAuth#logout"; + override val method: String = "webAuth#logout" override fun handle(context: Context, request: MethodCallRequest, result: MethodChannel.Result) { - val builder = builderResolver(request); - var args = request.data; + val builder = builderResolver(request) + val args = request.data if (args.getOrDefault("scheme", null) is String) { builder.withScheme(args["scheme"] as String) @@ -24,11 +24,11 @@ class LogoutWebAuthRequestHandler(private val builderResolver: (MethodCallReques builder.start(context, object: Callback { override fun onFailure(exception: AuthenticationException) { - result.error(exception.getCode(), exception.getDescription(), exception); + result.error(exception.getCode(), exception.getDescription(), exception) } override fun onSuccess(res: Void?) { - result.success(null); + result.success(null) } }) } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt index b76790ad..8d629c6e 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/assertHasProperties.kt @@ -2,18 +2,18 @@ package com.auth0.auth0_flutter.utils fun tryGetByKey(data: Any?, key: String): Any? { if (data is Map<*, *>) { - return data[key]; + return data[key] } - return null; + return null } fun assertHasProperties(requiredProperties: List, data: Map<*, *>, prefix: String? = null) { - var missingProperties = + val missingProperties = requiredProperties.filter { it.split('.') .fold(data) { acc: Any?, key: String -> tryGetByKey(acc, key) } == null - }; + } missingProperties .map { if (prefix != null) "$prefix.$it" else it } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/getCustomClaims.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/getCustomClaims.kt index dec0a90a..42f51b70 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/getCustomClaims.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/utils/getCustomClaims.kt @@ -42,5 +42,5 @@ fun getCustomClaims(claims: Map): Map { return filteredClaims.filterNot { standardClaims.contains(it.key) - }; + } } From a9434eb1a08dd4d7611e73ddae3f64e0a1d2dced Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 21 Jul 2022 06:13:18 -0300 Subject: [PATCH 30/38] Update SDK README and FAQ with latest API changes [SDK-3505] (#132) * Update README and FAQ with latest API changes * Fix indentation of code snippet * Use verb phrase for boolean var in snippet --- auth0_flutter/FAQ.md | 7 +++-- auth0_flutter/README.md | 69 ++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/auth0_flutter/FAQ.md b/auth0_flutter/FAQ.md index 5438bb1a..fd54f1c1 100644 --- a/auth0_flutter/FAQ.md +++ b/auth0_flutter/FAQ.md @@ -61,7 +61,8 @@ That alert box is displayed and managed by `ASWebAuthenticationSession`, not by If you don't need SSO, you can disable this behavior by adding `useEphemeralSession: true` to the login call. This will configure `ASWebAuthenticationSession` to not store the session cookie in the shared cookie jar, as if using an incognito browser window. With no shared cookie, `ASWebAuthenticationSession` will not prompt the user for consent. ```dart -final result = await auth0.webAuthentication +final credentials = await auth0 + .webAuthentication() .login(useEphemeralSession: true); // No SSO, therefore no alert box ``` @@ -78,7 +79,7 @@ You still need to call `logout()` on Android, though, as `useEphemeralSession` i If you need SSO and/or are willing to tolerate the alert box on the login call, but would prefer to get rid of it when calling `logout()`, you can simply not call `logout()` and just clear the credentials from the app. This means that the shared session cookie will not be removed, so to get the user to log in again you need to add the `'prompt': 'login'` parameter to the _login_ call. ```dart -final result = await auth0.webAuthentication.login( +final credentials = await auth0.webAuthentication().login( useEphemeralSession: true, parameters: { 'prompt': 'login' @@ -87,7 +88,7 @@ final result = await auth0.webAuthentication.login( Otherwise, the browser modal will close right away and the user will be automatically logged in again, as the cookie will still be there. -> โš ๏ธ Keeping the shared session cookie may not be an option if you have strong privacy and/or security requirements, e.g. for a banking app. +> โš ๏ธ Keeping the shared session cookie may not be an option if you have strong privacy and/or security requirements, for example in the case of a banking app. ## 4. Is there a way to disable the iOS _login_ alert box without `useEphemeralSession`? diff --git a/auth0_flutter/README.md b/auth0_flutter/README.md index 4b666cfe..2f8cbcbf 100644 --- a/auth0_flutter/README.md +++ b/auth0_flutter/README.md @@ -38,6 +38,7 @@ Auth0 SDK for Android / iOS Flutter apps. - Web Auth login and logout - Automatic storage and renewal of user's credentials +- Support for custom Credentials Manager implementations - Support for the following Authentication API operations: + Login with username or email and password + Signup @@ -232,8 +233,7 @@ final credentials = await auth0.webAuthentication().login(); auth0_flutter will automatically store the user's credentials using the built-in [Credentials Manager](#credentials-manager) instance. You can access this instance through the `credentialsManager` property. ```dart -final credentials = - await auth0.webAuthentication().credentialsManager?.credentials(); +final credentials = await auth0.credentialsManager.credentials(); ```
@@ -338,7 +338,6 @@ You can configure the ID token validation by passing an `IdTokenValidationConfig ```dart const config = IdTokenValidationConfig(leeway: 10); - final credentials = await auth0.webAuthentication().login(idTokenValidationConfig: config); ``` @@ -350,7 +349,6 @@ Users of Auth0 Private Cloud with custom domains still on the [legacy behavior]( ```dart const config = IdTokenValidationConfig(issuer: 'https://YOUR_AUTH0_DOMAIN/'); - final credentials = await auth0.webAuthentication().login(idTokenValidationConfig: config); ``` @@ -361,7 +359,7 @@ By default, `auth0_flutter` will automatically store the user's credentials afte ```dart final credentials = - await auth0.webAuthentication(useCredentialsManager: false).login(); + await auth0.webAuthentication(useCredentialsManager: false).login(); ``` #### Web Auth errors @@ -373,7 +371,7 @@ try { final credentials = await auth0.webAuthentication().login(); // ... } on WebAuthException catch (e) { - print(e.toString()); + print(e); } ``` @@ -383,6 +381,7 @@ try { - [Check for stored credentials](#check-for-stored-credentials) - [Retrieve stored credentials](#retrieve-stored-credentials) +- [Custom implementations](#custom-implementations) - [Local authentication](#local-authentication) - [Credentials Manager errors](#credentials-manager-errors) @@ -395,11 +394,7 @@ The Credentials Manager utility allows you to securely store and retrieve the us When the users open your app, check for valid credentials. If they exist, you can retrieve them and redirect the users to the app's main flow without any additional login steps. ```dart -final isLoggedIn = await auth0 - .webAuthentication() - .credentialsManager - ?.hasValidCredentials() ?? - false; +final isLoggedIn = await auth0.credentialsManager.hasValidCredentials(); if (isLoggedIn) { // Retrieve the credentials and redirect to the main flow @@ -413,38 +408,48 @@ if (isLoggedIn) { The credentials will be automatically renewed (if expired) using the [refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens). **This method is thread-safe.** ```dart -final credentials = - await auth0.webAuthentication().credentialsManager?.credentials(); +final credentials = await auth0.credentialsManager.credentials(); ``` -> ๐Ÿ’ก You do not need to call `credentialsManager?.storeCredentials()` afterward. The Credentials Manager automatically persists the renewed credentials. +> ๐Ÿ’ก You do not need to call `credentialsManager.storeCredentials()` afterward. The Credentials Manager automatically persists the renewed credentials. + +#### Custom implementations + +flutter_auth0 exposes a built-in, default Credentials Manager implementation through the `credentialsManager` property. You can pass your own implementation to the `Auth0` constructor. If you're using Web Auth, this implementation will be used to store the user's credentials after login and delete them after logout. + +```dart +final customCredentialsManager = CustomCredentialsManager(); +final auth0 = Auth0('YOUR_AUTH0_DOMAIN', 'YOUR_AUTH0_CLIENT_ID', + credentialsManager: customCredentialsManager); +// auth0.credentialsManager is now your CustomCredentialsManager instance +``` #### Local authentication You can enable an additional level of user authentication before retrieving credentials using the local authentication supported by the device, for example PIN or fingerprint on Android, and Face ID or Touch ID on iOS. ```dart -final localAuthentication = - LocalAuthenticationOptions(title: 'Please authenticate to continue'); - final credentials = await auth0 - .webAuthentication(localAuthentication: localAuthentication) - .credentialsManager - ?.credentials(); +const options = + LocalAuthenticationOptions(title: 'Please authenticate to continue'); +final auth0 = Auth0('YOUR_AUTH0_DOMAIN', 'YOUR_AUTH0_CLIENT_ID', + localAuthentication: options); +final credentials = await auth0.credentialsManager.credentials(); ``` Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/LocalAuthenticationOptions-class.html) to learn more about the available `LocalAuthenticationOptions` properties. +> โš ๏ธ Enabling local authentication will not work if you're using a custom Credentials Manager implementation. In that case, you will need to build support for local authentication into your custom implementation. + #### Credentials Manager errors The Credentials Manager will only throw `CredentialsManagerException` exceptions. You can find more information in the `details` property of the exception. Check the [API documentation](https://pub.dev/documentation/auth0_flutter_platform_interface/latest/auth0_flutter_platform_interface/CredentialsManagerException-class.html) to learn more about the available `CredentialsManagerException` properties. ```dart try { - final credentials = - await auth0.webAuthentication().credentialsManager?.credentials(); + final credentials = await auth0.credentialsManager.credentials(); // ... } on CredentialsManagerException catch (e) { - print(e.toString()); + print(e); } ``` @@ -474,6 +479,10 @@ final credentials = await auth0.api.login( usernameOrEmail: 'jane.smith@example.com', password: 'secret-password', connectionOrRealm: 'Username-Password-Authentication'); + +// Store the credentials afterward +final didStore = + await auth0.credentialsManager.storeCredentials(credentials); ```
@@ -507,7 +516,7 @@ final credentials = await auth0.api.login( #### Sign up with database connection ```dart -final credentials = await auth0.api.signup( +final databaseUser = await auth0.api.signup( email: 'jane.smith@example.com', password: 'secret-password', connection: 'Username-Password-Authentication', @@ -531,8 +540,12 @@ final userProfile = await auth0.api.userInfo(accessToken: accessToken); Use a [refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens) to renew the user's credentials. It's recommended that you read and understand the refresh token process beforehand. ```dart -final credentials = +final newCredentials = await auth0.api.renewCredentials(refreshToken: refreshToken); + +// Store the credentials afterward +final didStore = + await auth0.credentialsManager.storeCredentials(newCredentials); ``` > ๐Ÿ’ก To obtain a refresh token, make sure your Auth0 application has the **refresh token** [grant enabled](https://auth0.com/docs/get-started/applications/update-grant-types). If you are also specifying an audience value, make sure that the corresponding Auth0 API has the **Allow Offline Access** [setting enabled](https://auth0.com/docs/get-started/apis/api-settings#access-settings). @@ -549,7 +562,7 @@ try { connectionOrRealm: connection); // ... } on ApiException catch (e) { - print(e.toString()); + print(e); } ``` @@ -619,10 +632,10 @@ For general support or usage questions, use the [Auth0 Community](https://commun Auth0 helps you to: -- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML Identity Provider**. +- Add authentication with [multiple sources](https://auth0.com/docs/authenticate/identity-providers), either social identity providers such as **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce** (amongst others), or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS, or any SAML identity provider**. - Add authentication through more traditional **[username/password databases](https://auth0.com/docs/authenticate/database-connections/custom-db)**. - Add support for **[linking different user accounts](https://auth0.com/docs/manage-users/user-accounts/user-account-linking)** with the same user. -- Support for generating signed [JSON Web Tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. +- Support for generating signed [JSON web tokens](https://auth0.com/docs/secure/tokens/json-web-tokens) to call your APIs and **flow the user identity** securely. - Analytics of how, when, and where users are logging in. - Pull data from other sources and add it to the user profile through [JavaScript Actions](https://auth0.com/docs/customize/actions). From f6032da6da7bed9281cd814b168bdaefeb494aae Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 21 Jul 2022 08:49:53 -0300 Subject: [PATCH 31/38] Add missing Kotlin tests (#135) --- .../Auth0FlutterAuthMethodCallHandler.kt | 2 - .../auth0/auth0_flutter/Auth0FlutterPlugin.kt | 1 - .../CredentialsManagerMethodCallHandler.kt | 13 + .../Auth0FlutterAuthMethodCallHandlerTest.kt | 16 +- .../auth0_flutter/Auth0FlutterPluginTest.kt | 113 ++++++++ ...uth0FlutterWebAuthMethodCallHandlerTest.kt | 13 +- .../AuthenticationExceptionExtensionsTest.kt | 108 +++---- ...CredentialsManagerMethodCallHandlerTest.kt | 85 +++--- .../LoginWebAuthRequestHandlerTest.kt | 19 +- .../LogoutWebAuthRequestHandlerTest.kt | 14 +- .../UserProfileExtensionsTest.kt | 52 ++-- .../api/LoginApiRequestHandlerTest.kt | 271 +++++++++--------- .../api/RenewApiRequestHandlerTest.kt | 198 +++++++------ .../api/ResetPasswordApiRequestHandlerTest.kt | 162 +++++------ .../api/SignupApiRequestHandlerTest.kt | 180 ++++++------ .../api/UserInfoApiRequestHandlerTest.kt | 145 +++++----- .../ClearCredentialsRequestHandlerTest.kt | 39 +-- .../GetCredentialsRequestHandlerTest.kt | 248 ++++++++-------- .../HasValidCredentialsRequestHandlerTest.kt | 53 ++-- .../SaveCredentialsRequestHandlerTest.kt | 167 ++++++----- .../utils/assertHasPropertiesTest.kt | 29 +- .../utils/getCustomClaimsTest.kt | 27 +- 22 files changed, 1025 insertions(+), 930 deletions(-) create mode 100644 auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterPluginTest.kt diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt index 0e263a62..60981f67 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterAuthMethodCallHandler.kt @@ -11,8 +11,6 @@ import io.flutter.plugin.common.MethodChannel.Result class Auth0FlutterAuthMethodCallHandler(private val requestHandlers: List) : MethodCallHandler { - lateinit var activity: Activity - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { val requestHandler = requestHandlers.find { it.method == call.method } diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt index 14b000a6..eaa5d0a6 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt @@ -63,7 +63,6 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { override fun onAttachedToActivity(binding: ActivityPluginBinding) { webAuthCallHandler.activity = binding.activity - authCallHandler.activity = binding.activity credentialsManagerCallHandler.activity = binding.activity binding.addActivityResultListener(credentialsManagerCallHandler) diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt index fbb65da6..8af60e47 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandler.kt @@ -13,8 +13,15 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.PluginRegistry +import kotlin.annotation.AnnotationRetention +import kotlin.annotation.AnnotationTarget +import java.lang.annotation.ElementType +import java.lang.annotation.RetentionPolicy class CredentialsManagerMethodCallHandler(private val requestHandlers: List) : MethodCallHandler, PluginRegistry.ActivityResultListener { + // Coverage disabled because of an issue with Jacoco when using lateinit in kotlin. + // GitHub issue: https://github.com/jacoco/jacoco/issues/1182 + @Generated lateinit var activity: Activity var credentialsManager: SecureCredentialsManager? = null @@ -47,3 +54,9 @@ class CredentialsManagerMethodCallHandler(private val requestHandlers: List() - handler.activity = mock() - handler.onMethodCall(MethodCall(method, arguments), mockResult) onResult(mockResult) } @@ -48,9 +46,9 @@ class Auth0FlutterAuthMethodCallHandlerTest { @Test fun `handler should result in 'notImplemented' if no matching handler`() { - val signupHandler = mock(); + val signupHandler = mock() - `when`(signupHandler.method).thenReturn("auth#signup"); + `when`(signupHandler.method).thenReturn("auth#signup") runCallHandler("auth#login", requestHandlers = listOf(signupHandler)) { result -> verify(result).notImplemented() @@ -59,13 +57,13 @@ class Auth0FlutterAuthMethodCallHandlerTest { @Test fun `handler should only run the correct handler`() { - val loginHandler = mock(); - val signupHandler = mock(); + val loginHandler = mock() + val signupHandler = mock() - `when`(loginHandler.method).thenReturn("auth#login"); - `when`(signupHandler.method).thenReturn("auth#signup"); + `when`(loginHandler.method).thenReturn("auth#login") + `when`(signupHandler.method).thenReturn("auth#signup") - runCallHandler(loginHandler.method, requestHandlers = listOf(loginHandler, signupHandler)) { _ -> + runCallHandler(loginHandler.method, requestHandlers = listOf(loginHandler, signupHandler)) { verify(loginHandler).handle(any(), any(), any()) verify(signupHandler, times(0)).handle(any(), any(), any()) } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterPluginTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterPluginTest.kt new file mode 100644 index 00000000..cd8cf331 --- /dev/null +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterPluginTest.kt @@ -0,0 +1,113 @@ +package com.auth0.auth0_flutter + +import android.app.Activity +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.MethodChannel +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.* +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.mock +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class Auth0FlutterPluginTest { + @Test + fun `should set MethodCallHandler on onAttachedToEngine`() { + mockConstruction(MethodChannel::class.java).use { m -> + val plugin = Auth0FlutterPlugin() + + plugin.onAttachedToEngine(mock()) + + val constructed: List = m.constructed() + + fun assertMethodcallHandler(i: Int) { + verify(constructed[i]).setMethodCallHandler( + any() + ) + } + + assertMethodcallHandler(0) + assertMethodcallHandler(1) + assertMethodcallHandler(2) + + assert(constructed.size == 3) + } + } + + @Test + fun `should set MethodCallHandler to null on onDetachedFromEngine`() { + mockConstruction(MethodChannel::class.java).use { m -> + val plugin = Auth0FlutterPlugin() + + plugin.onAttachedToEngine(mock()) + + val constructed: List = m.constructed() + + plugin.onDetachedFromEngine(mock()) + + fun assertMethodcallHandler(i: Int) { + verify(constructed[i]).setMethodCallHandler( + isNull() + ) + } + + assertMethodcallHandler(0) + assertMethodcallHandler(1) + assertMethodcallHandler(2) + + assert(constructed.size == 3) + } + } + + @Test + fun `should set Activity on onAttachedToActivity`() { + mockConstruction(MethodChannel::class.java).use { m -> + val plugin = Auth0FlutterPlugin() + + plugin.onAttachedToEngine(mock()) + + val constructed: List = m.constructed() + + val mockBindings = mock() + val mockActivity = mock() + `when`(mockBindings.activity).thenReturn(mockActivity) + + plugin.onAttachedToActivity(mockBindings) + + fun getHandler(i: Int): TMethodCallHandler { + val captor = argumentCaptor() + + verify(constructed[i]).setMethodCallHandler(captor.capture()) + + @Suppress("UNCHECKED_CAST") + return captor.firstValue as TMethodCallHandler + } + + assert(getHandler(0).activity == mockActivity) + assert(getHandler(2).activity == mockActivity) + + assert(constructed.size == 3) + } + } + + @Test + fun `should call binding addActivityResultListener for CredentialsManager on onAttachedToActivity`() { + mockConstruction(MethodChannel::class.java).use { + val plugin = Auth0FlutterPlugin() + + plugin.onAttachedToEngine(mock()) + + val mockBindings = mock() + val mockActivity = mock() + + `when`(mockBindings.activity).thenReturn(mockActivity) + + plugin.onAttachedToActivity(mockBindings) + + verify(mockBindings).addActivityResultListener( + any() + ) + } + } +} diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt index 827878f4..56153dd1 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/Auth0FlutterWebAuthMethodCallHandlerTest.kt @@ -46,6 +46,17 @@ class Auth0FlutterWebAuthMethodCallHandlerTest { } } + @Test + fun `handler should result in 'notImplemented' if no matching handler`() { + val loginHandlerMock = mock() + + `when`(loginHandlerMock.method).thenReturn("webAuth#login") + + runCallHandler("webAuth#logout", handlers = listOf(loginHandlerMock)) { result -> + verify(result).notImplemented() + } + } + @Test fun `handler should only run the correct handler`() { val loginHandlerMock = mock() @@ -54,7 +65,7 @@ class Auth0FlutterWebAuthMethodCallHandlerTest { `when`(loginHandlerMock.method).thenReturn("webAuth#login") `when`(logoutHandlerMock.method).thenReturn("webAuth#logout") - runCallHandler(loginHandlerMock.method, handlers = listOf(loginHandlerMock, logoutHandlerMock)) { _ -> + runCallHandler(loginHandlerMock.method, handlers = listOf(loginHandlerMock, logoutHandlerMock)) { verify(loginHandlerMock).handle(any(), any(), any()) verify(logoutHandlerMock, times(0)).handle(any(), any(), any()) } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/AuthenticationExceptionExtensionsTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/AuthenticationExceptionExtensionsTest.kt index 21cfa412..1aad6740 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/AuthenticationExceptionExtensionsTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/AuthenticationExceptionExtensionsTest.kt @@ -15,29 +15,29 @@ class AuthenticationExceptionExtensionsTest { fun `should set errorFlags to false by default when calling toMap()`() { val exception = AuthenticationException(code = "Some Code", description = "Some Error") - val map = exception.toMap(); - val errorFlags = map["_errorFlags"] as Map; - - assertThat(errorFlags["isMultifactorRequired"], equalTo(false)); - assertThat(errorFlags["isMultifactorEnrollRequired"], equalTo(false)); - assertThat(errorFlags["isMultifactorCodeInvalid"], equalTo(false)); - assertThat(errorFlags["isMultifactorTokenInvalid"], equalTo(false)); - assertThat(errorFlags["isPasswordNotStrongEnough"], equalTo(false)); - assertThat(errorFlags["isPasswordAlreadyUsed"], equalTo(false)); - assertThat(errorFlags["isRuleError"], equalTo(false)); - assertThat(errorFlags["isInvalidCredentials"], equalTo(false)); - assertThat(errorFlags["isRefreshTokenDeleted"], equalTo(false)); - assertThat(errorFlags["isAccessDenied"], equalTo(false)); - assertThat(errorFlags["isTooManyAttempts"], equalTo(false)); - assertThat(errorFlags["isVerificationRequired"], equalTo(false)); - assertThat(errorFlags["isNetworkError"], equalTo(false)); - assertThat(errorFlags["isBrowserAppNotAvailable"], equalTo(false)); - assertThat(errorFlags["isPKCENotAvailable"], equalTo(false)); - assertThat(errorFlags["isInvalidAuthorizeURL"], equalTo(false)); - assertThat(errorFlags["isInvalidConfiguration"], equalTo(false)); - assertThat(errorFlags["isCanceled"], equalTo(false)); - assertThat(errorFlags["isPasswordLeaked"], equalTo(false)); - assertThat(errorFlags["isLoginRequired"], equalTo(false)); + val map = exception.toMap() + val errorFlags = map["_errorFlags"] as Map<*, *> + + assertThat(errorFlags["isMultifactorRequired"], equalTo(false)) + assertThat(errorFlags["isMultifactorEnrollRequired"], equalTo(false)) + assertThat(errorFlags["isMultifactorCodeInvalid"], equalTo(false)) + assertThat(errorFlags["isMultifactorTokenInvalid"], equalTo(false)) + assertThat(errorFlags["isPasswordNotStrongEnough"], equalTo(false)) + assertThat(errorFlags["isPasswordAlreadyUsed"], equalTo(false)) + assertThat(errorFlags["isRuleError"], equalTo(false)) + assertThat(errorFlags["isInvalidCredentials"], equalTo(false)) + assertThat(errorFlags["isRefreshTokenDeleted"], equalTo(false)) + assertThat(errorFlags["isAccessDenied"], equalTo(false)) + assertThat(errorFlags["isTooManyAttempts"], equalTo(false)) + assertThat(errorFlags["isVerificationRequired"], equalTo(false)) + assertThat(errorFlags["isNetworkError"], equalTo(false)) + assertThat(errorFlags["isBrowserAppNotAvailable"], equalTo(false)) + assertThat(errorFlags["isPKCENotAvailable"], equalTo(false)) + assertThat(errorFlags["isInvalidAuthorizeURL"], equalTo(false)) + assertThat(errorFlags["isInvalidConfiguration"], equalTo(false)) + assertThat(errorFlags["isCanceled"], equalTo(false)) + assertThat(errorFlags["isPasswordLeaked"], equalTo(false)) + assertThat(errorFlags["isLoginRequired"], equalTo(false)) } @Test @@ -46,52 +46,52 @@ class AuthenticationExceptionExtensionsTest { "isMultifactorRequired" to { exception: AuthenticationException -> `when`(exception.isMultifactorRequired).thenReturn( true - ); + ) }, "isMultifactorEnrollRequired" to { exception: AuthenticationException -> `when`(exception.isMultifactorEnrollRequired).thenReturn( true - ); + ) }, "isMultifactorCodeInvalid" to { exception: AuthenticationException -> `when`(exception.isMultifactorCodeInvalid).thenReturn( true - ); + ) }, "isMultifactorTokenInvalid" to { exception: AuthenticationException -> `when`(exception.isMultifactorTokenInvalid).thenReturn( true - ); + ) }, "isPasswordNotStrongEnough" to { exception: AuthenticationException -> `when`(exception.isPasswordNotStrongEnough).thenReturn( true - ); + ) }, "isPasswordAlreadyUsed" to { exception: AuthenticationException -> `when`(exception.isPasswordAlreadyUsed).thenReturn( true - ); + ) }, "isRuleError" to { exception: AuthenticationException -> `when`(exception.isRuleError).thenReturn( true - ); + ) }, "isInvalidCredentials" to { exception: AuthenticationException -> `when`(exception.isInvalidCredentials).thenReturn( true - ); + ) }, "isRefreshTokenDeleted" to { exception: AuthenticationException -> `when`(exception.isRefreshTokenDeleted).thenReturn( true - ); + ) }, "isAccessDenied" to { exception: AuthenticationException -> `when`(exception.isAccessDenied).thenReturn( true - ); + ) }, "isTooManyAttempts" to { exception: AuthenticationException -> doReturn("too_many_attempts").`when`(exception).getCode() @@ -99,47 +99,47 @@ class AuthenticationExceptionExtensionsTest { "isVerificationRequired" to { exception: AuthenticationException -> `when`(exception.isVerificationRequired).thenReturn( true - ); + ) }, "isNetworkError" to { exception: AuthenticationException -> `when`(exception.isNetworkError).thenReturn( true - ); + ) }, "isBrowserAppNotAvailable" to { exception: AuthenticationException -> `when`(exception.isBrowserAppNotAvailable).thenReturn( true - ); + ) }, "isPKCENotAvailable" to { exception: AuthenticationException -> `when`(exception.isPKCENotAvailable).thenReturn( true - ); + ) }, "isInvalidAuthorizeURL" to { exception: AuthenticationException -> `when`(exception.isInvalidAuthorizeURL).thenReturn( true - ); + ) }, "isInvalidConfiguration" to { exception: AuthenticationException -> `when`(exception.isInvalidConfiguration).thenReturn( true - ); + ) }, "isCanceled" to { exception: AuthenticationException -> `when`(exception.isCanceled).thenReturn( true - ); + ) }, "isPasswordLeaked" to { exception: AuthenticationException -> `when`(exception.isPasswordLeaked).thenReturn( true - ); + ) }, "isLoginRequired" to { exception: AuthenticationException -> `when`(exception.isLoginRequired).thenReturn( true - ); + ) } ) @@ -147,21 +147,21 @@ class AuthenticationExceptionExtensionsTest { val exception = spy(AuthenticationException(code = "Some Code", description = "Some Error")) - val setupProperty = testCase.value; - setupProperty(exception); + val setupProperty = testCase.value + setupProperty(exception) - val map = exception.toMap(); - val errorFlags = map["_errorFlags"] as Map; + val map = exception.toMap() + val errorFlags = map["_errorFlags"] as Map<*, *> assertThat( "should set '" + testCase.key + "' to true when calling toMap()", errorFlags[testCase.key], equalTo(true) - ); + ) - val allOtherErrorFlags = errorFlags.entries.filter { it.key !== testCase.key }; + val allOtherErrorFlags = errorFlags.entries.filter { it.key !== testCase.key } allOtherErrorFlags.forEach { - assertThat(it.value, equalTo(false)); + assertThat(it.value, equalTo(false)) } } } @@ -171,18 +171,18 @@ class AuthenticationExceptionExtensionsTest { val exception = AuthenticationException(code = "too_many_attempts", description = "Some Error") - assertThat(exception.isTooManyAttempts, equalTo(true)); + assertThat(exception.isTooManyAttempts, equalTo(true)) } @Test fun `should set statusCode when calling toMap()`() { val exception = AuthenticationException(mapOf( "code" to "Some Code", "description" to "Some Error" - ), 50); + ), 50) - val map = exception.toMap(); - val statusCode = map["_statusCode"] as Int; + val map = exception.toMap() + val statusCode = map["_statusCode"] as Int - assertThat(statusCode, equalTo(50)); + assertThat(statusCode, equalTo(50)) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt index 614eb09d..c06f8e08 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/CredentialsManagerMethodCallHandlerTest.kt @@ -1,16 +1,14 @@ package com.auth0.auth0_flutter import android.app.Activity -import android.content.Context import android.content.SharedPreferences -import com.auth0.auth0_flutter.request_handlers.api.ApiRequestHandler -import com.auth0.auth0_flutter.request_handlers.api.LoginApiRequestHandler -import com.auth0.auth0_flutter.request_handlers.api.SignupApiRequestHandler import com.auth0.auth0_flutter.request_handlers.credentials_manager.ClearCredentialsRequestHandler import com.auth0.auth0_flutter.request_handlers.credentials_manager.CredentialsManagerRequestHandler import com.auth0.auth0_flutter.request_handlers.credentials_manager.HasValidCredentialsRequestHandler import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel.Result +import org.hamcrest.CoreMatchers +import org.hamcrest.MatcherAssert import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.`when` @@ -40,7 +38,7 @@ class CredentialsManagerMethodCallHandlerTest { val handler = CredentialsManagerMethodCallHandler(requestHandlers) val mockResult = mock() - handler.activity = if (activity === null) mock() else activity; + handler.activity = if (activity === null) mock() else activity handler.onMethodCall(MethodCall(method, arguments), mockResult) onResult(mockResult) @@ -55,9 +53,9 @@ class CredentialsManagerMethodCallHandlerTest { @Test fun `handler should result in 'notImplemented' if no matching handler`() { - val clearCredentialsHandler = mock(); + val clearCredentialsHandler = mock() - `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials") runCallHandler("credentialsManager#saveCredentials", requestHandlers = listOf(clearCredentialsHandler)) { result -> verify(result).notImplemented() @@ -66,21 +64,21 @@ class CredentialsManagerMethodCallHandlerTest { @Test fun `handler should not call credentialsManager requireAuthentication`() { - val clearCredentialsHandler = mock(); + val clearCredentialsHandler = mock() - `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials") - val activity: Activity = mock(); + val activity: Activity = mock() val mockPrefs: SharedPreferences = mock() `when`(activity.getSharedPreferences(any(), any())) - .thenReturn(mockPrefs); + .thenReturn(mockPrefs) val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) val mockResult = mock() - handler.activity = activity; - handler.credentialsManager = mock(); + handler.activity = activity + handler.credentialsManager = mock() handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments), mockResult) @@ -89,21 +87,21 @@ class CredentialsManagerMethodCallHandlerTest { @Test fun `handler should call credentialsManager requireAuthentication`() { - val clearCredentialsHandler = mock(); + val clearCredentialsHandler = mock() - `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials") - val activity: Activity = mock(); + val activity: Activity = mock() val mockPrefs: SharedPreferences = mock() `when`(activity.getSharedPreferences(any(), any())) - .thenReturn(mockPrefs); + .thenReturn(mockPrefs) val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) val mockResult = mock() - handler.activity = activity; - handler.credentialsManager = mock(); + handler.activity = activity + handler.credentialsManager = mock() handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments + hashMapOf("localAuthentication" to hashMapOf("title" to "test", "description" to "test description"))), mockResult) @@ -112,21 +110,21 @@ class CredentialsManagerMethodCallHandlerTest { @Test fun `handler should call credentialsManager requireAuthentication with default values`() { - val clearCredentialsHandler = mock(); + val clearCredentialsHandler = mock() - `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials") - val activity: Activity = mock(); + val activity: Activity = mock() val mockPrefs: SharedPreferences = mock() `when`(activity.getSharedPreferences(any(), any())) - .thenReturn(mockPrefs); + .thenReturn(mockPrefs) val handler = CredentialsManagerMethodCallHandler(listOf(clearCredentialsHandler)) val mockResult = mock() - handler.activity = activity; - handler.credentialsManager = mock(); + handler.activity = activity + handler.credentialsManager = mock() handler.onMethodCall(MethodCall(clearCredentialsHandler.method, defaultArguments + hashMapOf("localAuthentication" to hashMapOf())), mockResult) @@ -135,21 +133,42 @@ class CredentialsManagerMethodCallHandlerTest { @Test fun `handler should only run the correct handler`() { - val clearCredentialsHandler = mock(); - val hasValidCredentialsHandler = mock(); + val clearCredentialsHandler = mock() + val hasValidCredentialsHandler = mock() - `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials"); - `when`(hasValidCredentialsHandler.method).thenReturn("credentialsManager#hasValidCredentials"); + `when`(clearCredentialsHandler.method).thenReturn("credentialsManager#clearCredentials") + `when`(hasValidCredentialsHandler.method).thenReturn("credentialsManager#hasValidCredentials") - val activity: Activity = mock(); - val mockPrefs: SharedPreferences = mock(); + val activity: Activity = mock() + val mockPrefs: SharedPreferences = mock() `when`(activity.getSharedPreferences(any(), any())) - .thenReturn(mockPrefs); + .thenReturn(mockPrefs) - runCallHandler(clearCredentialsHandler.method, activity = activity, requestHandlers = listOf(clearCredentialsHandler, hasValidCredentialsHandler)) { _ -> + runCallHandler(clearCredentialsHandler.method, activity = activity, requestHandlers = listOf(clearCredentialsHandler, hasValidCredentialsHandler)) { verify(clearCredentialsHandler).handle(any(), eq(activity), any(), any()) verify(hasValidCredentialsHandler, times(0)).handle(any(), eq(activity), any(), any()) } } + + @Test + fun `should call checkAuthenticationResult in onActivityResult`() { + val handler = CredentialsManagerMethodCallHandler(listOf()) + + handler.credentialsManager = mock() + handler.onActivityResult(1, 2, null) + + verify(handler.credentialsManager)?.checkAuthenticationResult(1, 2) + } + + @Test + fun `should return true in onActivityResult when no credentialsManager`() { + val handler = CredentialsManagerMethodCallHandler(listOf()) + val result = handler.onActivityResult(1, 2, null) + + MatcherAssert.assertThat( + result, + CoreMatchers.equalTo(true) + ) + } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt index 28d5cdf7..c75754f3 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LoginWebAuthRequestHandlerTest.kt @@ -1,14 +1,11 @@ package com.auth0.auth0_flutter import com.auth0.android.Auth0 -import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback import com.auth0.android.provider.WebAuthProvider -import com.auth0.android.request.AuthenticationRequest import com.auth0.android.result.Credentials import com.auth0.auth0_flutter.request_handlers.MethodCallRequest -import com.auth0.auth0_flutter.request_handlers.api.LoginApiRequestHandler import com.auth0.auth0_flutter.request_handlers.web_auth.LoginWebAuthRequestHandler import io.flutter.plugin.common.MethodChannel.Result import org.hamcrest.CoreMatchers.equalTo @@ -26,7 +23,7 @@ class LoginWebAuthRequestHandlerTest { private val defaultCredentials = Credentials(JwtTestUtils.createJwt(), "test", "", null, Date(), "openid profile email offline_access") - fun runRequestHandler( + private fun runRequestHandler( args: HashMap = hashMapOf(), credentials: Credentials = defaultCredentials, callback: (Result, WebAuthProvider.Builder) -> Unit @@ -284,8 +281,6 @@ class LoginWebAuthRequestHandlerTest { @Test fun `handler should not set the parameters on the SDK when not specified`() { - val parameters = hashMapOf("hello" to "world") - val args = hashMapOf() runRequestHandler(args) { _, builder -> @@ -338,11 +333,11 @@ class LoginWebAuthRequestHandlerTest { val formattedDate = sdf.format(credentials.expiresAt) - assertThat((captor.firstValue as Map)["accessToken"], equalTo(credentials.accessToken)) - assertThat((captor.firstValue as Map)["idToken"], equalTo(credentials.idToken)) - assertThat((captor.firstValue as Map)["refreshToken"], equalTo(credentials.refreshToken)) - assertThat((captor.firstValue as Map)["expiresAt"] as String, equalTo(formattedDate)) - assertThat((captor.firstValue as Map)["scopes"], equalTo(listOf("scope1", "scope2"))) - assertThat(((captor.firstValue as Map)["userProfile"] as Map)["name"], equalTo("John Doe")) + assertThat((captor.firstValue as Map<*, *>)["accessToken"], equalTo(credentials.accessToken)) + assertThat((captor.firstValue as Map<*, *>)["idToken"], equalTo(credentials.idToken)) + assertThat((captor.firstValue as Map<*, *>)["refreshToken"], equalTo(credentials.refreshToken)) + assertThat((captor.firstValue as Map<*, *>)["expiresAt"] as String, equalTo(formattedDate)) + assertThat((captor.firstValue as Map<*, *>)["scopes"], equalTo(listOf("scope1", "scope2"))) + assertThat(((captor.firstValue as Map<*, *>)["userProfile"] as Map<*, *>)["name"], equalTo("John Doe")) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LogoutWebAuthRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LogoutWebAuthRequestHandlerTest.kt index ffe33797..e7bad34a 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LogoutWebAuthRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/LogoutWebAuthRequestHandlerTest.kt @@ -1,31 +1,21 @@ package com.auth0.auth0_flutter import com.auth0.android.Auth0 -import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback import com.auth0.android.provider.WebAuthProvider -import com.auth0.android.request.AuthenticationRequest -import com.auth0.android.result.Credentials import com.auth0.auth0_flutter.request_handlers.MethodCallRequest -import com.auth0.auth0_flutter.request_handlers.api.LoginApiRequestHandler -import com.auth0.auth0_flutter.request_handlers.web_auth.LoginWebAuthRequestHandler import com.auth0.auth0_flutter.request_handlers.web_auth.LogoutWebAuthRequestHandler import io.flutter.plugin.common.MethodChannel.Result -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.nullValue -import org.hamcrest.MatcherAssert.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* import org.robolectric.RobolectricTestRunner -import java.text.SimpleDateFormat -import java.util.* import kotlin.collections.HashMap @RunWith(RobolectricTestRunner::class) class LogoutWebAuthRequestHandlerTest { - fun runHandler(args: HashMap = hashMapOf(), resultCallback: (Result, WebAuthProvider.LogoutBuilder) -> Unit) { + private fun runHandler(args: HashMap = hashMapOf(), resultCallback: (Result, WebAuthProvider.LogoutBuilder) -> Unit) { val mockBuilder = mock() val mockResult = mock() val handler = LogoutWebAuthRequestHandler { mockBuilder } @@ -86,7 +76,7 @@ class LogoutWebAuthRequestHandlerTest { @Test fun `should call logout with the correct parameters`() { runHandler { _, builder -> - verify(builder).start(any(), any()); + verify(builder).start(any(), any()) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/UserProfileExtensionsTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/UserProfileExtensionsTest.kt index fd6a75a5..f9e50ed0 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/UserProfileExtensionsTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/UserProfileExtensionsTest.kt @@ -31,17 +31,17 @@ class UserProfileExtensionsTest { null, "test-given_name" ) - val map = user.toMap(); + val map = user.toMap() - assertThat(map["name"], equalTo("test-name")); - assertThat(map["sub"], equalTo("test-sub")); - assertThat(map["middle_name"], equalTo("test-middle_name")); - assertThat(map["nickname"], equalTo("test-nickname")); - assertThat(map["picture"], equalTo("http://test-picture.com")); - assertThat(map["email"], equalTo("test-email")); - assertThat(map["email_verified"], equalTo(true)); - assertThat(map["family_name"], equalTo("test-family_name")); - assertThat(map["given_name"], equalTo("test-given_name")); + assertThat(map["name"], equalTo("test-name")) + assertThat(map["sub"], equalTo("test-sub")) + assertThat(map["middle_name"], equalTo("test-middle_name")) + assertThat(map["nickname"], equalTo("test-nickname")) + assertThat(map["picture"], equalTo("http://test-picture.com")) + assertThat(map["email"], equalTo("test-email")) + assertThat(map["email_verified"], equalTo(true)) + assertThat(map["family_name"], equalTo("test-family_name")) + assertThat(map["given_name"], equalTo("test-given_name")) } @Test @@ -61,9 +61,9 @@ class UserProfileExtensionsTest { null, null ) - val map = user.toMap(); + val map = user.toMap() - assertThat((map["custom_claims"] as Map)["test"], equalTo("test-claim")); + assertThat((map["custom_claims"] as Map<*, *>)["test"], equalTo("test-claim")) } @Test @@ -98,19 +98,19 @@ class UserProfileExtensionsTest { null ) - assertThat(user.sub, equalTo("test-sub")); - assertThat(user.middleName, equalTo("test-middle_name")); - assertThat(user.preferredUsername, equalTo("test-preferred_username")); - assertThat(user.profileURL, equalTo("https://test-profile.com")); - assertThat(user.websiteURL, equalTo("https://test-website.com")); - assertThat(user.gender, equalTo("test-gender")); - assertThat(user.birthdate, equalTo("test-birthdate")); - assertThat(user.zoneinfo, equalTo("test-zoneinfo")); - assertThat(user.locale, equalTo("test-locale")); - assertThat(user.phoneNumber, equalTo("test-phone_number")); - assertThat(user.isPhoneNumberVerified, equalTo(true)); - assertThat(user.updatedAt, equalTo("2022-04-22")); - assertThat(user.address?.get("street"), equalTo("test-street")); + assertThat(user.sub, equalTo("test-sub")) + assertThat(user.middleName, equalTo("test-middle_name")) + assertThat(user.preferredUsername, equalTo("test-preferred_username")) + assertThat(user.profileURL, equalTo("https://test-profile.com")) + assertThat(user.websiteURL, equalTo("https://test-website.com")) + assertThat(user.gender, equalTo("test-gender")) + assertThat(user.birthdate, equalTo("test-birthdate")) + assertThat(user.zoneinfo, equalTo("test-zoneinfo")) + assertThat(user.locale, equalTo("test-locale")) + assertThat(user.phoneNumber, equalTo("test-phone_number")) + assertThat(user.isPhoneNumberVerified, equalTo(true)) + assertThat(user.updatedAt, equalTo("2022-04-22")) + assertThat(user.address?.get("street"), equalTo("test-street")) } @Test @@ -118,6 +118,6 @@ class UserProfileExtensionsTest { val jwt = JWT(JwtTestUtils.createJwt(claims = mapOf("name" to "test-name"))) val user = createUserProfileFromClaims(jwt.claims) - assertThat(user.name, equalTo("test-name")); + assertThat(user.name, equalTo("test-name")) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt index 99a742f2..fc110038 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandlerTest.kt @@ -16,7 +16,6 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner import java.text.SimpleDateFormat import java.util.* @@ -26,72 +25,72 @@ class LoginApiRequestHandlerTest { @Test fun `should throw when missing usernameOrEmail`() { val options = - hashMapOf("password" to "test-password", "connectionOrRealm" to "test-connection"); - val handler = LoginApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + hashMapOf("password" to "test-password", "connectionOrRealm" to "test-connection") + val handler = LoginApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'usernameOrEmail' is not provided.") - ); + ) } @Test fun `should throw when missing password`() { val options = - hashMapOf("usernameOrEmail" to "test-email", "connectionOrRealm" to "test-connection"); - val handler = LoginApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + hashMapOf("usernameOrEmail" to "test-email", "connectionOrRealm" to "test-connection") + val handler = LoginApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'password' is not provided.") - ); + ) } @Test fun `should throw when missing connectionOrRealm`() { - val options = hashMapOf("usernameOrEmail" to "test-email", "password" to "test-pass"); - val handler = LoginApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val options = hashMapOf("usernameOrEmail" to "test-email", "password" to "test-pass") + val handler = LoginApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'connectionOrRealm' is not provided.") - ); + ) } @Test @@ -100,24 +99,24 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection" - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockApi).login("test-email", "test-pass", "test-connection"); - verify(mockLoginBuilder).start(any()); + verify(mockApi).login("test-email", "test-pass", "test-connection") + verify(mockLoginBuilder).start(any()) } @Test @@ -127,24 +126,24 @@ class LoginApiRequestHandlerTest { "password" to "test-pass", "connectionOrRealm" to "test-connection", "audience" to "test-audience" - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockLoginBuilder).setAudience("test-audience"); + verify(mockLoginBuilder).setAudience("test-audience") } @Test @@ -153,24 +152,24 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection", - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockLoginBuilder, times(0)).setAudience(any()); + verify(mockLoginBuilder, times(0)).setAudience(any()) } @Test @@ -180,24 +179,24 @@ class LoginApiRequestHandlerTest { "password" to "test-pass", "connectionOrRealm" to "test-connection", "scopes" to arrayListOf("scope1", "scope2") - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockLoginBuilder).setScope("scope1 scope2"); + verify(mockLoginBuilder).setScope("scope1 scope2") } @Test @@ -206,22 +205,22 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection", - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).setScope(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockLoginBuilder).setScope(""); } @@ -233,29 +232,29 @@ class LoginApiRequestHandlerTest { "password" to "test-pass", "connectionOrRealm" to "test-connection", "parameters" to mapOf("test" to "test-value", "test2" to "test-value") - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockLoginBuilder).addParameters( mapOf( "test" to "test-value", "test2" to "test-value" ) - ); + ) } @Test @@ -264,24 +263,24 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection", - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockLoginBuilder, times(0)).addParameters(any()); + verify(mockLoginBuilder, times(0)).addParameters(any()) } @Test @@ -290,30 +289,30 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection", - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = - AuthenticationException(code = "test-code", description = "test-description"); + AuthenticationException(code = "test-code", description = "test-description") - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onFailure(exception); - }.`when`(mockLoginBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onFailure(exception) + }.`when`(mockLoginBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockResult).error(eq("test-code"), eq("test-description"), any()); + verify(mockResult).error(eq("test-code"), eq("test-description"), any()) } @Test @@ -322,28 +321,28 @@ class LoginApiRequestHandlerTest { "usernameOrEmail" to "test-email", "password" to "test-pass", "connectionOrRealm" to "test-connection", - ); - val handler = LoginApiRequestHandler(); - val mockLoginBuilder = mock(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); - val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + ) + val handler = LoginApiRequestHandler() + val mockLoginBuilder = mock() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")) val credentials = Credentials(idToken, "test", "", null, Date(), "scope1 scope2") - doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()); - doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()); + doReturn(mockLoginBuilder).`when`(mockApi).login(any(), any(), any()) + doReturn(mockLoginBuilder).`when`(mockLoginBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onSuccess(credentials); - }.`when`(mockLoginBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onSuccess(credentials) + }.`when`(mockLoginBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) @@ -353,11 +352,11 @@ class LoginApiRequestHandlerTest { val formattedDate = sdf.format(credentials.expiresAt) - assertThat((captor.firstValue as Map)["accessToken"], equalTo(credentials.accessToken)) - assertThat((captor.firstValue as Map)["idToken"], equalTo(credentials.idToken)) - assertThat((captor.firstValue as Map)["refreshToken"], equalTo(credentials.refreshToken)) - assertThat((captor.firstValue as Map)["expiresAt"] as String, equalTo(formattedDate)) - assertThat((captor.firstValue as Map)["scopes"], equalTo(listOf("scope1", "scope2"))) - assertThat(((captor.firstValue as Map)["userProfile"] as Map)["name"], equalTo("John Doe")) + assertThat((captor.firstValue as Map<*, *>)["accessToken"], equalTo(credentials.accessToken)) + assertThat((captor.firstValue as Map<*, *>)["idToken"], equalTo(credentials.idToken)) + assertThat((captor.firstValue as Map<*, *>)["refreshToken"], equalTo(credentials.refreshToken)) + assertThat((captor.firstValue as Map<*, *>)["expiresAt"] as String, equalTo(formattedDate)) + assertThat((captor.firstValue as Map<*, *>)["scopes"], equalTo(listOf("scope1", "scope2"))) + assertThat(((captor.firstValue as Map<*, *>)["userProfile"] as Map<*, *>)["name"], equalTo("John Doe")) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandlerTest.kt index cd032b42..fee8a256 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandlerTest.kt @@ -4,7 +4,6 @@ import com.auth0.android.Auth0 import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback -import com.auth0.android.request.AuthenticationRequest import com.auth0.android.request.Request import com.auth0.android.result.Credentials import com.auth0.auth0_flutter.JwtTestUtils @@ -17,7 +16,6 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner import java.text.SimpleDateFormat import java.util.* @@ -26,49 +24,49 @@ import java.util.* class RenewApiRequestHandlerTest { @Test fun `should throw when missing refreshToken`() { - val options = hashMapOf(); - val handler = RenewApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val options = hashMapOf() + val handler = RenewApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'refreshToken' is not provided.") - ); + ) } @Test fun `should call renewAuth with the correct parameters`() { val options = hashMapOf( "refreshToken" to "test-token" - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockApi).renewAuth("test-token"); - verify(mockBuilder).start(any()); + verify(mockApi).renewAuth("test-token") + verify(mockBuilder).start(any()) } @Test @@ -76,48 +74,48 @@ class RenewApiRequestHandlerTest { val options = hashMapOf( "refreshToken" to "test-token", "scopes" to arrayListOf("scope1", "scope2") - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameter(any(), any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameter(any(), any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder).addParameter("scope", "scope1 scope2"); + verify(mockBuilder).addParameter("scope", "scope1 scope2") } @Test fun `should not configure the scopes when not provided`() { val options = hashMapOf( "refreshToken" to "test-token", - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameter(any(), any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameter(any(), any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder, times(0)).addParameter(any(), any()); + verify(mockBuilder, times(0)).addParameter(any(), any()) } @Test @@ -125,111 +123,111 @@ class RenewApiRequestHandlerTest { val options = hashMapOf( "refreshToken" to "test-token", "parameters" to mapOf("test" to "test-value", "test2" to "test-value") - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockBuilder).addParameters( mapOf( "test" to "test-value", "test2" to "test-value" ) - ); + ) } @Test fun `should not configure the parameters when not provided`() { val options = hashMapOf( "refreshToken" to "test-token", - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder, times(0)).addParameters(any()); + verify(mockBuilder, times(0)).addParameters(any()) } @Test fun `should call result error on failure`() { val options = hashMapOf( "refreshToken" to "test-token", - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = - AuthenticationException(code = "test-code", description = "test-description"); + AuthenticationException(code = "test-code", description = "test-description") - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onFailure(exception); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onFailure(exception) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockResult).error(eq("test-code"), eq("test-description"), any()); + verify(mockResult).error(eq("test-code"), eq("test-description"), any()) } @Test fun `should call result success on success`() { val options = hashMapOf( "refreshToken" to "test-token", - ); - val handler = RenewApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); - val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + ) + val handler = RenewApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")) val credentials = Credentials(idToken, "test", "", null, Date(), "scope1 scope2") - doReturn(mockBuilder).`when`(mockApi).renewAuth(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).renewAuth(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onSuccess(credentials); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onSuccess(credentials) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) @@ -240,24 +238,24 @@ class RenewApiRequestHandlerTest { val formattedDate = sdf.format(credentials.expiresAt) assertThat( - (captor.firstValue as Map)["accessToken"], + (captor.firstValue as Map<*, *>)["accessToken"], equalTo(credentials.accessToken) ) - assertThat((captor.firstValue as Map)["idToken"], equalTo(credentials.idToken)) + assertThat((captor.firstValue as Map<*, *>)["idToken"], equalTo(credentials.idToken)) assertThat( - (captor.firstValue as Map)["refreshToken"], + (captor.firstValue as Map<*, *>)["refreshToken"], equalTo(credentials.refreshToken) ) assertThat( - (captor.firstValue as Map)["expiresAt"] as String, + (captor.firstValue as Map<*, *>)["expiresAt"] as String, equalTo(formattedDate) ) assertThat( - (captor.firstValue as Map)["scopes"], + (captor.firstValue as Map<*, *>)["scopes"], equalTo(listOf("scope1", "scope2")) ) assertThat( - ((captor.firstValue as Map)["userProfile"] as Map)["name"], + ((captor.firstValue as Map<*, *>)["userProfile"] as Map<*, *>)["name"], equalTo("John Doe") ) } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandlerTest.kt index 1668463f..0b69f656 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/ResetPasswordApiRequestHandlerTest.kt @@ -4,10 +4,7 @@ import com.auth0.android.Auth0 import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback -import com.auth0.android.request.AuthenticationRequest import com.auth0.android.request.Request -import com.auth0.android.result.Credentials -import com.auth0.auth0_flutter.JwtTestUtils import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel.Result @@ -17,10 +14,7 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner -import java.text.SimpleDateFormat -import java.util.* @RunWith(RobolectricTestRunner::class) class ResetPasswordApiRequestHandlerTest { @@ -28,50 +22,50 @@ class ResetPasswordApiRequestHandlerTest { fun `should throw when missing email`() { val options = hashMapOf( "connection" to "test-connection" - ); - val handler = ResetPasswordApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'email' is not provided.") - ); + ) } @Test fun `should throw when missing connection`() { val options = hashMapOf( "email" to "test-email" - ); - val handler = ResetPasswordApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'connection' is not provided.") - ); + ) } @Test @@ -79,24 +73,24 @@ class ResetPasswordApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "connection" to "test-connection" - ); - val handler = ResetPasswordApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()); + doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockApi).resetPassword("test-email", "test-connection"); - verify(mockBuilder).start(any()); + verify(mockApi).resetPassword("test-email", "test-connection") + verify(mockBuilder).start(any()) } @Test @@ -105,29 +99,29 @@ class ResetPasswordApiRequestHandlerTest { "email" to "test-email", "connection" to "test-connection", "parameters" to mapOf("test" to "test-value", "test2" to "test-value") - ); - val handler = ResetPasswordApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockBuilder).addParameters( mapOf( "test" to "test-value", "test2" to "test-value" ) - ); + ) } @Test @@ -135,24 +129,24 @@ class ResetPasswordApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "connection" to "test-connection", - ); - val handler = ResetPasswordApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder, times(0)).addParameters(any()); + verify(mockBuilder, times(0)).addParameters(any()) } @Test @@ -160,30 +154,30 @@ class ResetPasswordApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "connection" to "test-connection", - ); - val handler = ResetPasswordApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = ResetPasswordApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = - AuthenticationException(code = "test-code", description = "test-description"); + AuthenticationException(code = "test-code", description = "test-description") - doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onFailure(exception); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onFailure(exception) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockResult).error(eq("test-code"), eq("test-description"), any()); + verify(mockResult).error(eq("test-code"), eq("test-description"), any()) } @Test @@ -191,26 +185,26 @@ class ResetPasswordApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "connection" to "test-connection", - ); - val handler = ResetPasswordApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); - - doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + ) + val handler = ResetPasswordApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) + + doReturn(mockBuilder).`when`(mockApi).resetPassword(any(), any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onSuccess(null); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onSuccess(null) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockResult).success(null) } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandlerTest.kt index ce4374fb..f142f338 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/SignupApiRequestHandlerTest.kt @@ -4,11 +4,8 @@ import com.auth0.android.Auth0 import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback -import com.auth0.android.request.AuthenticationRequest import com.auth0.android.request.Request -import com.auth0.android.result.Credentials import com.auth0.android.result.DatabaseUser -import com.auth0.auth0_flutter.JwtTestUtils import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel.Result @@ -18,10 +15,7 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner -import java.text.SimpleDateFormat -import java.util.* @RunWith(RobolectricTestRunner::class) class SignupApiRequestHandlerTest { @@ -30,25 +24,25 @@ class SignupApiRequestHandlerTest { val options = hashMapOf( "password" to "test-pass", "connection" to "test-connection" - ); - val handler = SignupApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'email' is not provided.") - ); + ) } @Test @@ -56,25 +50,25 @@ class SignupApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "connection" to "test-connection" - ); - val handler = SignupApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'password' is not provided.") - ); + ) } @Test @@ -82,25 +76,25 @@ class SignupApiRequestHandlerTest { val options = hashMapOf( "email" to "test-email", "password" to "test-pass" - ); - val handler = SignupApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'connection' is not provided.") - ); + ) } @Test @@ -109,25 +103,25 @@ class SignupApiRequestHandlerTest { "email" to "test-email", "password" to "test-pass", "connection" to "test-connection" - ); - val handler = SignupApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) doReturn(mockBuilder).`when`(mockApi) - .createUser(any(), any(), anyOrNull(), any(), anyOrNull()); + .createUser(any(), any(), anyOrNull(), any(), anyOrNull()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockApi).createUser("test-email", "test-pass", null, "test-connection", null); - verify(mockBuilder).start(any()); + verify(mockApi).createUser("test-email", "test-pass", null, "test-connection", null) + verify(mockBuilder).start(any()) } @Test @@ -137,29 +131,29 @@ class SignupApiRequestHandlerTest { "password" to "test-pass", "connection" to "test-connection", "parameters" to mapOf("test" to "test-value", "test2" to "test-value") - ); - val handler = SignupApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).createUser(any(), any(), anyOrNull(), any(), anyOrNull()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).createUser(any(), any(), anyOrNull(), any(), anyOrNull()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockBuilder).addParameters( mapOf( "test" to "test-value", "test2" to "test-value" ) - ); + ) } @Test @@ -169,24 +163,24 @@ class SignupApiRequestHandlerTest { "email" to "test-email", "password" to "test-pass", "connection" to "test-connection", - ); - val handler = SignupApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).createUser(any(), any(), anyOrNull(), any(), anyOrNull()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).createUser(any(), any(), anyOrNull(), any(), anyOrNull()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder, times(0)).addParameters(any()); + verify(mockBuilder, times(0)).addParameters(any()) } @Test @@ -195,30 +189,30 @@ class SignupApiRequestHandlerTest { "email" to "test-email", "password" to "test-pass", "connection" to "test-connection", - ); - val handler = SignupApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = SignupApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = - AuthenticationException(code = "test-code", description = "test-description"); + AuthenticationException(code = "test-code", description = "test-description") doReturn(mockBuilder).`when`(mockApi) - .createUser(any(), any(), anyOrNull(), any(), anyOrNull()); + .createUser(any(), any(), anyOrNull(), any(), anyOrNull()) doAnswer { - val ob = it.getArgument>(0); - ob.onFailure(exception); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onFailure(exception) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockResult).error(eq("test-code"), eq("test-description"), any()); + verify(mockResult).error(eq("test-code"), eq("test-description"), any()) } @Test @@ -227,37 +221,37 @@ class SignupApiRequestHandlerTest { "email" to "test-email", "password" to "test-pass", "connection" to "test-connection", - ); - val handler = SignupApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); - val user = DatabaseUser(options["email"] as String, null, false); + ) + val handler = SignupApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) + val user = DatabaseUser(options["email"] as String, null, false) doReturn(mockBuilder).`when`(mockApi) - .createUser(any(), any(), anyOrNull(), any(), anyOrNull()); + .createUser(any(), any(), anyOrNull(), any(), anyOrNull()) doAnswer { - val ob = it.getArgument>(0); - ob.onSuccess(user); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onSuccess(user) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) - assertThat((captor.firstValue as Map)["email"], equalTo(user.email)) + assertThat((captor.firstValue as Map<*, *>)["email"], equalTo(user.email)) assertThat( - (captor.firstValue as Map)["emailVerified"], + (captor.firstValue as Map<*, *>)["emailVerified"], equalTo(user.isEmailVerified) ) - assertThat((captor.firstValue as Map)["username"], equalTo(user.username)) + assertThat((captor.firstValue as Map<*, *>)["username"], equalTo(user.username)) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandlerTest.kt index 633d0ea1..7a8ba103 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/api/UserInfoApiRequestHandlerTest.kt @@ -4,12 +4,8 @@ import com.auth0.android.Auth0 import com.auth0.android.authentication.AuthenticationAPIClient import com.auth0.android.authentication.AuthenticationException import com.auth0.android.callback.Callback -import com.auth0.android.request.AuthenticationRequest import com.auth0.android.request.Request -import com.auth0.android.result.Credentials -import com.auth0.android.result.DatabaseUser import com.auth0.android.result.UserProfile -import com.auth0.auth0_flutter.JwtTestUtils import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import com.auth0.auth0_flutter.sub @@ -20,58 +16,55 @@ import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner -import java.text.SimpleDateFormat -import java.util.* @RunWith(RobolectricTestRunner::class) class UserInfoApiRequestHandlerTest { @Test fun `should throw when missing accessToken`() { - val options = hashMapOf(); - val handler = UserInfoApiRequestHandler(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val options = hashMapOf() + val handler = UserInfoApiRequestHandler() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( mockApi, request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'accessToken' is not provided.") - ); + ) } @Test fun `should call userInfo with the correct parameters`() { val options = hashMapOf( "accessToken" to "test-token", - ); - val handler = UserInfoApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = UserInfoApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).userInfo(any()); + doReturn(mockBuilder).`when`(mockApi).userInfo(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockApi).userInfo("test-token"); - verify(mockBuilder).start(any()); + verify(mockApi).userInfo("test-token") + verify(mockBuilder).start(any()) } @Test @@ -79,95 +72,95 @@ class UserInfoApiRequestHandlerTest { val options = hashMapOf( "accessToken" to "test-token", "parameters" to mapOf("test" to "test-value", "test2" to "test-value") - ); - val handler = UserInfoApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = UserInfoApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).userInfo(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).userInfo(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) verify(mockBuilder).addParameters( mapOf( "test" to "test-value", "test2" to "test-value" ) - ); + ) } @Test fun `should not configure the parameters when not provided`() { val options = hashMapOf( "accessToken" to "test-token", - ); - val handler = UserInfoApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = UserInfoApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) - doReturn(mockBuilder).`when`(mockApi).userInfo(any()); - doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()); + doReturn(mockBuilder).`when`(mockApi).userInfo(any()) + doReturn(mockBuilder).`when`(mockBuilder).addParameters(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockBuilder, times(0)).addParameters(any()); + verify(mockBuilder, times(0)).addParameters(any()) } @Test fun `should call result error on failure`() { val options = hashMapOf( "accessToken" to "test-token", - ); - val handler = UserInfoApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = UserInfoApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = - AuthenticationException(code = "test-code", description = "test-description"); + AuthenticationException(code = "test-code", description = "test-description") - doReturn(mockBuilder).`when`(mockApi).userInfo(any()); + doReturn(mockBuilder).`when`(mockApi).userInfo(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onFailure(exception); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onFailure(exception) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) - verify(mockResult).error(eq("test-code"), eq("test-description"), any()); + verify(mockResult).error(eq("test-code"), eq("test-description"), any()) } @Test fun `should call result success on success`() { val options = hashMapOf( "accessToken" to "test-token", - ); - val handler = UserInfoApiRequestHandler(); - val mockBuilder = mock>(); - val mockApi = mock(); - val mockAccount = mock(); - val mockResult = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val handler = UserInfoApiRequestHandler() + val mockBuilder = mock>() + val mockApi = mock() + val mockAccount = mock() + val mockResult = mock() + val request = MethodCallRequest(account = mockAccount, options) val user = UserProfile( "", "John Doe", @@ -184,23 +177,23 @@ class UserInfoApiRequestHandlerTest { null ) - doReturn(mockBuilder).`when`(mockApi).userInfo(any()); + doReturn(mockBuilder).`when`(mockApi).userInfo(any()) doAnswer { - val ob = it.getArgument>(0); - ob.onSuccess(user); - }.`when`(mockBuilder).start(any()); + val ob = it.getArgument>(0) + ob.onSuccess(user) + }.`when`(mockBuilder).start(any()) handler.handle( mockApi, request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) - assertThat((captor.firstValue as Map)["sub"], equalTo(user.sub)) - assertThat((captor.firstValue as Map)["name"], equalTo(user.name)) + assertThat((captor.firstValue as Map<*, *>)["sub"], equalTo(user.sub)) + assertThat((captor.firstValue as Map<*, *>)["name"], equalTo(user.name)) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt index 837fa65d..7a3cb996 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/ClearCredentialsRequestHandlerTest.kt @@ -1,66 +1,57 @@ package com.auth0.auth0_flutter.request_handlers.credentials_manager import com.auth0.android.Auth0 -import com.auth0.android.authentication.AuthenticationAPIClient -import com.auth0.android.authentication.AuthenticationException -import com.auth0.android.authentication.storage.SecureCredentialsManager; -import com.auth0.android.callback.Callback -import com.auth0.android.request.AuthenticationRequest -import com.auth0.android.result.Credentials -import com.auth0.auth0_flutter.JwtTestUtils +import com.auth0.android.authentication.storage.SecureCredentialsManager import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel.Result import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat -import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.* -import org.mockito.stubbing.Answer import org.robolectric.RobolectricTestRunner -import java.text.SimpleDateFormat -import java.util.* @RunWith(RobolectricTestRunner::class) class ClearCredentialsRequestHandlerTest { @Test fun `should call clearCredentials with the correct parameters`() { - val handler = ClearCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, mock()); + val handler = ClearCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, mock()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - verify(mockCredentialsManager).clearCredentials(); + verify(mockCredentialsManager).clearCredentials() } @Test fun `should call result success on success`() { - val handler = ClearCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, mock()); + val handler = ClearCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, mock()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) val captor = argumentCaptor() verify(mockResult).success(captor.capture()) assertThat(captor.firstValue, equalTo(true)) } + } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt index 16b03620..42fe901a 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt @@ -10,7 +10,6 @@ import com.auth0.auth0_flutter.request_handlers.MethodCallRequest import io.flutter.plugin.common.MethodChannel.Result import org.hamcrest.CoreMatchers import org.hamcrest.MatcherAssert -import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt @@ -26,293 +25,293 @@ class GetCredentialsRequestHandlerTest { @Test fun `should call getCredentials without providing options`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf() - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val handler = GetCredentialsRequestHandler() + val options = hashMapOf() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( isNull(), eq(0), anyMap(), any() - ); + ) } @Test fun `should use default value for minTtl and parameters when only providing scope`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( - "scopes" to arrayListOf("test-scope1", "test-scope2"), + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( + "scopes" to arrayListOf("test-scope1", "test-scope2"), ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( eq("test-scope1 test-scope2"), eq(0), anyMap(), any() - ); + ) } @Test fun `should use default value for parameters when only providing minTtl`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( "minTtl" to 30, ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( isNull(), eq(30), anyMap(), any() - ); + ) } @Test fun `should use default value for minTtl when only providing parameters`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( "parameters" to mapOf("test" to "test-value", "test2" to "test-value") ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( isNull(), eq(0), eq(mapOf("test" to "test-value", "test2" to "test-value")), any() - ); + ) } @Test fun `should use default value for parameters when providing scope and minTtl`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( "minTtl" to 30, - "scopes" to arrayListOf("test-scope1", "test-scope2"), + "scopes" to arrayListOf("test-scope1", "test-scope2"), ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( eq("test-scope1 test-scope2"), eq(30), anyMap(), any() - ); + ) } @Test fun `should use default value for minTtl when only providing scope and parameters`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( - "scopes" to arrayListOf("test-scope1", "test-scope2"), + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( + "scopes" to arrayListOf("test-scope1", "test-scope2"), "parameters" to mapOf("test" to "test-value", "test2" to "test-value") ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( eq("test-scope1 test-scope2"), eq(0), eq(mapOf("test" to "test-value", "test2" to "test-value")), any() - ); + ) } @Test fun `should call getCredentials when providing minTtl and parameters`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( "minTtl" to 30, "parameters" to mapOf("test" to "test-value", "test2" to "test-value") ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( isNull(), eq(30), eq(mapOf("test" to "test-value", "test2" to "test-value")), any() - ); + ) } @Test fun `should call getCredentials when providing all options`() { - val handler = GetCredentialsRequestHandler(); - var options = hashMapOf( + val handler = GetCredentialsRequestHandler() + val options = hashMapOf( "minTtl" to 30, - "scopes" to arrayListOf("test-scope1", "test-scope2"), + "scopes" to arrayListOf("test-scope1", "test-scope2"), "parameters" to mapOf("test" to "test-value", "test2" to "test-value") ) - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) verify(mockCredentialsManager).getCredentials( eq("test-scope1 test-scope2"), eq(30), eq(mapOf("test" to "test-value", "test2" to "test-value")), any() - ); + ) } @Test fun `should call result error on failure`() { - val options = hashMapOf(); - val handler = GetCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val options = hashMapOf() + val handler = GetCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) - val exception = mock(); + val exception = mock() `when`(exception.message).thenReturn("test-message") doAnswer { - val ob = it.getArgument>(3); - ob.onFailure(exception); - }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + val ob = it.getArgument>(3) + ob.onFailure(exception) + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - verify(mockResult).error(eq("test-message"), eq("test-message"), any()); + verify(mockResult).error(eq("test-message"), eq("test-message"), any()) } @Test fun `should fallback to UNKNOWN ERROR on failure without a message`() { - val options = hashMapOf(); - val handler = GetCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + val options = hashMapOf() + val handler = GetCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) - val exception = mock(); + val exception = mock() `when`(exception.message).thenReturn(null) doAnswer { - val ob = it.getArgument>(3); - ob.onFailure(exception); - }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + val ob = it.getArgument>(3) + ob.onFailure(exception) + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - verify(mockResult).error(eq("UNKNOWN ERROR"), isNull(), any()); + verify(mockResult).error(eq("UNKNOWN ERROR"), isNull(), any()) } @Test fun `should call result success on success`() { - val options = hashMapOf(); - val handler = GetCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); - val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + val options = hashMapOf() + val handler = GetCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")) val credentials = Credentials(idToken, "test", "", null, Date(), "scope1 scope2") doAnswer { - val ob = it.getArgument>(3); - ob.onSuccess(credentials); - }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + val ob = it.getArgument>(3) + ob.onSuccess(credentials) + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) @@ -323,61 +322,62 @@ class GetCredentialsRequestHandlerTest { val formattedDate = sdf.format(credentials.expiresAt) MatcherAssert.assertThat( - (captor.firstValue as Map)["accessToken"], + (captor.firstValue as Map<*, *>)["accessToken"], CoreMatchers.equalTo(credentials.accessToken) ) MatcherAssert.assertThat( - (captor.firstValue as Map)["idToken"], + (captor.firstValue as Map<*, *>)["idToken"], CoreMatchers.equalTo(credentials.idToken) ) MatcherAssert.assertThat( - (captor.firstValue as Map)["refreshToken"], + (captor.firstValue as Map<*, *>)["refreshToken"], CoreMatchers.equalTo(credentials.refreshToken) ) MatcherAssert.assertThat( - (captor.firstValue as Map)["expiresAt"] as String, + (captor.firstValue as Map<*, *>)["expiresAt"] as String, CoreMatchers.equalTo(formattedDate) ) MatcherAssert.assertThat( - (captor.firstValue as Map)["scopes"], + (captor.firstValue as Map<*, *>)["scopes"], CoreMatchers.equalTo(listOf("scope1", "scope2")) ) MatcherAssert.assertThat( - ((captor.firstValue as Map)["userProfile"] as Map)["name"], + ((captor.firstValue as Map<*, *>)["userProfile"] as Map<*, *>)["name"], CoreMatchers.equalTo("John Doe") ) } @Test fun `should call result success on success without scopes`() { - val options = hashMapOf(); - val handler = GetCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); - val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")); + val options = hashMapOf() + val handler = GetCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) + val idToken = JwtTestUtils.createJwt(claims = mapOf("name" to "John Doe")) val credentials = Credentials(idToken, "test", "", null, Date(), scope = null) doAnswer { - val ob = it.getArgument>(3); - ob.onSuccess(credentials); - }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()); + val ob = it.getArgument>(3) + ob.onSuccess(credentials) + }.`when`(mockCredentialsManager).getCredentials(isNull(), anyInt(), anyMap(), any()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - val captor = argumentCaptor<() -> Map>(); + val captor = argumentCaptor<() -> Map>() - verify(mockResult).success(captor.capture()); + verify(mockResult).success(captor.capture()) MatcherAssert.assertThat( - (captor.firstValue as Map)["scopes"], + (captor.firstValue as Map<*, *>)["scopes"], CoreMatchers.equalTo(listOf()) ) } + } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt index c7a5fc99..db7592a5 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/HasValidCredentialsRequestHandlerTest.kt @@ -16,70 +16,69 @@ class HasValidCredentialsRequestHandlerTest { @Test fun `should call hasValidCredentials with the correct parameters`() { - val handler = HasValidCredentialsRequestHandler(); - val minTtl = 30; + val handler = HasValidCredentialsRequestHandler() + val minTtl = 30 val options = hashMapOf( "minTtl" to minTtl, - ); - val mockResult = mock(); - val mockAccount = mock(); - val mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - verify(mockCredentialsManager).hasValidCredentials(minTtl.toLong()); + verify(mockCredentialsManager).hasValidCredentials(minTtl.toLong()) } @Test fun `should call hasValidCredentials with minTtl set to the default value`() { - val handler = HasValidCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - val mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, mock()); + val handler = HasValidCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, mock()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) - verify(mockCredentialsManager).hasValidCredentials(0); + verify(mockCredentialsManager).hasValidCredentials(0) } @Test fun `should call result success on success`() { - val handler = HasValidCredentialsRequestHandler(); - val minTtl = 30; + val handler = HasValidCredentialsRequestHandler() + val minTtl = 30 val options = hashMapOf( "minTtl" to minTtl, - ); - val mockResult = mock(); - val mockAccount = mock(); - val mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) - - doReturn(true).`when`(mockCredentialsManager).hasValidCredentials(any()); + doReturn(true).`when`(mockCredentialsManager).hasValidCredentials(any()) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); + ) val captor = argumentCaptor<() -> Map>() verify(mockResult).success(captor.capture()) assertThat(captor.firstValue, equalTo(true)) - } + } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt index e84a8a0c..e9a7ca80 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandlerTest.kt @@ -23,12 +23,12 @@ class SaveCredentialsRequestHandlerTest { @Test fun `should throw when missing credentials`() { val options = - hashMapOf(); - val handler = SaveCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + hashMapOf() + val handler = SaveCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( @@ -36,13 +36,13 @@ class SaveCredentialsRequestHandlerTest { mock(), request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'credentials' is not provided.") - ); + ) } @Test @@ -52,12 +52,12 @@ class SaveCredentialsRequestHandlerTest { "idToken" to "test-id-token", "tokenType" to "Bearer", "expiresAt" to "2022-01-01" - )); - val handler = SaveCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + )) + val handler = SaveCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( @@ -65,13 +65,13 @@ class SaveCredentialsRequestHandlerTest { mock(), request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'credentials.accessToken' is not provided.") - ); + ) } @Test @@ -81,12 +81,12 @@ class SaveCredentialsRequestHandlerTest { "accessToken" to "test-access-token", "tokenType" to "Bearer", "expiresAt" to "2022-01-01" - )); - val handler = SaveCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + )) + val handler = SaveCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( @@ -94,13 +94,13 @@ class SaveCredentialsRequestHandlerTest { mock(), request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'credentials.idToken' is not provided.") - ); + ) } @Test @@ -110,12 +110,12 @@ class SaveCredentialsRequestHandlerTest { "accessToken" to "test-access-token", "idToken" to "test-id-token", "expiresAt" to "2022-01-01" - )); - val handler = SaveCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + )) + val handler = SaveCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( @@ -123,13 +123,13 @@ class SaveCredentialsRequestHandlerTest { mock(), request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'credentials.tokenType' is not provided.") - ); + ) } @Test @@ -139,12 +139,12 @@ class SaveCredentialsRequestHandlerTest { "accessToken" to "test-access-token", "idToken" to "test-id-token", "tokenType" to "Bearer", - )); - val handler = SaveCredentialsRequestHandler(); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + )) + val handler = SaveCredentialsRequestHandler() + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) val exception = Assert.assertThrows(IllegalArgumentException::class.java) { handler.handle( @@ -152,111 +152,106 @@ class SaveCredentialsRequestHandlerTest { mock(), request, mockResult - ); + ) } assertThat( exception.message, equalTo("Required property 'credentials.expiresAt' is not provided.") - ); + ) } @Test fun `should call saveCredentials with the correct parameters`() { - val handler = SaveCredentialsRequestHandler(); - var credentialsMap = hashMapOf( + val handler = SaveCredentialsRequestHandler() + val credentialsMap = hashMapOf( "accessToken" to "test-access-token", "idToken" to "test-access-token", "tokenType" to "Bearer", "expiresAt" to "2022-01-01T00:00:00.000Z", "scopes" to arrayListOf("a", "b") - ); - val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); - var date = format.parse(credentialsMap.get("expiresAt") as String); - var scope: String? = null; + ) + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val date = format.parse(credentialsMap["expiresAt"] as String) as Date + var scope: String? = null val scopes = credentialsMap.getOrDefault("scopes", arrayListOf()) as ArrayList<*> if (scopes.isNotEmpty()) { - scope = scopes.joinToString(separator = " "); + scope = scopes.joinToString(separator = " ") } - - var credentials = Credentials( - credentialsMap.get("idToken") as String, - credentialsMap.get("accessToken") as String, - credentialsMap.get("tokenType") as String, - credentialsMap.get("refreshToken") as String?, + val credentials = Credentials( + credentialsMap["idToken"] as String, + credentialsMap["accessToken"] as String, + credentialsMap["tokenType"] as String, + credentialsMap["refreshToken"] as String?, date, scope, ) val options = hashMapOf( "credentials" to credentialsMap, - ); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); - + ) val captor = argumentCaptor() - verify(mockCredentialsManager).saveCredentials(captor.capture()); - - assertThat((captor.firstValue as Credentials).accessToken, equalTo(credentials.accessToken)) + verify(mockCredentialsManager).saveCredentials(captor.capture()) + assertThat((captor.firstValue).accessToken, equalTo(credentials.accessToken)) } @Test fun `should call saveCredentials with the correct parameters without scopes`() { - val handler = SaveCredentialsRequestHandler(); - var credentialsMap = hashMapOf( + val handler = SaveCredentialsRequestHandler() + val credentialsMap = hashMapOf( "accessToken" to "test-access-token", "idToken" to "test-access-token", "tokenType" to "Bearer", "expiresAt" to "2022-01-01T00:00:00.000Z" - ); - val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); - var date = format.parse(credentialsMap.get("expiresAt") as String); - var scope: String? = null; + ) + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val date = format.parse(credentialsMap["expiresAt"] as String) as Date + var scope: String? = null val scopes = credentialsMap.getOrDefault("scopes", arrayListOf()) as ArrayList<*> if (scopes.isNotEmpty()) { - scope = scopes.joinToString(separator = " "); + scope = scopes.joinToString(separator = " ") } - - var credentials = Credentials( - credentialsMap.get("idToken") as String, - credentialsMap.get("accessToken") as String, - credentialsMap.get("tokenType") as String, - credentialsMap.get("refreshToken"), + val credentials = Credentials( + credentialsMap["idToken"] as String, + credentialsMap["accessToken"] as String, + credentialsMap["tokenType"] as String, + credentialsMap["refreshToken"], date, scope, ) val options = hashMapOf( "credentials" to credentialsMap, - ); - val mockResult = mock(); - val mockAccount = mock(); - var mockCredentialsManager = mock(); - val request = MethodCallRequest(account = mockAccount, options); + ) + val mockResult = mock() + val mockAccount = mock() + val mockCredentialsManager = mock() + val request = MethodCallRequest(account = mockAccount, options) handler.handle( mockCredentialsManager, mock(), request, mockResult - ); - + ) val captor = argumentCaptor() - verify(mockCredentialsManager).saveCredentials(captor.capture()); - - assertThat((captor.firstValue as Credentials).accessToken, equalTo(credentials.accessToken)) + verify(mockCredentialsManager).saveCredentials(captor.capture()) + assertThat((captor.firstValue).accessToken, equalTo(credentials.accessToken)) } + } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/assertHasPropertiesTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/assertHasPropertiesTest.kt index 03317155..1f248b3c 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/assertHasPropertiesTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/assertHasPropertiesTest.kt @@ -5,66 +5,65 @@ import org.hamcrest.MatcherAssert.assertThat import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.* import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class AssertHasPropertiesTest { @Test fun `should not throw when all properties exactly equal`() { - assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test2" to "test2")); + assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test2" to "test2")) - assertThat(true, equalTo(true)); + assertThat(true, equalTo(true)) } @Test fun `should not throw when contains at least all properties`() { - assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test2" to "test2", "test3" to "test3")); + assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test2" to "test2", "test3" to "test3")) - assertThat(true, equalTo(true)); + assertThat(true, equalTo(true)) } @Test fun `should not throw when nested property found`() { - assertHasProperties(listOf("test", "test.prop"), mapOf("test" to mapOf("prop" to "value"))); + assertHasProperties(listOf("test", "test.prop"), mapOf("test" to mapOf("prop" to "value"))) - assertThat(true, equalTo(true)); + assertThat(true, equalTo(true)) } @Test fun `should throw when nested property not found`() { val exception = assertThrows(IllegalArgumentException::class.java) { - assertHasProperties(listOf("test", "test.prop"), mapOf("test2" to mapOf("prop" to "value"))); + assertHasProperties(listOf("test", "test.prop"), mapOf("test2" to mapOf("prop" to "value"))) } - assertThat(exception.message, equalTo("Required property 'test' is not provided.")); + assertThat(exception.message, equalTo("Required property 'test' is not provided.")) } @Test fun `should throw when nested sub property not found`() { val exception = assertThrows(IllegalArgumentException::class.java) { - assertHasProperties(listOf("test", "test.prop"), mapOf("test" to mapOf("prop2" to "value"))); + assertHasProperties(listOf("test", "test.prop"), mapOf("test" to mapOf("prop2" to "value"))) } - assertThat(exception.message, equalTo("Required property 'test.prop' is not provided.")); + assertThat(exception.message, equalTo("Required property 'test.prop' is not provided.")) } @Test fun `should throw when no properties found`() { val exception = assertThrows(IllegalArgumentException::class.java) { - assertHasProperties(listOf("test", "test2"), mapOf("test3" to "test3", "test4" to "test4")); + assertHasProperties(listOf("test", "test2"), mapOf("test3" to "test3", "test4" to "test4")) } - assertThat(exception.message, equalTo("Required property 'test' is not provided.")); + assertThat(exception.message, equalTo("Required property 'test' is not provided.")) } @Test fun `should throw when some properties not found`() { val exception = assertThrows(IllegalArgumentException::class.java) { - assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test3" to "test3")); + assertHasProperties(listOf("test", "test2"), mapOf("test" to "test", "test3" to "test3")) } - assertThat(exception.message, equalTo("Required property 'test2' is not provided.")); + assertThat(exception.message, equalTo("Required property 'test2' is not provided.")) } } diff --git a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/getCustomClaimsTest.kt b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/getCustomClaimsTest.kt index 3448cc2d..f5891fb7 100644 --- a/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/getCustomClaimsTest.kt +++ b/auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/utils/getCustomClaimsTest.kt @@ -4,20 +4,17 @@ import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.CoreMatchers.nullValue import org.hamcrest.CoreMatchers.not import org.hamcrest.MatcherAssert.assertThat -import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.* import org.robolectric.RobolectricTestRunner -import java.util.* @RunWith(RobolectricTestRunner::class) class GetCustomClaimsTest { @Test fun `should return an empty map when no claims`() { - val customClaims = getCustomClaims(mapOf()); + val customClaims = getCustomClaims(mapOf()) - assertThat(customClaims, equalTo(mapOf())); + assertThat(customClaims, equalTo(mapOf())) } @Test @@ -39,13 +36,13 @@ class GetCustomClaimsTest { val claims = claimsToFilter.associateWith { "test-value" } claimsToFilter.forEach { - assertThat(claims[it], not(nullValue())); + assertThat(claims[it], not(nullValue())) } - val customClaims = getCustomClaims(claims); + val customClaims = getCustomClaims(claims) claimsToFilter.forEach { - assertThat(customClaims[it], nullValue()); + assertThat(customClaims[it], nullValue()) } } @@ -77,21 +74,21 @@ class GetCustomClaimsTest { val claims = standardClaims.associateWith { "test-value" } standardClaims.forEach { - assertThat(claims[it], not(nullValue())); + assertThat(claims[it], not(nullValue())) } - val customClaims = getCustomClaims(claims); + val customClaims = getCustomClaims(claims) standardClaims.forEach { - assertThat(customClaims[it], nullValue()); + assertThat(customClaims[it], nullValue()) } } @Test fun `should return an empty map when no custom claims`() { - val customClaims = getCustomClaims(mapOf("name" to "test", "given_name" to "test2")); + val customClaims = getCustomClaims(mapOf("name" to "test", "given_name" to "test2")) - assertThat(customClaims, equalTo(mapOf())); + assertThat(customClaims, equalTo(mapOf())) } @Test @@ -103,8 +100,8 @@ class GetCustomClaimsTest { "aud" to "test-aud", "custom" to "custom value" ) - ); + ) - assertThat(customClaims, equalTo(mapOf("custom" to "custom value"))); + assertThat(customClaims, equalTo(mapOf("custom" to "custom value"))) } } From 428e519a24026ef545b7e03fed63bac51246ac97 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Thu, 21 Jul 2022 21:14:01 +0100 Subject: [PATCH 32/38] Correct path to auth0_flutter_platform_interface --- auth0_flutter/pubspec.lock | 6 +++--- auth0_flutter/pubspec.yaml | 4 +++- auth0_flutter_platform_interface/pubspec.lock | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/auth0_flutter/pubspec.lock b/auth0_flutter/pubspec.lock index 4c4c5c42..d075e86b 100644 --- a/auth0_flutter/pubspec.lock +++ b/auth0_flutter/pubspec.lock @@ -35,7 +35,7 @@ packages: path: "../auth0_flutter_platform_interface" relative: true source: path - version: "1.0.0-beta.0" + version: "1.0.0-beta.1" boolean_selector: dependency: transitive description: @@ -201,7 +201,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -283,7 +283,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" logging: dependency: transitive description: diff --git a/auth0_flutter/pubspec.yaml b/auth0_flutter/pubspec.yaml index d405eb0d..dea79f26 100644 --- a/auth0_flutter/pubspec.yaml +++ b/auth0_flutter/pubspec.yaml @@ -2,13 +2,15 @@ name: auth0_flutter description: Auth0 SDK for Flutter version: 1.0.0-beta.1 homepage: https://github.com/auth0/auth0-flutter +publish_to: none environment: sdk: ">=2.17.0 <3.0.0" flutter: ">=3.0.0" dependencies: - auth0_flutter_platform_interface: 1.0.0-beta.1 + auth0_flutter_platform_interface: + path: ../auth0_flutter_platform_interface flutter: sdk: flutter diff --git a/auth0_flutter_platform_interface/pubspec.lock b/auth0_flutter_platform_interface/pubspec.lock index d943ffc7..28179b7a 100644 --- a/auth0_flutter_platform_interface/pubspec.lock +++ b/auth0_flutter_platform_interface/pubspec.lock @@ -194,7 +194,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -262,7 +262,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" logging: dependency: transitive description: From 5a7cedc803f900e3ff5b31eeba306eb6a099d40e Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Thu, 21 Jul 2022 22:01:13 +0100 Subject: [PATCH 33/38] Release 1.0.0-fa.0 (auth0_flutter_platform_interface) --- auth0_flutter/pubspec.lock | 2 +- auth0_flutter_platform_interface/CHANGELOG.md | 6 ++++++ auth0_flutter_platform_interface/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/auth0_flutter/pubspec.lock b/auth0_flutter/pubspec.lock index d075e86b..3188e92e 100644 --- a/auth0_flutter/pubspec.lock +++ b/auth0_flutter/pubspec.lock @@ -35,7 +35,7 @@ packages: path: "../auth0_flutter_platform_interface" relative: true source: path - version: "1.0.0-beta.1" + version: "1.0.0-fa.0" boolean_selector: dependency: transitive description: diff --git a/auth0_flutter_platform_interface/CHANGELOG.md b/auth0_flutter_platform_interface/CHANGELOG.md index 5256b223..0937799d 100644 --- a/auth0_flutter_platform_interface/CHANGELOG.md +++ b/auth0_flutter_platform_interface/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [1.0.0-fa.0](https://github.com/auth0/auth0-flutter/tree/1.0.0-fa.0) (2022-07-21) + +This is a [First Availability](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#first-availability) release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ + +This release includes the addition of a Credentials Manager: a mechanism to manage the tokens returned from Auth0, including the ability to automatically renew the access token when expired (web authentication only). [Read more about the credentials manager](https://github.com/auth0/auth0-flutter/tree/main/auth0_flutter#credentials-manager) in the `auth0_flutter` package readme. + ## [1.0.0-beta.1](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.1) (2022-07-08) This is the first public beta release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ diff --git a/auth0_flutter_platform_interface/pubspec.yaml b/auth0_flutter_platform_interface/pubspec.yaml index 28f1f95b..d7b37ae3 100644 --- a/auth0_flutter_platform_interface/pubspec.yaml +++ b/auth0_flutter_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: auth0_flutter_platform_interface description: A common platform interface for the auth0_flutter plugin. -version: 1.0.0-beta.1 +version: 1.0.0-fa.0 homepage: https://github.com/auth0/auth0-flutter environment: From 32cd5c6917222be851d8b0cf3da6f287154f5b60 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 22 Jul 2022 08:02:33 -0300 Subject: [PATCH 34/38] Fix iOS coverage reporting (#139) --- .circleci/config.yml | 15 ++++++------- auth0_flutter/example/ios/.slather.yml | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 4 ++++ .../CredentialsManagerExtensionsTests.swift | 21 ++++++++++++++++++ .../example/ios/Tests/ExtensionsTests.swift | 22 +++++++++++-------- .../example/ios/Tests/Utilities.swift | 5 +++++ 6 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f404cb7..6c81d17a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ orbs: android: circleci/android@2 commands: prepare-config: - description: "Prepares the environment configuration files" + description: Prepares the environment configuration files steps: - run: name: Prepare Environment Configuration @@ -25,7 +25,7 @@ orbs: mv android/local.properties.ci android/local.properties working_directory: ./auth0_flutter/example run-smoke-tests: - description: "Runs the Android smoke tests" + description: Runs the Android smoke tests parameters: android_simulator: type: string @@ -97,7 +97,7 @@ jobs: executor: name: android/android-machine resource-class: medium - tag: 2021.10.1 + tag: 2022.06.1 steps: - checkout - flutter/install_sdk_and_pub: @@ -137,7 +137,7 @@ jobs: executor: name: android/android-machine resource-class: xlarge - tag: "2022.06.1" + tag: 2022.06.1 steps: - run: name: Guard Smoke Tests @@ -198,15 +198,14 @@ jobs: - run: name: Generate iOS test coverage report command: | - mkdir -p ~/test-results/cobertura + mkdir cobertura bundle exec slather working_directory: ./auth0_flutter/example/ios - - store_artifacts: - path: ~/test-results/cobertura - codecov/upload: - file: ~/test-results/cobertura/cobertura.xml + file: ./auth0_flutter/example/ios/cobertura/cobertura.xml upload_name: Auth0 Flutter iOS flags: auth0_flutter_ios + xtra_args: -s ./auth0_flutter/example/ios/cobertura workflows: build_and_test: jobs: diff --git a/auth0_flutter/example/ios/.slather.yml b/auth0_flutter/example/ios/.slather.yml index 13fc58bb..d2b2318b 100644 --- a/auth0_flutter/example/ios/.slather.yml +++ b/auth0_flutter/example/ios/.slather.yml @@ -4,4 +4,4 @@ scheme: Runner workspace: Runner.xcworkspace binary_basename: auth0_flutter arch: x86_64 -output_directory: ~/test-results/cobertura +output_directory: cobertura diff --git a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj index ad071b59..72bffc4b 100644 --- a/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/auth0_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3F1B396BCCAD9DA04D4998A2 /* Pods_Runner_RunnerUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52FDC1B88C21EFE2421C98FA /* Pods_Runner_RunnerUITests.framework */; }; + 5C08DBC8288A7646000D2F37 /* CredentialsManagerExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C08DBC7288A7646000D2F37 /* CredentialsManagerExtensionsTests.swift */; }; 5C328B4827F7822600451E70 /* WebAuthHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B4727F7822600451E70 /* WebAuthHandlerTests.swift */; }; 5C328B5027F7B0E700451E70 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B4F27F7B0E600451E70 /* Utilities.swift */; }; 5C328B5327F7B12F00451E70 /* WebAuthSpies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C328B5227F7B12F00451E70 /* WebAuthSpies.swift */; }; @@ -82,6 +83,7 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3DA3F79738DB2CDFBC131B5E /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 52FDC1B88C21EFE2421C98FA /* Pods_Runner_RunnerUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner_RunnerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C08DBC7288A7646000D2F37 /* CredentialsManagerExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsManagerExtensionsTests.swift; sourceTree = ""; }; 5C328B4527F7822600451E70 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5C328B4727F7822600451E70 /* WebAuthHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthHandlerTests.swift; sourceTree = ""; }; 5C328B4F27F7B0E600451E70 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; @@ -220,6 +222,7 @@ 5C4E65C4286D1CFB00141449 /* CredentialsManagerHasValidMethodHandlerTests.swift */, 5C4E65C8286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift */, 5C4E65BD286D151400141449 /* CredentialsManagerClearMethodHandlerTests.swift */, + 5C08DBC7288A7646000D2F37 /* CredentialsManagerExtensionsTests.swift */, ); path = CredentialsManager; sourceTree = ""; @@ -592,6 +595,7 @@ 5C4E65C9286D26D800141449 /* CredentialsManagerGetMethodHandlerTests.swift in Sources */, 5C328B5727F7BFEA00451E70 /* Mocks.swift in Sources */, 5C335E3D27FBBC2300EDDE3A /* WebAuthLogoutMethodHandlerTests.swift in Sources */, + 5C08DBC8288A7646000D2F37 /* CredentialsManagerExtensionsTests.swift in Sources */, 5C335E4127FBD2FE00EDDE3A /* ExtensionsTests.swift in Sources */, 5C59DA732807B1A300365CDB /* AuthAPIResetPasswordMethodHandlerTests.swift in Sources */, 5C59DA832809214200365CDB /* AuthAPIUserInfoMethodHandlerTests.swift in Sources */, diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift new file mode 100644 index 00000000..bf1274c9 --- /dev/null +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift @@ -0,0 +1,21 @@ +import XCTest +import Auth0 + +@testable import auth0_flutter + +class CredentialsManagerExtensionsTests: XCTestCase { + func testInitializesFlutterErrorFromCredentialsManagerError() { + let errors: [String: CredentialsManagerError] = [ + "NO_CREDENTIALS": .noCredentials, + "NO_REFRESH_TOKEN": .noRefreshToken, + "RENEW_FAILED": .renewFailed, + "BIOMETRICS_FAILED": .biometricsFailed, + "REVOKE_FAILED": .revokeFailed, + "LARGE_MIN_TTL": .largeMinTTL + ] + for (code, error) in errors { + let flutterError = FlutterError(from: error) + assert(flutterError: flutterError, is: error, with: code) + } + } +} diff --git a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift index 7ec88716..cdc7b6a3 100644 --- a/auth0_flutter/example/ios/Tests/ExtensionsTests.swift +++ b/auth0_flutter/example/ios/Tests/ExtensionsTests.swift @@ -91,16 +91,20 @@ extension ExtensionsTests { credentials.scope?.split(separator: " ").map(String.init)) } + func testFailsToMapCredentialsWithMissingRequiredProperties() throws { + let values: [String: Any] = [:] + XCTAssertNil(Credentials(from: values)) + } + func testFailsToMapCredentialsFromDictionaryWithInvalidExpiresAt() throws { let values: [String: Any] = [ CredentialsProperty.accessToken.rawValue: "", CredentialsProperty.idToken.rawValue: testIdToken, - CredentialsProperty.expiresAt.rawValue: Date().asISO8601String, + CredentialsProperty.expiresAt.rawValue: "foo", CredentialsProperty.scopes.rawValue: [], CredentialsProperty.tokenType.rawValue: "" ] - let credentials = try XCTUnwrap(Credentials(from: values)) - XCTAssertNil(credentials.scope) + XCTAssertNil(Credentials(from: values)) } } @@ -145,12 +149,6 @@ extension ExtensionsTests { values[CredentialsProperty.scopes] as? [String]) } - func testFailsToMapCredentialsWithMalformedIdTokenToDictionary() { - let idToken = "foo" - let credentials = Credentials(accessToken: "", tokenType: "", idToken: idToken, expiresIn: Date()) - XCTAssertThrowsError(try credentials.asDictionary(), HandlerError.idTokenDecodingFailed.message) - } - func testMapsUserProfileToDictionary() throws { let credentials = Credentials(accessToken: "", tokenType: "", idToken: testIdToken, expiresIn: Date()) let values = try credentials.asDictionary() @@ -158,6 +156,12 @@ extension ExtensionsTests { let userProfile = try XCTUnwrap(UserInfo(json: jwt.body)?.asDictionary()) XCTAssertTrue(userProfile == values[CredentialsProperty.userProfile] as? [String: Any]) } + + func testFailsToMapCredentialsWithMalformedIdTokenToDictionary() { + let idToken = "foo" + let credentials = Credentials(accessToken: "", tokenType: "", idToken: idToken, expiresIn: Date()) + XCTAssertThrowsError(try credentials.asDictionary(), HandlerError.idTokenDecodingFailed.message) + } } // MARK: - UserInfo+asDictionary diff --git a/auth0_flutter/example/ios/Tests/Utilities.swift b/auth0_flutter/example/ios/Tests/Utilities.swift index d5983e38..6ac5fb96 100644 --- a/auth0_flutter/example/ios/Tests/Utilities.swift +++ b/auth0_flutter/example/ios/Tests/Utilities.swift @@ -132,3 +132,8 @@ func assert(flutterError: FlutterError, is authenticationError: AuthenticationEr XCTAssertEqual(flags[AuthAPIErrorFlag.isLoginRequired], authenticationError.isLoginRequired) XCTAssertEqual(flags[AuthAPIErrorFlag.isNetworkError], authenticationError.isNetworkError) } + +func assert(flutterError: FlutterError, is credentialsManagerError: CredentialsManagerError, with code: String) { + XCTAssertEqual(flutterError.code, code) + XCTAssertEqual(flutterError.message, String(describing: credentialsManagerError)) +} From 7c9115a85e01ccdb42b0a0732ff0f3598b03ae1f Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Fri, 22 Jul 2022 11:15:53 -0300 Subject: [PATCH 35/38] Update to Auth0.swift 2.3.0 (#140) --- .../CredentialsManagerExtensionsTests.swift | 1 + ...dentialsManagerGetMethodHandlerTests.swift | 58 ++++++++++++++++--- ...alsManagerHasValidMethodHandlerTests.swift | 6 +- ...CredentialsManagerClearMethodHandler.swift | 2 +- .../CredentialsManagerExtensions.swift | 1 + .../CredentialsManagerGetMethodHandler.swift | 2 +- ...dentialsManagerHasValidMethodHandler.swift | 16 +---- .../CredentialsManagerSaveMethodHandler.swift | 2 +- auth0_flutter/ios/auth0_flutter.podspec | 2 +- 9 files changed, 60 insertions(+), 30 deletions(-) diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift index bf1274c9..c9fa1e60 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerExtensionsTests.swift @@ -9,6 +9,7 @@ class CredentialsManagerExtensionsTests: XCTestCase { "NO_CREDENTIALS": .noCredentials, "NO_REFRESH_TOKEN": .noRefreshToken, "RENEW_FAILED": .renewFailed, + "STORE_FAILED": .storeFailed, "BIOMETRICS_FAILED": .biometricsFailed, "REVOKE_FAILED": .revokeFailed, "LARGE_MIN_TTL": .largeMinTTL diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift index 158b7764..784307fb 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerGetMethodHandlerTests.swift @@ -6,12 +6,14 @@ import Auth0 fileprivate typealias Argument = CredentialsManagerGetMethodHandler.Argument class CredentialsManagerGetMethodHandlerTests: XCTestCase { - var spy: SpyCredentialsStorage! + var spyAuthentication: SpyAuthentication! + var spyStorage: SpyCredentialsStorage! var sut: CredentialsManagerGetMethodHandler! override func setUpWithError() throws { - spy = SpyCredentialsStorage() - let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + spyAuthentication = SpyAuthentication() + spyStorage = SpyCredentialsStorage() + let credentialsManager = CredentialsManager(authentication: spyAuthentication, storage: spyStorage) sut = CredentialsManagerGetMethodHandler(credentialsManager: credentialsManager) } } @@ -32,13 +34,55 @@ extension CredentialsManagerGetMethodHandlerTests { } } +// MARK: - Arguments + +extension CredentialsManagerGetMethodHandlerTests { + + // MARK: scopes + + func testAddsScopes() { + let value = ["foo", "bar"] + let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", + idToken: testIdToken, + refreshToken: "refreshToken", + expiresIn: Date(timeIntervalSinceNow: -3600), + scope: "foo bar") + let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) + let expectation = self.expectation(description: "Produced credentials") + spyStorage.getEntryReturnValue = data + sut.handle(with: arguments(withKey: Argument.scopes, value: value)) { _ in + XCTAssertEqual(self.spyAuthentication.arguments["scope"] as? String, value.asSpaceSeparatedString) + expectation.fulfill() + } + wait(for: [expectation]) + } + + func testAddsNilScopeWhenEmpty() { + let credentials = Credentials(accessToken: "accessToken", + tokenType: "tokenType", + idToken: testIdToken, + refreshToken: "refreshToken", + expiresIn: Date(timeIntervalSinceNow: -3600), + scope: "foo bar") + let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) + let expectation = self.expectation(description: "Produced credentials") + spyStorage.getEntryReturnValue = data + sut.handle(with: arguments(withKey: Argument.scopes, value: [])) { _ in + XCTAssertNil(self.spyAuthentication.arguments["scope"] as? String) + expectation.fulfill() + } + wait(for: [expectation]) + } +} + // MARK: - Get Result extension CredentialsManagerGetMethodHandlerTests { func testCallsSDKGetMethod() { let expectation = self.expectation(description: "Called get credentials method from the SDK") sut.handle(with: arguments()) { _ in - XCTAssertTrue(self.spy.calledGetEntry) + XCTAssertTrue(self.spyStorage.calledGetEntry) expectation.fulfill() } wait(for: [expectation]) @@ -51,9 +95,9 @@ extension CredentialsManagerGetMethodHandlerTests { refreshToken: "refreshToken", expiresIn: Date(timeIntervalSinceNow: 3600), scope: "foo bar") - let expectation = self.expectation(description: "Produced credentials") let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) - spy.getEntryReturnValue = data + let expectation = self.expectation(description: "Produced credentials") + spyStorage.getEntryReturnValue = data sut.handle(with: arguments()) { result in assert(result: result, has: CredentialsProperty.allCases) expectation.fulfill() @@ -64,7 +108,7 @@ extension CredentialsManagerGetMethodHandlerTests { func testProducesCredentialsManagerError() { let error = CredentialsManagerError.noCredentials let expectation = self.expectation(description: "Produced the CredentialsManagerError \(error)") - spy.getEntryReturnValue = nil + spyStorage.getEntryReturnValue = nil sut.handle(with: arguments()) { result in assert(result: result, isError: error) expectation.fulfill() diff --git a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift index 058ca343..e9b3c518 100644 --- a/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift +++ b/auth0_flutter/example/ios/Tests/CredentialsManager/CredentialsManagerHasValidMethodHandlerTests.swift @@ -54,10 +54,8 @@ extension CredentialsManagerHasValidMethodHandlerTests { let credentials = Credentials(refreshToken: "foo") let data = try? NSKeyedArchiver.archivedData(withRootObject: credentials, requiringSecureCoding: true) let expectation = self.expectation(description: "Produced true") - let emptyStorage = SpyCredentialsStorage() - emptyStorage.getEntryReturnValue = nil - let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: emptyStorage) - sut = CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager, credentialsStorage: spy) + let credentialsManager = CredentialsManager(authentication: SpyAuthentication(), storage: spy) + sut = CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager) spy.getEntryReturnValue = data sut.handle(with: arguments()) { result in XCTAssertEqual(result as? Bool, true) diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift index 832e429d..c2e40c0f 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerClearMethodHandler.swift @@ -5,6 +5,6 @@ struct CredentialsManagerClearMethodHandler: MethodHandler { let credentialsManager: CredentialsManager func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { - callback(credentialsManager.clear()) + callback(self.credentialsManager.clear()) } } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift index df3046d8..38db6f9e 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerExtensions.swift @@ -8,6 +8,7 @@ extension FlutterError { case .noCredentials: code = "NO_CREDENTIALS" case .noRefreshToken: code = "NO_REFRESH_TOKEN" case .renewFailed: code = "RENEW_FAILED" + case .storeFailed: code = "STORE_FAILED" case .biometricsFailed: code = "BIOMETRICS_FAILED" case .revokeFailed: code = "REVOKE_FAILED" case .largeMinTTL: code = "LARGE_MIN_TTL" diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift index 685a70d5..eceae886 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerGetMethodHandler.swift @@ -21,7 +21,7 @@ struct CredentialsManagerGetMethodHandler: MethodHandler { return callback(FlutterError(from: .requiredArgumentMissing(Argument.parameters.rawValue))) } - credentialsManager.credentials(withScope: scopes.isEmpty ? nil : scopes.asSpaceSeparatedString, + self.credentialsManager.credentials(withScope: scopes.isEmpty ? nil : scopes.asSpaceSeparatedString, minTTL: minTTL, parameters: parameters) { switch $0 { diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift index 251a5591..e3e9f896 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerHasValidMethodHandler.swift @@ -1,6 +1,5 @@ import Flutter import Auth0 -import SimpleKeychain struct CredentialsManagerHasValidMethodHandler: MethodHandler { enum Argument: String { @@ -8,13 +7,6 @@ struct CredentialsManagerHasValidMethodHandler: MethodHandler { } let credentialsManager: CredentialsManager - let credentialsStorage: CredentialsStorage - let credentialsKey = "credentials" - - init(credentialsManager: CredentialsManager, credentialsStorage: CredentialsStorage = A0SimpleKeychain()) { - self.credentialsManager = credentialsManager - self.credentialsStorage = credentialsStorage - } func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { guard let minTTL = arguments[Argument.minTtl] as? Int else { @@ -22,12 +14,6 @@ struct CredentialsManagerHasValidMethodHandler: MethodHandler { } // So it behaves the same as the Credentials Manager from Auth0.Android - if let data = self.credentialsStorage.getEntry(forKey: credentialsKey), - let credentials = try? NSKeyedUnarchiver.unarchivedObject(ofClass: Credentials.self, from: data), - credentials.refreshToken != nil { - return callback(true) - } - - callback(credentialsManager.hasValid(minTTL: minTTL)) + callback(self.credentialsManager.canRenew() || self.credentialsManager.hasValid(minTTL: minTTL)) } } diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift index ce04a589..902a9bc5 100644 --- a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerSaveMethodHandler.swift @@ -14,6 +14,6 @@ struct CredentialsManagerSaveMethodHandler: MethodHandler { return callback(FlutterError(from: .requiredArgumentMissing(Argument.credentials.rawValue))) } - callback(credentialsManager.store(credentials: credentials)) + callback(self.credentialsManager.store(credentials: credentials)) } } diff --git a/auth0_flutter/ios/auth0_flutter.podspec b/auth0_flutter/ios/auth0_flutter.podspec index 5e317412..f36828b9 100644 --- a/auth0_flutter/ios/auth0_flutter.podspec +++ b/auth0_flutter/ios/auth0_flutter.podspec @@ -15,7 +15,7 @@ A new flutter plugin project. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'Auth0', '~> 2.2' + s.dependency 'Auth0', '~> 2.3' s.platform = :ios, '12.0' # Flutter.framework does not contain a i386 slice. From 421764faf9a1305c569e1dd31571b7d2c43b1311 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Fri, 22 Jul 2022 16:06:03 +0100 Subject: [PATCH 36/38] Release 1.0.0-fa.0 (auth0_flutter) --- auth0_flutter/CHANGELOG.md | 6 ++++++ auth0_flutter/ios/auth0_flutter.podspec | 2 +- auth0_flutter/pubspec.lock | 6 +++--- auth0_flutter/pubspec.yaml | 6 ++---- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/auth0_flutter/CHANGELOG.md b/auth0_flutter/CHANGELOG.md index 5256b223..b7aa1652 100644 --- a/auth0_flutter/CHANGELOG.md +++ b/auth0_flutter/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [1.0.0-fa.0](https://github.com/auth0/auth0-flutter/tree/1.0.0-fa.0) (2022-07-22) + +This is a [First Availability](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#first-availability) release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ + +This release includes the addition of a Credentials Manager: a mechanism to manage the tokens returned from Auth0, including the ability to automatically renew the access token when expired (web authentication only). [Read more about the credentials manager](https://github.com/auth0/auth0-flutter/tree/main/auth0_flutter#credentials-manager) in the readme. + ## [1.0.0-beta.1](https://github.com/auth0/auth0-flutter/tree/1.0.0-beta.1) (2022-07-08) This is the first public beta release of the **Auth0 Flutter SDK**! ๐ŸŽ‰ diff --git a/auth0_flutter/ios/auth0_flutter.podspec b/auth0_flutter/ios/auth0_flutter.podspec index f36828b9..51714c84 100644 --- a/auth0_flutter/ios/auth0_flutter.podspec +++ b/auth0_flutter/ios/auth0_flutter.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'auth0_flutter' - s.version = ' 1.0.0-beta.0' + s.version = ' 1.0.0-fa.0' s.summary = 'A new flutter plugin project.' s.description = <<-DESC A new flutter plugin project. diff --git a/auth0_flutter/pubspec.lock b/auth0_flutter/pubspec.lock index 3188e92e..53f8b685 100644 --- a/auth0_flutter/pubspec.lock +++ b/auth0_flutter/pubspec.lock @@ -32,9 +32,9 @@ packages: auth0_flutter_platform_interface: dependency: "direct main" description: - path: "../auth0_flutter_platform_interface" - relative: true - source: path + name: auth0_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted version: "1.0.0-fa.0" boolean_selector: dependency: transitive diff --git a/auth0_flutter/pubspec.yaml b/auth0_flutter/pubspec.yaml index dea79f26..52e63c24 100644 --- a/auth0_flutter/pubspec.yaml +++ b/auth0_flutter/pubspec.yaml @@ -1,16 +1,14 @@ name: auth0_flutter description: Auth0 SDK for Flutter -version: 1.0.0-beta.1 +version: 1.0.0-fa.0 homepage: https://github.com/auth0/auth0-flutter -publish_to: none environment: sdk: ">=2.17.0 <3.0.0" flutter: ">=3.0.0" dependencies: - auth0_flutter_platform_interface: - path: ../auth0_flutter_platform_interface + auth0_flutter_platform_interface: 1.0.0-fa.0 flutter: sdk: flutter From eaec692ca2e76191b22c0416f02afd77bfddbb6a Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Fri, 22 Jul 2022 16:14:00 +0100 Subject: [PATCH 37/38] Update version.dart --- auth0_flutter/lib/src/version.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth0_flutter/lib/src/version.dart b/auth0_flutter/lib/src/version.dart index 2d6bd4e5..162ccb4e 100644 --- a/auth0_flutter/lib/src/version.dart +++ b/auth0_flutter/lib/src/version.dart @@ -1 +1 @@ -const String version = '1.0.0-beta.0'; +const String version = '1.0.0-fa.0'; From 6489a620640a9b6f723c4446a9bb268096c273e7 Mon Sep 17 00:00:00 2001 From: Steve Hobbs Date: Fri, 22 Jul 2022 16:28:10 +0100 Subject: [PATCH 38/38] Update README.md --- auth0_flutter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth0_flutter/README.md b/auth0_flutter/README.md index 8316d604..c964a232 100644 --- a/auth0_flutter/README.md +++ b/auth0_flutter/README.md @@ -1,4 +1,4 @@ -# Auth0 SDK for Flutter (Beta) +# Auth0 SDK for Flutter (First Availability) [![CircleCI](https://img.shields.io/circleci/project/github/auth0/auth0-flutter.svg)](https://circleci.com/gh/auth0/auth0-flutter/tree/main) [![Codecov](https://codecov.io/gh/auth0/auth0-flutter/branch/main/graph/badge.svg)](https://codecov.io/gh/auth0/auth0-flutter)