diff --git a/CHANGELOG.md b/CHANGELOG.md index 224ac4ad4..1d5a0246a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Possibility to login using LDAP +- Possibility to login using OAuth providers + ### Changed - Completely replaced HTMLSanitizeEx with FastSanitize [!490](https://framagit.org/framasoft/mobilizon/-/merge_requests/490) diff --git a/config/config.exs b/config/config.exs index 012953b09..e4e4aaad2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -118,6 +118,30 @@ config :guardian, Guardian.DB, config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase +config :mobilizon, + Mobilizon.Service.Auth.Authenticator, + Mobilizon.Service.Auth.MobilizonAuthenticator + +config :ueberauth, + Ueberauth, + providers: [] + +config :mobilizon, :auth, oauth_consumer_strategies: [] + +config :mobilizon, :ldap, + enabled: System.get_env("LDAP_ENABLED") == "true", + host: System.get_env("LDAP_HOST") || "localhost", + port: String.to_integer(System.get_env("LDAP_PORT") || "389"), + ssl: System.get_env("LDAP_SSL") == "true", + sslopts: [], + tls: System.get_env("LDAP_TLS") == "true", + tlsopts: [], + base: System.get_env("LDAP_BASE") || "dc=example,dc=com", + uid: System.get_env("LDAP_UID") || "cn", + require_bind_for_search: !(System.get_env("LDAP_REQUIRE_BIND_FOR_SEARCH") == "false"), + bind_uid: System.get_env("LDAP_BIND_UID"), + bind_password: System.get_env("LDAP_BIND_PASSWORD") + config :geolix, databases: [ %{ diff --git a/docs/administration/configure/auth.md b/docs/administration/configure/auth.md new file mode 100644 index 000000000..91ff5b91e --- /dev/null +++ b/docs/administration/configure/auth.md @@ -0,0 +1,113 @@ +# Authentification + +## LDAP + +Use LDAP for user authentication. When a user logs in to the Mobilizon instance, the email and password will be verified by trying to authenticate +(bind) to an LDAP server. If a user exists in the LDAP directory but there is no account with the same email yet on the Mobilizon instance then a new +Mobilizon account will be created (without needing email confirmation) with the same email as the LDAP email name. + +!!! tip + As Mobilizon uses email for login and LDAP bind is often done with account UID/CN, we need to start by searching for LDAP account matching with this email. LDAP search without bind is often disallowed, so you'll probably need an admin LDAP user. + + +Change authentification method: +```elixir +config :mobilizon, + Mobilizon.Service.Auth.Authenticator, + Mobilizon.Service.Auth.LDAPAuthenticator +``` + +LDAP configuration under `:mobilizon, :ldap`: + +* `enabled`: enables LDAP authentication +* `host`: LDAP server hostname +* `port`: LDAP port, e.g. 389 or 636 +* `ssl`: true to use SSL, usually implies the port 636 +* `sslopts`: additional SSL options +* `tls`: true to start TLS, usually implies the port 389 +* `tlsopts`: additional TLS options +* `base`: LDAP base, e.g. "dc=example,dc=com" +* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base" +* `require_bind_for_search` whether admin bind is required to perform search +* `bind_uid` the admin uid/cn for binding before searching +* `bind_password` the admin password for binding before searching + +Example: + +```elixir +config :mobilizon, :ldap, + enabled: true, + host: "localhost", + port: 636, + ssl: true, + sslopts: [], + tls: true, + tlsopts: [], + base: "ou=users,dc=example,dc=local", + uid: "cn", + require_bind_for_search: true, + bind_uid: "admin_account", + bind_password: "some_admin_password" +``` + +## OAuth + +Mobilizon currently supports the following providers: + +* [Discord](https://github.com/schwarz/ueberauth_discord) +* [Facebook](https://github.com/ueberauth/ueberauth_facebook) +* [Github](https://github.com/ueberauth/ueberauth_github) +* [Gitlab](https://github.com/mtchavez/ueberauth_gitlab) (including self-hosted) +* [Google](https://github.com/ueberauth/ueberauth_google) +* [Keycloak](https://github.com/Rukenshia/ueberauth_keycloak) (through OpenID Connect) +* [Twitter](https://github.com/Rukenshia/ueberauth_keycloak) + +Support for [other providers](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies) can easily be added if requested. + +!!! tip + We advise to look at each provider's README file for eventual specific instructions. + +You'll have to start by registering an app at the provider. Be sure to activate features like "Sign-in with" and "emails" scope, as Mobilizon needs users emails to register them. + +Add the configured providers to configuration (you may find the appropriate scopes on the provider's API documentation): +```elixir +config :ueberauth, + Ueberauth, + providers: [ + gitlab: {Ueberauth.Strategy.Gitlab, [default_scope: "read_user"]}, + keycloak: {Ueberauth.Strategy.Keycloak, [default_scope: "email"]} + # ... + ] +``` + +In order for the « Sign-in with » buttons to be added on Register and Login pages, list your providers: +```elixir +config :mobilizon, :auth, + oauth_consumer_strategies: [ + :gitlab, + {:keycloak, "My corporate account"} + # ... + ] +``` + +!!! note + If you use the `{:provider_id, "Some label"}` form, the label will be used inside the buttons on Register and Login pages. + +Finally add the configuration for each specific provider. The Client ID and Client Secret are at least required: +```elixir +config :ueberauth, Ueberauth.Strategy.Facebook.OAuth, + client_id: "some_numeric_id", + client_secret: "some_secret" + +keycloak_url = "https://some-keycloak-instance.org" + +# Realm may be something else than master +config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, + client_id: "some_id", + client_secret: "some_hexadecimal_secret", + site: keycloak_url, + authorize_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/auth", + token_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/token", + userinfo_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/userinfo", + token_method: :post +``` \ No newline at end of file diff --git a/js/package.json b/js/package.json index e4679b4fa..43d57fa04 100644 --- a/js/package.json +++ b/js/package.json @@ -90,7 +90,7 @@ "prettier-eslint": "^10.1.1", "sass-loader": "^8.0.2", "typescript": "~3.9.3", - "vue-cli-plugin-styleguidist": "^4.25.0", + "vue-cli-plugin-styleguidist": "~4.26.0", "vue-cli-plugin-svg": "~0.1.3", "vue-i18n-extract": "^1.0.2", "vue-template-compiler": "^2.6.11", diff --git a/js/src/components/User/AuthProvider.vue b/js/src/components/User/AuthProvider.vue new file mode 100644 index 000000000..79e48ef6b --- /dev/null +++ b/js/src/components/User/AuthProvider.vue @@ -0,0 +1,26 @@ + + diff --git a/js/src/components/User/AuthProviders.vue b/js/src/components/User/AuthProviders.vue new file mode 100644 index 000000000..cd04d09d8 --- /dev/null +++ b/js/src/components/User/AuthProviders.vue @@ -0,0 +1,26 @@ + + diff --git a/js/src/graphql/config.ts b/js/src/graphql/config.ts index 90ab6ef8e..44471990c 100644 --- a/js/src/graphql/config.ts +++ b/js/src/graphql/config.ts @@ -62,6 +62,13 @@ export const CONFIG = gql` features { groups } + auth { + ldap + oauthProviders { + id + label + } + } } } `; diff --git a/js/src/graphql/user.ts b/js/src/graphql/user.ts index 91d7e14af..f5fdd350d 100644 --- a/js/src/graphql/user.ts +++ b/js/src/graphql/user.ts @@ -35,6 +35,15 @@ export const LOGGED_USER = gql` loggedUser { id email + defaultActor { + id + preferredUsername + name + avatar { + url + } + } + provider } } `; @@ -64,7 +73,7 @@ export const VALIDATE_EMAIL = gql` `; export const DELETE_ACCOUNT = gql` - mutation DeleteAccount($password: String, $userId: ID!) { + mutation DeleteAccount($password: String, $userId: ID) { deleteAccount(password: $password, userId: $userId) { id } diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 0f8cad665..95070573f 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -703,5 +703,10 @@ "New discussion": "New discussion", "Create a discussion": "Create a discussion", "Create the discussion": "Create the discussion", - "View all discussions": "View all discussions" + "View all discussions": "View all discussions", + "Sign in with": "Sign in with", + "Your email address was automatically set based on your {provider} account.": "Your email address was automatically set based on your {provider} account.", + "You can't change your password because you are registered through {provider}.": "You can't change your password because you are registered through {provider}.", + "Error while login with {provider}. Retry or login another way.": "Error while login with {provider}. Retry or login another way.", + "Error while login with {provider}. This login provider doesn't exist.": "Error while login with {provider}. This login provider doesn't exist." } diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 12204305f..b0ad62388 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -703,5 +703,10 @@ "{number} participations": "Aucune participation|Une participation|{number} participations", "{profile} (by default)": "{profile} (par défault)", "{title} ({count} todos)": "{title} ({count} todos)", - "© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap" + "© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap", + "Sign in with": "Se connecter avec", + "Your email address was automatically set based on your {provider} account.": "Votre adresse email a été définie automatiquement en se basant sur votre compte {provider}.", + "You can't change your password because you are registered through {provider}.": "Vous ne pouvez pas changer votre mot de passe car vous vous êtes enregistré via {provider}.", + "Error while login with {provider}. Retry or login another way.": "Erreur lors de la connexion avec {provider}. Réessayez ou bien connectez vous autrement.", + "Error while login with {provider}. This login provider doesn't exist.": "Erreur lors de la connexion avec {provider}. Cette méthode de connexion n'existe pas." } diff --git a/js/src/router/index.ts b/js/src/router/index.ts index e7cce702c..52e64663f 100644 --- a/js/src/router/index.ts +++ b/js/src/router/index.ts @@ -112,6 +112,11 @@ const router = new Router({ component: () => import(/* webpackChunkName: "cookies" */ "@/views/Interact.vue"), meta: { requiredAuth: false }, }, + { + path: "/auth/:provider/callback", + name: "auth-callback", + component: () => import("@/views/User/ProviderValidation.vue"), + }, { path: "/404", name: RouteName.PAGE_NOT_FOUND, diff --git a/js/src/types/config.model.ts b/js/src/types/config.model.ts index 61f0aaad9..3e53bf3bf 100644 --- a/js/src/types/config.model.ts +++ b/js/src/types/config.model.ts @@ -74,4 +74,13 @@ export interface IConfig { }; federating: boolean; version: string; + auth: { + ldap: boolean; + oauthProviders: IOAuthProvider[]; + }; +} + +export interface IOAuthProvider { + id: string; + label: string; } diff --git a/js/src/types/current-user.model.ts b/js/src/types/current-user.model.ts index 5eb7a2034..574ecd078 100644 --- a/js/src/types/current-user.model.ts +++ b/js/src/types/current-user.model.ts @@ -9,15 +9,11 @@ export enum ICurrentUserRole { } export interface ICurrentUser { - id: number; + id: string; email: string; isLoggedIn: boolean; role: ICurrentUserRole; - participations: Paginate; - defaultActor: IPerson; - drafts: IEvent[]; - settings: IUserSettings; - locale: string; + defaultActor?: IPerson; } export interface IUser extends ICurrentUser { @@ -25,6 +21,22 @@ export interface IUser extends ICurrentUser { confirmationSendAt: Date; actors: IPerson[]; disabled: boolean; + participations: Paginate; + drafts: IEvent[]; + settings: IUserSettings; + locale: string; + provider?: string; +} + +export enum IAuthProvider { + LDAP = "ldap", + GOOGLE = "google", + DISCORD = "discord", + GITHUB = "github", + KEYCLOAK = "keycloak", + FACEBOOK = "facebook", + GITLAB = "gitlab", + TWITTER = "twitter", } export enum INotificationPendingParticipationEnum { diff --git a/js/src/types/login-error-code.model.ts b/js/src/types/login-error-code.model.ts index c12c4c5c9..e2752030b 100644 --- a/js/src/types/login-error-code.model.ts +++ b/js/src/types/login-error-code.model.ts @@ -6,4 +6,6 @@ export enum LoginError { USER_NOT_CONFIRMED = "User account not confirmed", USER_DOES_NOT_EXIST = "No user with this email was found", USER_EMAIL_PASSWORD_INVALID = "Impossible to authenticate, either your email or password are invalid.", + LOGIN_PROVIDER_ERROR = "Error with Login Provider", + LOGIN_PROVIDER_NOT_FOUND = "Login Provider not found", } diff --git a/js/src/utils/auth.ts b/js/src/utils/auth.ts index 9d8a91c4e..f18f6104a 100644 --- a/js/src/utils/auth.ts +++ b/js/src/utils/auth.ts @@ -94,3 +94,14 @@ export async function logout(apollo: ApolloClient) { deleteUserData(); } + +export const SELECTED_PROVIDERS: { [key: string]: string } = { + twitter: "Twitter", + discord: "Discord", + facebook: "Facebook", + github: "Github", + gitlab: "Gitlab", + google: "Google", + keycloak: "Keycloak", + ldap: "LDAP", +}; diff --git a/js/src/views/Settings/AccountSettings.vue b/js/src/views/Settings/AccountSettings.vue index a1f320cc7..80168b738 100644 --- a/js/src/views/Settings/AccountSettings.vue +++ b/js/src/views/Settings/AccountSettings.vue @@ -1,5 +1,5 @@ + diff --git a/js/src/views/User/Register.vue b/js/src/views/User/Register.vue index abe9ce3a0..3df320bdc 100644 --- a/js/src/views/User/Register.vue +++ b/js/src/views/User/Register.vue @@ -96,6 +96,7 @@ {{ $t("Register") }}

+

{{ $t("Login") }}

+ +
+
+ +
@@ -131,9 +137,10 @@ import RouteName from "../../router/name"; import { IConfig } from "../../types/config.model"; import { CONFIG } from "../../graphql/config"; import Subtitle from "../../components/Utils/Subtitle.vue"; +import AuthProviders from "../../components/User/AuthProviders.vue"; @Component({ - components: { Subtitle }, + components: { Subtitle, AuthProviders }, metaInfo() { return { // if no subcomponents specify a metaInfo.title, this title will be used diff --git a/js/src/views/User/Validate.vue b/js/src/views/User/Validate.vue index c7a7ef183..f6df0fe0f 100644 --- a/js/src/views/User/Validate.vue +++ b/js/src/views/User/Validate.vue @@ -18,7 +18,7 @@ import { Component, Prop, Vue } from "vue-property-decorator"; import { VALIDATE_USER, UPDATE_CURRENT_USER_CLIENT } from "../../graphql/user"; import RouteName from "../../router/name"; -import { saveUserData, changeIdentity } from "../../utils/auth"; +import { saveUserData, saveTokenData, changeIdentity } from "../../utils/auth"; import { ILogin } from "../../types/login.model"; import { ICurrentUserRole } from "../../types/current-user.model"; @@ -45,6 +45,7 @@ export default class Validate extends Vue { if (data) { saveUserData(data.validateUser); + saveTokenData(data.validateUser); const { user } = data.validateUser; diff --git a/js/yarn.lock b/js/yarn.lock index 6b8fb3084..fb896df7a 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -41,35 +41,35 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.3.tgz#324bcfd8d35cd3d47dae18cde63d752086435e9a" - integrity sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== dependencies: - "@babel/highlight" "^7.10.3" + "@babel/highlight" "^7.10.4" -"@babel/compat-data@^7.10.1", "@babel/compat-data@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.3.tgz#9af3e033f36e8e2d6e47570db91e64a846f5d382" - integrity sha512-BDIfJ9uNZuI0LajPfoYV28lX8kyCPMHY6uY4WH1lJdcicmAfxCK5ASzaeV0D/wsUaRH/cLk+amuxtC37sZ8TUg== +"@babel/compat-data@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.4.tgz#706a6484ee6f910b719b696a9194f8da7d7ac241" + integrity sha512-t+rjExOrSVvjQQXNp5zAIYDp00KjdvGl/TpDX5REPr0S9IAIPQMTilcfG6q8c0QFmj9lSTVySV2VTsyggvtNIw== dependencies: browserslist "^4.12.0" invariant "^2.2.4" semver "^5.5.0" "@babel/core@^7.7.5", "@babel/core@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.3.tgz#73b0e8ddeec1e3fdd7a2de587a60e17c440ec77e" - integrity sha512-5YqWxYE3pyhIi84L84YcwjeEgS+fa7ZjK6IBVGTjDVfm64njkR2lfDhVR5OudLk8x2GK59YoSyVv+L/03k1q9w== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.4.tgz#780e8b83e496152f8dd7df63892b2e052bf1d51d" + integrity sha512-3A0tS0HWpy4XujGc7QtOIHTeNwUgWaZc/WuS5YQrfhU67jnVmsD6OGPc1AKHH0LJHQICGncy3+YUjIhVlfDdcA== dependencies: - "@babel/code-frame" "^7.10.3" - "@babel/generator" "^7.10.3" - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helpers" "^7.10.1" - "@babel/parser" "^7.10.3" - "@babel/template" "^7.10.3" - "@babel/traverse" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.4" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helpers" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -90,321 +90,321 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.3.tgz#32b9a0d963a71d7a54f5f6c15659c3dbc2a523a5" - integrity sha512-drt8MUHbEqRzNR0xnF8nMehbY11b1SDkRw03PSNH/3Rb2Z35oxkddVSi3rcaak0YJQ86PCuE7Qx1jSFhbLNBMA== +"@babel/generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243" + integrity sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz#f6d08acc6f70bbd59b436262553fb2e259a1a268" - integrity sha512-ewp3rvJEwLaHgyWGe4wQssC2vjks3E80WiUe2BpMb0KhreTjMROCbxXcEovTrbeGVdQct5VjQfrv9EgC+xMzCw== +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== dependencies: - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.4" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.1": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.3.tgz#4e9012d6701bef0030348d7f9c808209bd3e8687" - integrity sha512-lo4XXRnBlU6eRM92FkiZxpo1xFLmv3VsPFk61zJKMm7XYJfwqXHsYJTY6agoc4a3L8QPw1HqWehO18coZgbT6A== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== dependencies: - "@babel/helper-explode-assignable-expression" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-compilation-targets@^7.10.2", "@babel/helper-compilation-targets@^7.9.6": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz#a17d9723b6e2c750299d2a14d4637c76936d8285" - integrity sha512-hYgOhF4To2UTB4LTaZepN/4Pl9LD4gfbJx8A34mqoluT8TLbof1mhUlYuNWTEebONa8+UlCC4X0TEXu7AOUyGA== +"@babel/helper-compilation-targets@^7.10.4", "@babel/helper-compilation-targets@^7.9.6": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" + integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== dependencies: - "@babel/compat-data" "^7.10.1" + "@babel/compat-data" "^7.10.4" browserslist "^4.12.0" invariant "^2.2.4" levenary "^1.1.1" semver "^5.5.0" -"@babel/helper-create-class-features-plugin@^7.10.1", "@babel/helper-create-class-features-plugin@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.3.tgz#2783daa6866822e3d5ed119163b50f0fc3ae4b35" - integrity sha512-iRT9VwqtdFmv7UheJWthGc/h2s7MqoweBF9RUj77NFZsg9VfISvBTum3k6coAhJ8RWv2tj3yUjA03HxPd0vfpQ== +"@babel/helper-create-class-features-plugin@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz#2d4015d0136bd314103a70d84a7183e4b344a355" + integrity sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ== dependencies: - "@babel/helper-function-name" "^7.10.3" - "@babel/helper-member-expression-to-functions" "^7.10.3" - "@babel/helper-optimise-call-expression" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" - "@babel/helper-replace-supers" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" -"@babel/helper-create-regexp-features-plugin@^7.10.1", "@babel/helper-create-regexp-features-plugin@^7.8.3": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz#1b8feeab1594cbcfbf3ab5a3bbcabac0468efdbd" - integrity sha512-Rx4rHS0pVuJn5pJOqaqcZR4XSgeF9G/pO/79t+4r7380tXFJdzImFnxMU19f83wjSrmKHq6myrM10pFHTGzkUA== +"@babel/helper-create-regexp-features-plugin@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" + integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-regex" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" regexpu-core "^4.7.0" -"@babel/helper-define-map@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.3.tgz#d27120a5e57c84727b30944549b2dfeca62401a8" - integrity sha512-bxRzDi4Sin/k0drWCczppOhov1sBSdBvXJObM1NLHQzjhXhwRtn7aRWGvLJWCYbuu2qUk3EKs6Ci9C9ps8XokQ== +"@babel/helper-define-map@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz#f037ad794264f729eda1889f4ee210b870999092" + integrity sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA== dependencies: - "@babel/helper-function-name" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.4" lodash "^4.17.13" -"@babel/helper-explode-assignable-expression@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.3.tgz#9dc14f0cfa2833ea830a9c8a1c742b6e7461b05e" - integrity sha512-0nKcR64XrOC3lsl+uhD15cwxPvaB6QKUDlD84OT9C3myRbhJqTMYir69/RWItUvHpharv0eJ/wk7fl34ONSwZw== +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c" + integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A== dependencies: - "@babel/traverse" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-function-name@^7.10.1", "@babel/helper-function-name@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz#79316cd75a9fa25ba9787ff54544307ed444f197" - integrity sha512-FvSj2aiOd8zbeqijjgqdMDSyxsGHaMt5Tr0XjQsGKHD3/1FP3wksjnLAWzxw7lvXiej8W1Jt47SKTZ6upQNiRw== +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== dependencies: - "@babel/helper-get-function-arity" "^7.10.3" - "@babel/template" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-get-function-arity@^7.10.1", "@babel/helper-get-function-arity@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz#3a28f7b28ccc7719eacd9223b659fdf162e4c45e" - integrity sha512-iUD/gFsR+M6uiy69JA6fzM5seno8oE85IYZdbVVEuQaZlEzMO2MXblh+KSPJgsZAUx0EEbWXU0yJaW7C9CdAVg== +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" -"@babel/helper-hoist-variables@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.3.tgz#d554f52baf1657ffbd7e5137311abc993bb3f068" - integrity sha512-9JyafKoBt5h20Yv1+BXQMdcXXavozI1vt401KBiRc2qzUepbVnd7ogVNymY1xkQN9fekGwfxtotH2Yf5xsGzgg== +"@babel/helper-hoist-variables@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" -"@babel/helper-member-expression-to-functions@^7.10.1", "@babel/helper-member-expression-to-functions@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz#bc3663ac81ac57c39148fef4c69bf48a77ba8dd6" - integrity sha512-q7+37c4EPLSjNb2NmWOjNwj0+BOyYlssuQ58kHEWk1Z78K5i8vTUsteq78HMieRPQSl/NtpQyJfdjt3qZ5V2vw== +"@babel/helper-member-expression-to-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz#7cd04b57dfcf82fce9aeae7d4e4452fa31b8c7c4" + integrity sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.1", "@babel/helper-module-imports@^7.10.3", "@babel/helper-module-imports@^7.8.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz#766fa1d57608e53e5676f23ae498ec7a95e1b11a" - integrity sha512-Jtqw5M9pahLSUWA+76nhK9OG8nwYXzhQzVIGFoNaHnXF/r4l7kz4Fl0UAW7B6mqC5myoJiBP5/YQlXQTMfHI9w== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" -"@babel/helper-module-transforms@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" - integrity sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg== +"@babel/helper-module-transforms@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz#ca1f01fdb84e48c24d7506bb818c961f1da8805d" + integrity sha512-Er2FQX0oa3nV7eM1o0tNCTx7izmQtwAQsIiaLRWtavAAEcskb0XJ5OjJbVrYXWOTr8om921Scabn4/tzlx7j1Q== dependencies: - "@babel/helper-module-imports" "^7.10.1" - "@babel/helper-replace-supers" "^7.10.1" - "@babel/helper-simple-access" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" lodash "^4.17.13" -"@babel/helper-optimise-call-expression@^7.10.1", "@babel/helper-optimise-call-expression@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz#f53c4b6783093195b0f69330439908841660c530" - integrity sha512-kT2R3VBH/cnSz+yChKpaKRJQJWxdGoc6SjioRId2wkeV3bK0wLLioFpJROrX0U4xr/NmxSSAWT/9Ih5snwIIzg== +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== dependencies: - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.10.3", "@babel/helper-plugin-utils@^7.8.0": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244" - integrity sha512-j/+j8NAWUTxOtx4LKHybpSClxHoq6I91DQ/mKgAXn5oNUPIUiGppjPIX3TDtJWPrdfP9Kfl7e4fgVMiQR9VE/g== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== -"@babel/helper-regex@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.1.tgz#021cf1a7ba99822f993222a001cc3fec83255b96" - integrity sha512-7isHr19RsIJWWLLFn21ubFt223PjQyg1HY7CZEMRr820HttHPpVvrsIN3bUOo44DEfFV4kBXO7Abbn9KTUZV7g== +"@babel/helper-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.4.tgz#59b373daaf3458e5747dece71bbaf45f9676af6d" + integrity sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ== dependencies: lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.10.1", "@babel/helper-remap-async-to-generator@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.3.tgz#18564f8a6748be466970195b876e8bba3bccf442" - integrity sha512-sLB7666ARbJUGDO60ZormmhQOyqMX/shKBXZ7fy937s+3ID8gSrneMvKSSb+8xIM5V7Vn6uNVtOY1vIm26XLtA== +"@babel/helper-remap-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5" + integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-wrap-function" "^7.10.1" - "@babel/template" "^7.10.3" - "@babel/traverse" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-replace-supers@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" - integrity sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A== +"@babel/helper-replace-supers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" + integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.1" - "@babel/helper-optimise-call-expression" "^7.10.1" - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-simple-access@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e" - integrity sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw== +"@babel/helper-simple-access@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" + integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== dependencies: - "@babel/template" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-split-export-declaration@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" - integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g== +"@babel/helper-split-export-declaration@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1" + integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg== dependencies: - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.4" -"@babel/helper-validator-identifier@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" - integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw== +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== -"@babel/helper-wrap-function@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.1.tgz#956d1310d6696257a7afd47e4c42dfda5dfcedc9" - integrity sha512-C0MzRGteVDn+H32/ZgbAv5r56f2o1fZSA/rj/TYo8JEJNHg+9BdSmKBUND0shxWRztWhjlT2cvHYuynpPsVJwQ== +"@babel/helper-wrap-function@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" + integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helpers@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.1.tgz#a6827b7cb975c9d9cef5fd61d919f60d8844a973" - integrity sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw== +"@babel/helpers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" + integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== dependencies: - "@babel/template" "^7.10.1" - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/highlight@^7.0.0", "@babel/highlight@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d" - integrity sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw== +"@babel/highlight@^7.0.0", "@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== dependencies: - "@babel/helper-validator-identifier" "^7.10.3" + "@babel/helper-validator-identifier" "^7.10.4" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.3", "@babel/parser@^7.6.0": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315" - integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA== +"@babel/parser@^7.10.4", "@babel/parser@^7.6.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64" + integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA== -"@babel/plugin-proposal-async-generator-functions@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.3.tgz#5a02453d46e5362e2073c7278beab2e53ad7d939" - integrity sha512-WUUWM7YTOudF4jZBAJIW9D7aViYC/Fn0Pln4RIHlQALyno3sXSjqmTA4Zy1TKC2D49RCR8Y/Pn4OIUtEypK3CA== +"@babel/plugin-proposal-async-generator-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz#4b65abb3d9bacc6c657aaa413e56696f9f170fc6" + integrity sha512-MJbxGSmejEFVOANAezdO39SObkURO5o/8b6fSH6D1pi9RZQt+ldppKPXfqgUWpSQ9asM6xaSaSJIaeWMDRP0Zg== dependencies: - "@babel/helper-plugin-utils" "^7.10.3" - "@babel/helper-remap-async-to-generator" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-class-properties@^7.10.1", "@babel/plugin-proposal-class-properties@^7.8.3": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.1.tgz#046bc7f6550bb08d9bd1d4f060f5f5a4f1087e01" - integrity sha512-sqdGWgoXlnOdgMXU+9MbhzwFRgxVLeiGBqTrnuS7LC2IBU31wSsESbTUreT2O418obpfPdGUR2GbEufZF1bpqw== +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-proposal-decorators@^7.8.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.3.tgz#2fc6b5696028adccfcd14bc826c184c578b857f8" - integrity sha512-Rzwn5tcYFTdWWK3IrhMZkMDjzFQLIGYqHvv9XuzNnEB91Y6gHr/JjazYV1Yec9g0yMLhy1p/21eiW1P7f5UN4A== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.4.tgz#fe20ef10cc73f386f70910fca48798041cd357c7" + integrity sha512-JHTWjQngOPv+ZQQqOGv2x6sCCr4IYWy7S1/VH6BE9ZfkoLrdQ2GpEP3tfb5M++G9PwvqjhY8VC/C3tXm+/eHvA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" - "@babel/plugin-syntax-decorators" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.10.4" -"@babel/plugin-proposal-dynamic-import@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.1.tgz#e36979dc1dc3b73f6d6816fc4951da2363488ef0" - integrity sha512-Cpc2yUVHTEGPlmiQzXj026kqwjEQAD9I4ZC16uzdbgWgitg/UHKHLffKNCQZ5+y8jpIZPJcKcwsr2HwPh+w3XA== +"@babel/plugin-proposal-dynamic-import@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" + integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-json-strings@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.1.tgz#b1e691ee24c651b5a5e32213222b2379734aff09" - integrity sha512-m8r5BmV+ZLpWPtMY2mOKN7wre6HIO4gfIiV+eOmsnZABNenrt/kzYBwrh+KOfgumSWpnlGs5F70J8afYMSJMBg== +"@babel/plugin-proposal-json-strings@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" + integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.1.tgz#02dca21673842ff2fe763ac253777f235e9bbf78" - integrity sha512-56cI/uHYgL2C8HVuHOuvVowihhX0sxb3nnfVRzUeVHTWmRHTZrKuAh/OBIMggGU/S1g/1D2CRCXqP+3u7vX7iA== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" + integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-numeric-separator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.1.tgz#a9a38bc34f78bdfd981e791c27c6fdcec478c123" - integrity sha512-jjfym4N9HtCiNfyyLAVD8WqPYeHUrw4ihxuAynWj6zzp2gf9Ey2f7ImhFm6ikB3CLf5Z/zmcJDri6B4+9j9RsA== +"@babel/plugin-proposal-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" + integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-numeric-separator" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.3.tgz#b8d0d22f70afa34ad84b7a200ff772f9b9fce474" - integrity sha512-ZZh5leCIlH9lni5bU/wB/UcjtcVLgR8gc+FAgW2OOY+m9h1II3ItTO1/cewNUcsIDZSYcSaz/rYVls+Fb0ExVQ== +"@babel/plugin-proposal-object-rest-spread@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0" + integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA== dependencies: - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.1" + "@babel/plugin-transform-parameters" "^7.10.4" -"@babel/plugin-proposal-optional-catch-binding@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.1.tgz#c9f86d99305f9fa531b568ff5ab8c964b8b223d2" - integrity sha512-VqExgeE62YBqI3ogkGoOJp1R6u12DFZjqwJhqtKc2o5m1YTUuUWnos7bZQFBhwkxIFpWYJ7uB75U7VAPPiKETA== +"@babel/plugin-proposal-optional-catch-binding@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" + integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.3.tgz#9a726f94622b653c0a3a7a59cdce94730f526f7c" - integrity sha512-yyG3n9dJ1vZ6v5sfmIlMMZ8azQoqx/5/nZTSWX1td6L1H1bsjzA8TInDChpafCZiJkeOFzp/PtrfigAQXxI1Ng== +"@babel/plugin-proposal-optional-chaining@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz#750f1255e930a1f82d8cdde45031f81a0d0adff7" + integrity sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-private-methods@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.1.tgz#ed85e8058ab0fe309c3f448e5e1b73ca89cdb598" - integrity sha512-RZecFFJjDiQ2z6maFprLgrdnm0OzoC23Mx89xf1CcEsxmHuzuXOdniEuI+S3v7vjQG4F5sa6YtUp+19sZuSxHg== +"@babel/plugin-proposal-private-methods@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" + integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-unicode-property-regex@^7.10.1", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.1.tgz#dc04feb25e2dd70c12b05d680190e138fa2c0c6f" - integrity sha512-JjfngYRvwmPwmnbRZyNiPFI8zxCZb8euzbCG/LxyKdeTb59tVciKo9GK9bi6JYKInk1H11Dq9j/zRqIH4KigfQ== +"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" + integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-async-generators@^7.8.0": version "7.8.4" @@ -413,19 +413,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz#d5bc0645913df5b17ad7eda0fa2308330bde34c5" - integrity sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ== +"@babel/plugin-syntax-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" + integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-decorators@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.1.tgz#16b869c4beafc9a442565147bda7ce0967bd4f13" - integrity sha512-a9OAbQhKOwSle1Vr0NJu/ISg1sPfdEkfRKWpgPuzhnWWzForou2gIeUIIwjAMHRekhhpJ7eulZlYs0H14Cbi+g== +"@babel/plugin-syntax-decorators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c" + integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" @@ -442,11 +442,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.2.0", "@babel/plugin-syntax-jsx@^7.8.3": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.1.tgz#0ae371134a42b91d5418feb3c8c8d43e1565d2da" - integrity sha512-+OxyOArpVFXQeXKLO9o+r2I4dIoVoy6+Uu0vKELrlweDM3QJADZj+Z+5ERansZqIZBcLj42vHnDI8Rz9BnRIuQ== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c" + integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": version "7.8.3" @@ -455,12 +455,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz#25761ee7410bc8cf97327ba741ee94e4a61b7d99" - integrity sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg== +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.0": version "7.8.3" @@ -483,338 +483,338 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.1.tgz#8b8733f8c57397b3eaa47ddba8841586dcaef362" - integrity sha512-hgA5RYkmZm8FTFT3yu2N9Bx7yVVOKYT6yEdXXo6j2JTm0wNxgqaGeQVaSHRjhfnQbX91DtjFB6McRFSlcJH3xQ== +"@babel/plugin-syntax-top-level-await@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" + integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-arrow-functions@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.1.tgz#cb5ee3a36f0863c06ead0b409b4cc43a889b295b" - integrity sha512-6AZHgFJKP3DJX0eCNJj01RpytUa3SOGawIxweHkNX2L6PYikOZmoh5B0d7hIHaIgveMjX990IAa/xK7jRTN8OA== +"@babel/plugin-transform-arrow-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" + integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-async-to-generator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.1.tgz#e5153eb1a3e028f79194ed8a7a4bf55f862b2062" - integrity sha512-XCgYjJ8TY2slj6SReBUyamJn3k2JLUIiiR5b6t1mNCMSvv7yx+jJpaewakikp0uWFQSF7ChPPoe3dHmXLpISkg== +"@babel/plugin-transform-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" + integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== dependencies: - "@babel/helper-module-imports" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-remap-async-to-generator" "^7.10.1" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" -"@babel/plugin-transform-block-scoped-functions@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.1.tgz#146856e756d54b20fff14b819456b3e01820b85d" - integrity sha512-B7K15Xp8lv0sOJrdVAoukKlxP9N59HS48V1J3U/JGj+Ad+MHq+am6xJVs85AgXrQn4LV8vaYFOB+pr/yIuzW8Q== +"@babel/plugin-transform-block-scoped-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" + integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-block-scoping@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.1.tgz#47092d89ca345811451cd0dc5d91605982705d5e" - integrity sha512-8bpWG6TtF5akdhIm/uWTyjHqENpy13Fx8chg7pFH875aNLwX8JxIxqm08gmAT+Whe6AOmaTeLPe7dpLbXt+xUw== +"@babel/plugin-transform-block-scoping@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.4.tgz#a670d1364bb5019a621b9ea2001482876d734787" + integrity sha512-J3b5CluMg3hPUii2onJDRiaVbPtKFPLEaV5dOPY5OeAbDi1iU/UbbFFTgwb7WnanaDy7bjU35kc26W3eM5Qa0A== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.3.tgz#8d9a656bc3d01f3ff69e1fccb354b0f9d72ac544" - integrity sha512-irEX0ChJLaZVC7FvvRoSIxJlmk0IczFLcwaRXUArBKYHCHbOhe57aG8q3uw/fJsoSXvZhjRX960hyeAGlVBXZw== +"@babel/plugin-transform-classes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" + integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-define-map" "^7.10.3" - "@babel/helper-function-name" "^7.10.3" - "@babel/helper-optimise-call-expression" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" - "@babel/helper-replace-supers" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.3.tgz#d3aa6eef67cb967150f76faff20f0abbf553757b" - integrity sha512-GWzhaBOsdbjVFav96drOz7FzrcEW6AP5nax0gLIpstiFaI3LOb2tAg06TimaWU6YKOfUACK3FVrxPJ4GSc5TgA== +"@babel/plugin-transform-computed-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" + integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== dependencies: - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-destructuring@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.1.tgz#abd58e51337815ca3a22a336b85f62b998e71907" - integrity sha512-V/nUc4yGWG71OhaTH705pU8ZSdM6c1KmmLP8ys59oOYbT7RpMYAR3MsVOt6OHL0WzG7BlTU076va9fjJyYzJMA== +"@babel/plugin-transform-destructuring@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" + integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-dotall-regex@^7.10.1", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.1.tgz#920b9fec2d78bb57ebb64a644d5c2ba67cc104ee" - integrity sha512-19VIMsD1dp02RvduFUmfzj8uknaO3uiHHF0s3E1OHnVsNj8oge8EQ5RzHRbJjGSetRnkEuBYO7TG1M5kKjGLOA== +"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" + integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-duplicate-keys@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.1.tgz#c900a793beb096bc9d4d0a9d0cde19518ffc83b9" - integrity sha512-wIEpkX4QvX8Mo9W6XF3EdGttrIPZWozHfEaDTU0WJD/TDnXMvdDh30mzUl/9qWhnf7naicYartcEfUghTCSNpA== +"@babel/plugin-transform-duplicate-keys@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" + integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-exponentiation-operator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.1.tgz#279c3116756a60dd6e6f5e488ba7957db9c59eb3" - integrity sha512-lr/przdAbpEA2BUzRvjXdEDLrArGRRPwbaF9rvayuHRvdQ7lUTTkZnhZrJ4LE2jvgMRFF4f0YuPQ20vhiPYxtA== +"@babel/plugin-transform-exponentiation-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" + integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-for-of@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.1.tgz#ff01119784eb0ee32258e8646157ba2501fcfda5" - integrity sha512-US8KCuxfQcn0LwSCMWMma8M2R5mAjJGsmoCBVwlMygvmDUMkTCykc84IqN1M7t+agSfOmLYTInLCHJM+RUoz+w== +"@babel/plugin-transform-for-of@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" + integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-function-name@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.1.tgz#4ed46fd6e1d8fde2a2ec7b03c66d853d2c92427d" - integrity sha512-//bsKsKFBJfGd65qSNNh1exBy5Y9gD9ZN+DvrJ8f7HXr4avE5POW6zB7Rj6VnqHV33+0vXWUwJT0wSHubiAQkw== +"@babel/plugin-transform-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" + integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.1.tgz#5794f8da82846b22e4e6631ea1658bce708eb46a" - integrity sha512-qi0+5qgevz1NHLZroObRm5A+8JJtibb7vdcPQF1KQE12+Y/xxl8coJ+TpPW9iRq+Mhw/NKLjm+5SHtAHCC7lAw== +"@babel/plugin-transform-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" + integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-member-expression-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.1.tgz#90347cba31bca6f394b3f7bd95d2bbfd9fce2f39" - integrity sha512-UmaWhDokOFT2GcgU6MkHC11i0NQcL63iqeufXWfRy6pUOGYeCGEKhvfFO6Vz70UfYJYHwveg62GS83Rvpxn+NA== +"@babel/plugin-transform-member-expression-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" + integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-modules-amd@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.1.tgz#65950e8e05797ebd2fe532b96e19fc5482a1d52a" - integrity sha512-31+hnWSFRI4/ACFr1qkboBbrTxoBIzj7qA69qlq8HY8p7+YCzkCT6/TvQ1a4B0z27VeWtAeJd6pr5G04dc1iHw== +"@babel/plugin-transform-modules-amd@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.4.tgz#cb407c68b862e4c1d13a2fc738c7ec5ed75fc520" + integrity sha512-3Fw+H3WLUrTlzi3zMiZWp3AR4xadAEMv6XRCYnd5jAlLM61Rn+CRJaZMaNvIpcJpQ3vs1kyifYvEVPFfoSkKOA== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.1.tgz#d5ff4b4413ed97ffded99961056e1fb980fb9301" - integrity sha512-AQG4fc3KOah0vdITwt7Gi6hD9BtQP/8bhem7OjbaMoRNCH5Djx42O2vYMfau7QnAzQCa+RJnhJBmFFMGpQEzrg== +"@babel/plugin-transform-modules-commonjs@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" + integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-simple-access" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.3.tgz#004ae727b122b7b146b150d50cba5ffbff4ac56b" - integrity sha512-GWXWQMmE1GH4ALc7YXW56BTh/AlzvDWhUNn9ArFF0+Cz5G8esYlVbXfdyHa1xaD1j+GnBoCeoQNlwtZTVdiG/A== +"@babel/plugin-transform-modules-systemjs@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.4.tgz#8f576afd943ac2f789b35ded0a6312f929c633f9" + integrity sha512-Tb28LlfxrTiOTGtZFsvkjpyjCl9IoaRI52AEU/VIwOwvDQWtbNJsAqTXzh+5R7i74e/OZHH2c2w2fsOqAfnQYQ== dependencies: - "@babel/helper-hoist-variables" "^7.10.3" - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-hoist-variables" "^7.10.4" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.1.tgz#ea080911ffc6eb21840a5197a39ede4ee67b1595" - integrity sha512-EIuiRNMd6GB6ulcYlETnYYfgv4AxqrswghmBRQbWLHZxN4s7mupxzglnHqk9ZiUpDI4eRWewedJJNj67PWOXKA== +"@babel/plugin-transform-modules-umd@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" + integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-named-capturing-groups-regex@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.3.tgz#a4f8444d1c5a46f35834a410285f2c901c007ca6" - integrity sha512-I3EH+RMFyVi8Iy/LekQm948Z4Lz4yKT7rK+vuCAeRm0kTa6Z5W7xuhRxDNJv0FPya/her6AUgrDITb70YHtTvA== +"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" + integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" -"@babel/plugin-transform-new-target@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.1.tgz#6ee41a5e648da7632e22b6fb54012e87f612f324" - integrity sha512-MBlzPc1nJvbmO9rPr1fQwXOM2iGut+JC92ku6PbiJMMK7SnQc1rytgpopveE3Evn47gzvGYeCdgfCDbZo0ecUw== +"@babel/plugin-transform-new-target@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" + integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-object-super@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.1.tgz#2e3016b0adbf262983bf0d5121d676a5ed9c4fde" - integrity sha512-WnnStUDN5GL+wGQrJylrnnVlFhFmeArINIR9gjhSeYyvroGhBrSAXYg/RHsnfzmsa+onJrTJrEClPzgNmmQ4Gw== +"@babel/plugin-transform-object-super@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" + integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-replace-supers" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" -"@babel/plugin-transform-parameters@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.1.tgz#b25938a3c5fae0354144a720b07b32766f683ddd" - integrity sha512-tJ1T0n6g4dXMsL45YsSzzSDZCxiHXAQp/qHrucOq5gEHncTA3xDxnd5+sZcoQp+N1ZbieAaB8r/VUCG0gqseOg== +"@babel/plugin-transform-parameters@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.4.tgz#7b4d137c87ea7adc2a0f3ebf53266871daa6fced" + integrity sha512-RurVtZ/D5nYfEg0iVERXYKEgDFeesHrHfx8RT05Sq57ucj2eOYAP6eu5fynL4Adju4I/mP/I6SO0DqNWAXjfLQ== dependencies: - "@babel/helper-get-function-arity" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-property-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.1.tgz#cffc7315219230ed81dc53e4625bf86815b6050d" - integrity sha512-Kr6+mgag8auNrgEpbfIWzdXYOvqDHZOF0+Bx2xh4H2EDNwcbRb9lY6nkZg8oSjsX+DH9Ebxm9hOqtKW+gRDeNA== +"@babel/plugin-transform-property-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" + integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-regenerator@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.3.tgz#6ec680f140a5ceefd291c221cb7131f6d7e8cb6d" - integrity sha512-H5kNeW0u8mbk0qa1jVIVTeJJL6/TJ81ltD4oyPx0P499DhMJrTmmIFCmJ3QloGpQG8K9symccB7S7SJpCKLwtw== +"@babel/plugin-transform-regenerator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" + integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.1.tgz#0fc1027312b4d1c3276a57890c8ae3bcc0b64a86" - integrity sha512-qN1OMoE2nuqSPmpTqEM7OvJ1FkMEV+BjVeZZm9V9mq/x1JLKQ4pcv8riZJMNN3u2AUGl0ouOMjRr2siecvHqUQ== +"@babel/plugin-transform-reserved-words@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" + integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-runtime@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.3.tgz#3b287b06acc534a7cb6e6c71d6b1d88b1922dd6c" - integrity sha512-b5OzMD1Hi8BBzgQdRHyVVaYrk9zG0wset1it2o3BgonkPadXfOv0aXRqd7864DeOIu3FGKP/h6lr15FE5mahVw== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.4.tgz#594fb53453ea1b6f0779cceb48ce0718a447feb7" + integrity sha512-8ULlGv8p+Vuxu+kz2Y1dk6MYS2b/Dki+NO6/0ZlfSj5tMalfDL7jI/o/2a+rrWLqSXvnadEqc2WguB4gdQIxZw== dependencies: - "@babel/helper-module-imports" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-shorthand-properties@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.1.tgz#e8b54f238a1ccbae482c4dce946180ae7b3143f3" - integrity sha512-AR0E/lZMfLstScFwztApGeyTHJ5u3JUKMjneqRItWeEqDdHWZwAOKycvQNCasCK/3r5YXsuNG25funcJDu7Y2g== +"@babel/plugin-transform-shorthand-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" + integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-spread@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.1.tgz#0c6d618a0c4461a274418460a28c9ccf5239a7c8" - integrity sha512-8wTPym6edIrClW8FI2IoaePB91ETOtg36dOkj3bYcNe7aDMN2FXEoUa+WrmPc4xa1u2PQK46fUX2aCb+zo9rfw== +"@babel/plugin-transform-spread@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff" + integrity sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-sticky-regex@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.1.tgz#90fc89b7526228bed9842cff3588270a7a393b00" - integrity sha512-j17ojftKjrL7ufX8ajKvwRilwqTok4q+BjkknmQw9VNHnItTyMP5anPFzxFJdCQs7clLcWpCV3ma+6qZWLnGMA== +"@babel/plugin-transform-sticky-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" + integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-regex" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" -"@babel/plugin-transform-template-literals@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.3.tgz#69d39b3d44b31e7b4864173322565894ce939b25" - integrity sha512-yaBn9OpxQra/bk0/CaA4wr41O0/Whkg6nqjqApcinxM7pro51ojhX6fv1pimAnVjVfDy14K0ULoRL70CA9jWWA== +"@babel/plugin-transform-template-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.4.tgz#e6375407b30fcb7fcfdbba3bb98ef3e9d36df7bc" + integrity sha512-4NErciJkAYe+xI5cqfS8pV/0ntlY5N5Ske/4ImxAVX7mk9Rxt2bwDTGv1Msc2BRJvWQcmYEC+yoMLdX22aE4VQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.3" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-typeof-symbol@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.1.tgz#60c0239b69965d166b80a84de7315c1bc7e0bb0e" - integrity sha512-qX8KZcmbvA23zDi+lk9s6hC1FM7jgLHYIjuLgULgc8QtYnmB3tAVIYkNoKRQ75qWBeyzcoMoK8ZQmogGtC/w0g== +"@babel/plugin-transform-typeof-symbol@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" + integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-unicode-escapes@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.1.tgz#add0f8483dab60570d9e03cecef6c023aa8c9940" - integrity sha512-zZ0Poh/yy1d4jeDWpx/mNwbKJVwUYJX73q+gyh4bwtG0/iUlzdEu0sLMda8yuDFS6LBQlT/ST1SJAR6zYwXWgw== +"@babel/plugin-transform-unicode-escapes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" + integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-unicode-regex@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.1.tgz#6b58f2aea7b68df37ac5025d9c88752443a6b43f" - integrity sha512-Y/2a2W299k0VIUdbqYm9X2qS6fE0CUBhhiPpimK6byy7OJ/kORLlIX+J6UrjgNu5awvs62k+6RSslxhcvVw2Tw== +"@babel/plugin-transform-unicode-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" + integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/preset-env@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.3.tgz#3e58c9861bbd93b6a679987c7e4bd365c56c80c9" - integrity sha512-jHaSUgiewTmly88bJtMHbOd1bJf2ocYxb5BWKSDQIP5tmgFuS/n0gl+nhSrYDhT33m0vPxp+rP8oYYgPgMNQlg== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f" + integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw== dependencies: - "@babel/compat-data" "^7.10.3" - "@babel/helper-compilation-targets" "^7.10.2" - "@babel/helper-module-imports" "^7.10.3" - "@babel/helper-plugin-utils" "^7.10.3" - "@babel/plugin-proposal-async-generator-functions" "^7.10.3" - "@babel/plugin-proposal-class-properties" "^7.10.1" - "@babel/plugin-proposal-dynamic-import" "^7.10.1" - "@babel/plugin-proposal-json-strings" "^7.10.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" - "@babel/plugin-proposal-numeric-separator" "^7.10.1" - "@babel/plugin-proposal-object-rest-spread" "^7.10.3" - "@babel/plugin-proposal-optional-catch-binding" "^7.10.1" - "@babel/plugin-proposal-optional-chaining" "^7.10.3" - "@babel/plugin-proposal-private-methods" "^7.10.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.10.1" + "@babel/compat-data" "^7.10.4" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-async-generator-functions" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-dynamic-import" "^7.10.4" + "@babel/plugin-proposal-json-strings" "^7.10.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" + "@babel/plugin-proposal-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread" "^7.10.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" + "@babel/plugin-proposal-optional-chaining" "^7.10.4" + "@babel/plugin-proposal-private-methods" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.10.1" + "@babel/plugin-syntax-class-properties" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.1" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.10.1" - "@babel/plugin-transform-arrow-functions" "^7.10.1" - "@babel/plugin-transform-async-to-generator" "^7.10.1" - "@babel/plugin-transform-block-scoped-functions" "^7.10.1" - "@babel/plugin-transform-block-scoping" "^7.10.1" - "@babel/plugin-transform-classes" "^7.10.3" - "@babel/plugin-transform-computed-properties" "^7.10.3" - "@babel/plugin-transform-destructuring" "^7.10.1" - "@babel/plugin-transform-dotall-regex" "^7.10.1" - "@babel/plugin-transform-duplicate-keys" "^7.10.1" - "@babel/plugin-transform-exponentiation-operator" "^7.10.1" - "@babel/plugin-transform-for-of" "^7.10.1" - "@babel/plugin-transform-function-name" "^7.10.1" - "@babel/plugin-transform-literals" "^7.10.1" - "@babel/plugin-transform-member-expression-literals" "^7.10.1" - "@babel/plugin-transform-modules-amd" "^7.10.1" - "@babel/plugin-transform-modules-commonjs" "^7.10.1" - "@babel/plugin-transform-modules-systemjs" "^7.10.3" - "@babel/plugin-transform-modules-umd" "^7.10.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.3" - "@babel/plugin-transform-new-target" "^7.10.1" - "@babel/plugin-transform-object-super" "^7.10.1" - "@babel/plugin-transform-parameters" "^7.10.1" - "@babel/plugin-transform-property-literals" "^7.10.1" - "@babel/plugin-transform-regenerator" "^7.10.3" - "@babel/plugin-transform-reserved-words" "^7.10.1" - "@babel/plugin-transform-shorthand-properties" "^7.10.1" - "@babel/plugin-transform-spread" "^7.10.1" - "@babel/plugin-transform-sticky-regex" "^7.10.1" - "@babel/plugin-transform-template-literals" "^7.10.3" - "@babel/plugin-transform-typeof-symbol" "^7.10.1" - "@babel/plugin-transform-unicode-escapes" "^7.10.1" - "@babel/plugin-transform-unicode-regex" "^7.10.1" + "@babel/plugin-syntax-top-level-await" "^7.10.4" + "@babel/plugin-transform-arrow-functions" "^7.10.4" + "@babel/plugin-transform-async-to-generator" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions" "^7.10.4" + "@babel/plugin-transform-block-scoping" "^7.10.4" + "@babel/plugin-transform-classes" "^7.10.4" + "@babel/plugin-transform-computed-properties" "^7.10.4" + "@babel/plugin-transform-destructuring" "^7.10.4" + "@babel/plugin-transform-dotall-regex" "^7.10.4" + "@babel/plugin-transform-duplicate-keys" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator" "^7.10.4" + "@babel/plugin-transform-for-of" "^7.10.4" + "@babel/plugin-transform-function-name" "^7.10.4" + "@babel/plugin-transform-literals" "^7.10.4" + "@babel/plugin-transform-member-expression-literals" "^7.10.4" + "@babel/plugin-transform-modules-amd" "^7.10.4" + "@babel/plugin-transform-modules-commonjs" "^7.10.4" + "@babel/plugin-transform-modules-systemjs" "^7.10.4" + "@babel/plugin-transform-modules-umd" "^7.10.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" + "@babel/plugin-transform-new-target" "^7.10.4" + "@babel/plugin-transform-object-super" "^7.10.4" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-transform-property-literals" "^7.10.4" + "@babel/plugin-transform-regenerator" "^7.10.4" + "@babel/plugin-transform-reserved-words" "^7.10.4" + "@babel/plugin-transform-shorthand-properties" "^7.10.4" + "@babel/plugin-transform-spread" "^7.10.4" + "@babel/plugin-transform-sticky-regex" "^7.10.4" + "@babel/plugin-transform-template-literals" "^7.10.4" + "@babel/plugin-transform-typeof-symbol" "^7.10.4" + "@babel/plugin-transform-unicode-escapes" "^7.10.4" + "@babel/plugin-transform-unicode-regex" "^7.10.4" "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.10.3" + "@babel/types" "^7.10.4" browserslist "^4.12.0" core-js-compat "^3.6.2" invariant "^2.2.2" @@ -833,13 +833,21 @@ esutils "^2.0.2" "@babel/runtime-corejs2@^7.0.0": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.10.3.tgz#81bc99a96bfcb6db3f0dcf73fdc577cc554d341b" - integrity sha512-enKvnR/kKFbZFgXYo165wtSA5OeiTlgsnU4jV3vpKRhfWUJjLS6dfVcjIPeRcgJbgEgdgu0I+UyBWqu6c0GumQ== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.10.4.tgz#5d48ee239624d511c88208da86c27a161ee01cf7" + integrity sha512-9sArmpZDQsnR1yyAcU51DxQrntWxt0LUKjPp3pIyo7kVLfaqKt8muppcT87QmFkXV5H50qXAF8JWOjk0jaXRYA== dependencies: core-js "^2.6.5" regenerator-runtime "^0.13.4" +"@babel/runtime-corejs3@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz#f29fc1990307c4c57b10dbd6ce667b27159d9e0d" + integrity sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" + "@babel/runtime@7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f" @@ -848,32 +856,32 @@ regenerator-runtime "^0.12.0" "@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364" - integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99" + integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.10.1", "@babel/template@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8" - integrity sha512-5BjI4gdtD+9fHZUsaxPHPNpwa+xRkDO7c7JbhYn2afvrkDu5SfAAbi9AIMXw2xEhO/BR35TqiW97IqNvCo/GqA== +"@babel/template@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== dependencies: - "@babel/code-frame" "^7.10.3" - "@babel/parser" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/traverse@^7.10.1", "@babel/traverse@^7.10.3": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.3.tgz#0b01731794aa7b77b214bcd96661f18281155d7e" - integrity sha512-qO6623eBFhuPm0TmmrUFMT1FulCmsSeJuVGhiLodk2raUDFhhTECLd9E9jC4LBIWziqt4wgF6KuXE4d+Jz9yug== +"@babel/traverse@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818" + integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q== dependencies: - "@babel/code-frame" "^7.10.3" - "@babel/generator" "^7.10.3" - "@babel/helper-function-name" "^7.10.3" - "@babel/helper-split-export-declaration" "^7.10.1" - "@babel/parser" "^7.10.3" - "@babel/types" "^7.10.3" + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" @@ -887,12 +895,12 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@babel/types@^7.10.1", "@babel/types@^7.10.3", "@babel/types@^7.4.4", "@babel/types@^7.6.0": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" - integrity sha512-nZxaJhBXBQ8HVoIcGsf9qWep3Oh3jCENK54V4mRF7qaJabVsAYdbTtmSD8WmAp1R6ytPiu5apMwSXyxB1WlaBA== +"@babel/types@^7.10.4", "@babel/types@^7.4.4", "@babel/types@^7.6.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee" + integrity sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg== dependencies: - "@babel/helper-validator-identifier" "^7.10.3" + "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.13" to-fast-properties "^2.0.0" @@ -1039,9 +1047,9 @@ fastq "^1.6.0" "@popperjs/core@^2.3.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.2.tgz#7c6dc4ecef16149fd7a736710baa1b811017fdca" - integrity sha512-JlGTGRYHC2QK+DDbePyXdBdooxFq2+noLfWpRqJtkxcb/oYWzOF0kcbfvvbWrwevCC1l6hLUg1wHYT+ona5BWQ== + version "2.4.4" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.4.tgz#11d5db19bd178936ec89cd84519c4de439574398" + integrity sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg== "@sindresorhus/is@^0.14.0": version "0.14.0" @@ -1137,9 +1145,9 @@ "@types/leaflet" "*" "@types/leaflet@*", "@types/leaflet@^1.5.2": - version "1.5.12" - resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.12.tgz#9953b7e47a53e0a70cdd7a903a43dc3c343cf623" - integrity sha512-61HRMIng+bWvnnAIqUWLBlrd/TQZc4gU+gN1JL4K47EDtwIrcMEhWgi7PdcpbG1YmpH4F0EfOimkvV82gJIl9w== + version "1.5.13" + resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.13.tgz#e0e41612b236a6a37877a69a6eb996d2a9ba6905" + integrity sha512-aCNOIeoukY8DIQUs/8bNiiKQKc75HSFwo1YqcFaLe+SkG4DL+0ygKCDfhfZ54UX8k28pn5uA3QJEAw3wa2hqHw== dependencies: "@types/geojson" "*" @@ -1194,9 +1202,9 @@ "@types/orderedmap" "*" "@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.4": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.4.tgz#d135ecd4cdbd9ffa97cff24ffadc1e611dea7211" - integrity sha512-Gch4THfZ9QNsRQ7myibU8cG99F3b8/3Gto083ZuutNG72E0VmS8yfQzA5ahbndr5GUIbmKyOD5LqKTBvx/M0qw== + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.5.tgz#a91304e9aab6e71f868e23b3a1ae514a75033f8f" + integrity sha512-a5DxAifiF6vmdSJ5jsDMkpykUgUJUy+T5Q5hCjFOKJ4cfd3m3q1lsFKr7Bc4r91Qb7rfqyiKCMDnASS8LIHrKw== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-transform" "*" @@ -1210,9 +1218,9 @@ "@types/prosemirror-model" "*" "@types/prosemirror-view@*", "@types/prosemirror-view@^1.11.4": - version "1.11.4" - resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.11.4.tgz#580f5044fc600c79e199dfb56bf988028422c4e4" - integrity sha512-Hh8v2tpCEMaIesQuw7Y7Pz6imoC1T/bR5OlNGVtp944PZvctXiBvFRkQIb0YvZpt7vVkFzeq2kmR+7mnUfvWiw== + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.15.0.tgz#47d80431559107854f559ccaa29f919f5224a440" + integrity sha512-OBIAiVInYS0cr4txLZEVYs1t1aFKaAZvogFDgkZfLwa+uda+LNPSs6m4tNLU/KXoFu9iK9CPOpiYTlDQPEnU6g== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-state" "*" @@ -1272,9 +1280,9 @@ source-map "^0.7.3" "@types/webpack@^4.4.31": - version "4.41.17" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.17.tgz#0a69005e644d657c85b7d6ec1c826a71bebd1c93" - integrity sha512-6FfeCidTSHozwKI67gIVQQ5Mp0g4X96c2IXxX75hYEQJwST/i6NyZexP//zzMOBb+wG9jJ7oO8fk9yObP2HWAw== + version "4.41.18" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.18.tgz#2945202617866ecdffa582087f1b6de04a7eed55" + integrity sha512-mQm2R8vV2BZE/qIDVYqmBVLfX73a8muwjs74SpjEyJWJxeXBbsI9L65Pcia9XfYLYWzD1c1V8m+L0p30y2N7MA== dependencies: "@types/anymatch" "*" "@types/node" "*" @@ -1308,13 +1316,14 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz#8a44dfc6fb7f1d071937b390fe27608ebda122b8" - integrity sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw== +"@typescript-eslint/experimental-utils@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.5.0.tgz#d09f9ffb890d1b15a7ffa9975fae92eee05597c4" + integrity sha512-zGNOrVi5Wz0jcjUnFZ6QUD0MCox5hBuVwemGCew2qJzUX5xPoyR+0EzS5qD5qQXL/vnQ8Eu+nv03tpeFRwLrDg== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "3.4.0" + "@typescript-eslint/types" "3.5.0" + "@typescript-eslint/typescript-estree" "3.5.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -1329,15 +1338,21 @@ eslint-visitor-keys "^1.1.0" "@typescript-eslint/parser@^3.0.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.4.0.tgz#fe52b68c5cb3bba3f5d875bd17adb70420d49d8d" - integrity sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA== + version "3.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.5.0.tgz#9ff8c11877c48df24e10e19d7bf542ee0359500d" + integrity sha512-sU07VbYB70WZHtgOjH/qfAp1+OwaWgrvD1Km1VXqRpcVxt971PMTU7gJtlrCje0M+Sdz7xKAbtiyIu+Y6QdnVA== dependencies: "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.4.0" - "@typescript-eslint/typescript-estree" "3.4.0" + "@typescript-eslint/experimental-utils" "3.5.0" + "@typescript-eslint/types" "3.5.0" + "@typescript-eslint/typescript-estree" "3.5.0" eslint-visitor-keys "^1.1.0" +"@typescript-eslint/types@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.5.0.tgz#4e3d2a2272268d8ec3e3e4a37152a64956682639" + integrity sha512-Dreqb5idi66VVs1QkbAwVeDmdJG+sDtofJtKwKCZXIaBsINuCN7Jv5eDIHrS0hFMMiOvPH9UuOs4splW0iZe4Q== + "@typescript-eslint/typescript-estree@2.34.0": version "2.34.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" @@ -1351,19 +1366,27 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz#6a787eb70b48969e4cd1ea67b057083f96dfee29" - integrity sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw== +"@typescript-eslint/typescript-estree@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.5.0.tgz#dfc895db21a381b84f24c2a719f5bf9c600dcfdc" + integrity sha512-Na71ezI6QP5WVR4EHxwcBJgYiD+Sre9BZO5iJK2QhrmRPo/42+b0no/HZIrdD1sjghzlYv7t+7Jis05M1uMxQg== dependencies: + "@typescript-eslint/types" "3.5.0" + "@typescript-eslint/visitor-keys" "3.5.0" debug "^4.1.1" - eslint-visitor-keys "^1.1.0" glob "^7.1.6" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/visitor-keys@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.5.0.tgz#73c1ea2582f814735e4afdc1cf6f5e3af78db60a" + integrity sha512-7cTp9rcX2sz9Z+zua9MCOX4cqp5rYyFD5o8LlbSpXrMTXoRdngTtotRZEkm8+FNMHPWYFhitFK+qt/brK8BVJQ== + dependencies: + eslint-visitor-keys "^1.1.0" + "@vue/babel-helper-vue-jsx-merge-props@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" @@ -2695,9 +2718,9 @@ binary-extensions@^1.0.0: integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" - integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + version "2.1.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" + integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== bindings@^1.5.0: version "1.5.0" @@ -2919,12 +2942,12 @@ browserslist@4.7.0: node-releases "^1.1.29" browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5: - version "4.12.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.1.tgz#6d08bef149b70d153930780ba762644e0f329122" - integrity sha512-WMjXwFtPskSW1pQUDJRxvRKRkeCr7usN0O/Za76N+F4oadaTdQHotSGcX9jT/Hs7mSKPkyMFNvqawB/1HzYDKQ== + version "4.12.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.2.tgz#76653d7e4c57caa8a1a28513e2f4e197dc11a711" + integrity sha512-MfZaeYqR8StRZdstAK9hCKDd2StvePCYp5rHzQCPicUjfFliDgmuaBNPHYUTpAywBN8+Wc/d7NYVFkO0aqaBUw== dependencies: caniuse-lite "^1.0.30001088" - electron-to-chromium "^1.3.481" + electron-to-chromium "^1.3.483" escalade "^3.0.1" node-releases "^1.1.58" @@ -3186,9 +3209,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001087, caniuse-lite@^1.0.30001088: - version "1.0.30001088" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001088.tgz#23a6b9e192106107458528858f2c0e0dba0d9073" - integrity sha512-6eYUrlShRYveyqKG58HcyOfPgh3zb2xqs7NvT2VVtP3hEUeeWvc3lqhpeMTxYWBBeeaT9A4bKsrtjATm66BTHg== + version "1.0.30001093" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001093.tgz#833e80f64b1a0455cbceed2a4a3baf19e4abd312" + integrity sha512-0+ODNoOjtWD5eS9aaIpf4K0gQqZfILNY4WSNuYzeT1sXni+lMrrVjc0odEobJt6wrODofDZUX8XYi/5y7+xl8g== capture-stack-trace@^1.0.0: version "1.0.1" @@ -3267,6 +3290,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + change-case@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e" @@ -3516,6 +3547,11 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + clipboard-copy@^3.0.0, clipboard-copy@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/clipboard-copy/-/clipboard-copy-3.1.0.tgz#4c59030a43d4988990564a664baeafba99f78ca4" @@ -4004,6 +4040,11 @@ core-js-compat@^3.6.2, core-js-compat@^3.6.5: browserslist "^4.8.5" semver "7.0.0" +core-js-pure@^3.0.0: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" + integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== + core-js@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.0.tgz#1e30793e9ee5782b307e37ffa22da0eacddd84d4" @@ -4357,9 +4398,9 @@ cssstyle@^2.0.0: cssom "~0.3.6" csstype@^2.6.5: - version "2.6.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" - integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== + version "2.6.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.11.tgz#452f4d024149ecf260a852b025e36562a253ffc5" + integrity sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw== cucumber-html-reporter@^3.0.4: version "3.0.4" @@ -4483,6 +4524,13 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-3.2.0.tgz#84b8e8f4f8c579f938e35e2cc7024907e0090851" + integrity sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw== + dependencies: + xregexp "^4.2.4" + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -4937,10 +4985,10 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.481: - version "1.3.483" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz#9269e7cfc1c8e72709824da171cbe47ca5e3ca9e" - integrity sha512-+05RF8S9rk8S0G8eBCqBRBaRq7+UN3lDs2DAvnG8SBSgQO3hjy0+qt4CmRk5eiuGbTcaicgXfPmBi31a+BD3lg== +electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.483: + version "1.3.487" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.487.tgz#8075e6ea33ee2e79a2dfb2a2467033f014017258" + integrity sha512-m4QS3IDShxauFfYFpnEzRCcUI55oKB9acEnHCuY/hSCZMz9Pz2KJj+UBnGHxRxS/mS1aphqOQ5wI6gc3yDZ7ew== elegant-spinner@^1.0.1: version "1.0.1" @@ -5190,9 +5238,9 @@ eslint-plugin-cypress@^2.10.3: globals "^11.12.0" eslint-plugin-import@^2.20.2, eslint-plugin-import@^2.21.2: - version "2.21.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.21.2.tgz#8fef77475cc5510801bedc95f84b932f7f334a7c" - integrity sha512-FEmxeGI6yaz+SnEB6YgNHlQK1Bs2DKLM+YF+vuTk5H8J9CLbJLtlPvRFgZZ2+sXiKAlN5dpdlrWOjK8ZoZJpQA== + version "2.22.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" + integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== dependencies: array-includes "^3.1.1" array.prototype.flat "^1.2.3" @@ -6635,9 +6683,9 @@ graphql@^14.0.0, graphql@^14.0.2: iterall "^1.2.2" graphql@^15.0.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.1.0.tgz#b93e28de805294ec08e1630d901db550cb8960a1" - integrity sha512-0TVyfOlCGhv/DBczQkJmwXOK6fjWkjzY3Pt7wY8i0gcYXq8aogG3weCsg48m72lywKSeOqedEHvVPOvZvSD51Q== + version "15.2.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.2.0.tgz#d9c655a523a3196d4b23657ec6ec5963b3bd4970" + integrity sha512-tsceRyHfgzZo+ee0YK3o8f0CR0cXAXxRlxoORWFo/CoM1bVy3UXGWeyzBcf+Y6oqPvO27BDmOEVATcunOO/MrQ== growl@1.10.5: version "1.10.5" @@ -7245,20 +7293,20 @@ inquirer@6.5.0: through "^2.3.6" inquirer@^7.0.0, inquirer@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.2.0.tgz#63ce99d823090de7eb420e4bb05e6f3449aa389a" - integrity sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ== + version "7.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.0.tgz#aa3e7cb0c18a410c3c16cdd2bc9dcbe83c4d333e" + integrity sha512-K+LZp6L/6eE5swqIcVXrxl21aGDU4S50gKH0/d96OMQnSBCyGyZl/oZhbkVmdp5sBoINHd4xZvFSARh2dk6DWA== dependencies: ansi-escapes "^4.2.1" - chalk "^3.0.0" + chalk "^4.1.0" cli-cursor "^3.1.0" - cli-width "^2.0.0" + cli-width "^3.0.0" external-editor "^3.0.3" figures "^3.0.0" lodash "^4.17.15" mute-stream "0.0.8" run-async "^2.4.0" - rxjs "^6.5.3" + rxjs "^6.6.0" string-width "^4.1.0" strip-ansi "^6.0.0" through "^2.3.6" @@ -7841,9 +7889,9 @@ javascript-stringify@^2.0.0, javascript-stringify@^2.0.1: integrity sha512-yV+gqbd5vaOYjqlbk16EG89xB5udgjqQF3C5FAORDg4f/IS1Yc5ERCv5e/57yBcfJYw05V5JyIXabhwb75Xxow== javascript-time-ago@^2.0.4: - version "2.0.7" - resolved "https://registry.yarnpkg.com/javascript-time-ago/-/javascript-time-ago-2.0.7.tgz#ed3e4cfae7059d1c3ecc0e7fc253427f0e120636" - integrity sha512-NjM8FNqY91lciAE4bIm6KBW1efDt+0T6+08erwaQRu6SzLov8fJ6623LcyxnBN/Xtf4q9O4s5AMxPtStaNz0rA== + version "2.0.8" + resolved "https://registry.yarnpkg.com/javascript-time-ago/-/javascript-time-ago-2.0.8.tgz#708e5d507b9e1a4ea0c25987b0d9a1a86e8ee229" + integrity sha512-/cQbnAwmF2OgpMCg8r185ZGqkkoHE8paNn9T3S98A6DXFQn4irzMVgMSWnKB4jvcvzTauF3HRi9wZXUdwHyj6Q== dependencies: relative-time-format "^0.1.3" @@ -11698,12 +11746,11 @@ regenerator-runtime@^0.13.4: integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== regenerator-transform@^0.14.2: - version "0.14.4" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" - integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== dependencies: "@babel/runtime" "^7.8.4" - private "^0.1.8" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" @@ -12165,10 +12212,10 @@ rxjs@^5.0.0-beta.11: dependencies: symbol-observable "1.0.1" -rxjs@^6.1.0, rxjs@^6.4.0, rxjs@^6.5.3: - version "6.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" - integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== +rxjs@^6.1.0, rxjs@^6.4.0, rxjs@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84" + integrity sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg== dependencies: tslib "^1.9.0" @@ -13358,9 +13405,9 @@ tiny-warning@^1.0.2: integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== tippy.js@^6.2.3: - version "6.2.3" - resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.2.3.tgz#0a5db67dc6bd9129233b26052b7ae2b2047fd73e" - integrity sha512-MzqHMrr2C0IC8ZUnG5kLQPxonWJ7V+Usqiy2W5b+dCvAfousio0mA85h+Ea5wRq94AQGd8mbFGeciRgkP+F+7w== + version "6.2.4" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.2.4.tgz#b76000080cc035745cab4f20ac7a30e1ccb1b6bb" + integrity sha512-S3qLJhx7cpeGDpHw411jU62W1RvOGPkt3r68y8nwPi7wm/aexrSYAADbVb1ZNYCjspEwLWQvtAx76COvPcLvCw== dependencies: "@popperjs/core" "^2.3.2" @@ -13756,9 +13803,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^3.9.3, typescript@~3.9.3: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + version "3.9.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" + integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw== uglify-js@3.4.x: version "3.4.10" @@ -14231,12 +14278,12 @@ vue-class-component@^7.2.3: resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.3.tgz#a5b1abd53513a72ad51098752e2dedd499807cca" integrity sha512-oEqYpXKaFN+TaXU+mRLEx8dX0ah85aAJEe61mpdoUrq0Bhe/6sWhyZX1JjMQLhVsHAkncyhedhmCdDVSasUtDw== -vue-cli-plugin-styleguidist@^4.25.0: - version "4.25.0" - resolved "https://registry.yarnpkg.com/vue-cli-plugin-styleguidist/-/vue-cli-plugin-styleguidist-4.25.0.tgz#8aab348db3983217c7be63cd92f8ad462cd4da89" - integrity sha512-7TPPOscE2j+0otWy5EFAS6us48mBEfGboycJE8bStSbnImNtBEBmIwAx2Jy8sd8Mnf1biSl0fzMzPizd1MVylQ== +vue-cli-plugin-styleguidist@~4.26.0: + version "4.26.0" + resolved "https://registry.yarnpkg.com/vue-cli-plugin-styleguidist/-/vue-cli-plugin-styleguidist-4.26.0.tgz#fd267f763e85939756b42db0e1a902343113db0b" + integrity sha512-cyS6cGwEG+wghZO8T06O6A2sUMMPpoVIbqQLMWqZTc+zU+A56+Ljo6ecPN0L9G0yaOv9MKXuIPZrAahLNGyxBQ== dependencies: - vue-styleguidist "^4.25.0" + vue-styleguidist "^4.26.0" webpack-merge "^4.2.1" vue-cli-plugin-svg@~0.1.3: @@ -14250,10 +14297,10 @@ vue-cli-plugin-svg@~0.1.3: url-loader "^2.0.0" vue-svg-loader "^0.12.0" -vue-docgen-api@^4.25.0: - version "4.25.0" - resolved "https://registry.yarnpkg.com/vue-docgen-api/-/vue-docgen-api-4.25.0.tgz#844d68c0badf0e30284283df94a2d544958b553a" - integrity sha512-HlYQ7MK9AhkXfnTlJcNWMDvCnSo1q6M0lbO0U39OdEUoQpzYqzBXSMvPZjuvYe6Tmdhuhl2PD7L37J5RspkVnw== +vue-docgen-api@^4.26.0: + version "4.26.0" + resolved "https://registry.yarnpkg.com/vue-docgen-api/-/vue-docgen-api-4.26.0.tgz#bf1a7fd201ddbcd62e4432a0e8b6369651fcf1fe" + integrity sha512-uJbmLup5NHukMUecMJiKgjLPdPIFDjlCFwOGX107S5gdlb+c/rd4ihOvWRAuVEBiUXWFxHJ12DZxCX1/UJGPcQ== dependencies: "@babel/parser" "^7.6.0" "@babel/types" "^7.6.0" @@ -14366,10 +14413,10 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2: hash-sum "^1.0.2" loader-utils "^1.0.2" -vue-styleguidist@^4.25.0: - version "4.25.0" - resolved "https://registry.yarnpkg.com/vue-styleguidist/-/vue-styleguidist-4.25.0.tgz#280cd6addefd0aa7d0f4047af56c0b17c5fcf2f2" - integrity sha512-tmKA+iHlbDKFJ2EIK6zQ9eeKXdoNPCuWKGKxdO3oiIdS8t47SslIJQ6TCQHQEx0CkGv1B4EHPybAouiJGSsTSw== +vue-styleguidist@^4.26.0: + version "4.26.0" + resolved "https://registry.yarnpkg.com/vue-styleguidist/-/vue-styleguidist-4.26.0.tgz#2e0be5a5bbbb276e0cfad1daffe0594ff7c25b23" + integrity sha512-/H/d47DMcCvSew88q3nXD+P5jlYvlBFqu162S9EqY4h3G1E1qaBXHxcKGAutJaEJNlWOWeNU8RrUmAau0Jb6Sw== dependencies: "@vxna/mini-html-webpack-template" "^1.0.0" ast-types "^0.13.2" @@ -14419,7 +14466,7 @@ vue-styleguidist@^4.25.0: style-loader "^1.0.0" terser-webpack-plugin "^2.2.2" to-ast "^1.0.0" - vue-docgen-api "^4.25.0" + vue-docgen-api "^4.26.0" vue-inbrowser-compiler "^4.23.3" vue-inbrowser-compiler-utils "^4.23.3" webpack-dev-server "^3.11.0" @@ -14546,9 +14593,9 @@ webpack-bundle-analyzer@^3.8.0: ws "^6.0.0" webpack-chain@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-6.4.0.tgz#22f0b27b6a9bc9ee3cba4f9e6513cf66394034e2" - integrity sha512-f97PYqxU+9/u0IUqp/ekAHRhBD1IQwhBv3wlJo2nvyELpr2vNnUqO3XQEk+qneg0uWGP54iciotszpjfnEExFA== + version "6.5.0" + resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-6.5.0.tgz#0b4af2094a5058a9ccd34b8f7ab194de4c83365f" + integrity sha512-K4EHiEg4WlP4w1rKXKpYWvX9cfGBERHCGP06ETSNV62XUIfOUg1DDRQpxyBsFYxZLKc4YUAI3iiCIvWoliheGA== dependencies: deepmerge "^1.5.2" javascript-stringify "^2.0.1" @@ -14706,9 +14753,9 @@ whatwg-fetch@2.0.4: integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== whatwg-fetch@>=0.10.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + version "3.1.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.1.0.tgz#49d630cdfa308dba7f2819d49d09364f540dbcc6" + integrity sha512-pgmbsVWKpH9GxLXZmtdowDIqtb/rvPyjjQv3z9wLcmgWKFHilKnZD3ldgrOlwJoPGOUluQsRPWd52yVkPfmI1A== whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" @@ -15003,6 +15050,13 @@ xmlchars@^2.1.1: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xregexp@^4.2.4: + version "4.3.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" + integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== + dependencies: + "@babel/runtime-corejs3" "^7.8.3" + xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -15054,7 +15108,7 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.1: +yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -15155,12 +15209,12 @@ yargs@^10.0.3: yargs-parser "^8.1.0" yargs@^15.0.0: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== + version "15.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.0.tgz#53949fb768309bac1843de9b17b80051e9805ec2" + integrity sha512-D3fRFnZwLWp8jVAAhPZBsmeIHY8tTsb8ItV9KaAaopmC6wde2u6Yw29JBIZHXw14kgkRnYmDgmQU4FVMDlIsWw== dependencies: cliui "^6.0.0" - decamelize "^1.2.0" + decamelize "^3.2.0" find-up "^4.1.0" get-caller-file "^2.0.1" require-directory "^2.1.1" @@ -15169,7 +15223,7 @@ yargs@^15.0.0: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" + yargs-parser "^18.1.2" yargs@^8.0.2: version "8.0.2" diff --git a/lib/graphql/resolvers/config.ex b/lib/graphql/resolvers/config.ex index 0e6aadf4f..21f536f7e 100644 --- a/lib/graphql/resolvers/config.ex +++ b/lib/graphql/resolvers/config.ex @@ -124,7 +124,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do }, rules: Config.instance_rules(), version: Config.instance_version(), - federating: Config.instance_federating() + federating: Config.instance_federating(), + auth: %{ + ldap: Config.ldap_enabled?(), + oauth_providers: Config.oauth_consumer_strategies() + } } end end diff --git a/lib/graphql/resolvers/person.ex b/lib/graphql/resolvers/person.ex index e6446f185..472d86669 100644 --- a/lib/graphql/resolvers/person.ex +++ b/lib/graphql/resolvers/person.ex @@ -202,10 +202,12 @@ defmodule Mobilizon.GraphQL.Resolvers.Person do """ def register_person(_parent, args, _resolution) do with {:ok, %User{} = user} <- Users.get_user_by_email(args.email), - {:no_actor, nil} <- {:no_actor, Users.get_actor_for_user(user)}, + user_actor <- Users.get_actor_for_user(user), + no_actor <- is_nil(user_actor), + {:no_actor, true} <- {:no_actor, no_actor}, args <- Map.put(args, :user_id, user.id), args <- save_attached_pictures(args), - {:ok, %Actor{} = new_person} <- Actors.new_person(args) do + {:ok, %Actor{} = new_person} <- Actors.new_person(args, true) do {:ok, new_person} else {:error, :user_not_found} -> diff --git a/lib/graphql/resolvers/user.ex b/lib/graphql/resolvers/user.ex index 7c2cd5ec4..b3043b97c 100644 --- a/lib/graphql/resolvers/user.ex +++ b/lib/graphql/resolvers/user.ex @@ -9,6 +9,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do alias Mobilizon.Actors.Actor alias Mobilizon.Crypto alias Mobilizon.Federation.ActivityPub + alias Mobilizon.Service.Auth.Authenticator alias Mobilizon.Storage.{Page, Repo} alias Mobilizon.Users.{Setting, User} @@ -59,18 +60,16 @@ defmodule Mobilizon.GraphQL.Resolvers.User do Login an user. Returns a token and the user """ def login_user(_parent, %{email: email, password: password}, _resolution) do - with {:ok, %User{confirmed_at: %DateTime{}} = user} <- Users.get_user_by_email(email), - {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- - Users.authenticate(%{user: user, password: password}) do - {:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}} - else - {:ok, %User{confirmed_at: nil} = _user} -> - {:error, "User account not confirmed"} + case Authenticator.authenticate(email, password) do + {:ok, + %{access_token: _access_token, refresh_token: _refresh_token, user: _user} = + user_and_tokens} -> + {:ok, user_and_tokens} {:error, :user_not_found} -> {:error, "No user with this email was found"} - {:error, :unauthorized} -> + {:error, _error} -> {:error, "Impossible to authenticate, either your email or password are invalid."} end end @@ -82,7 +81,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do with {:ok, user, _claims} <- Auth.Guardian.resource_from_token(refresh_token), {:ok, _old, {exchanged_token, _claims}} <- Auth.Guardian.exchange(refresh_token, ["access", "refresh"], "access"), - {:ok, refresh_token} <- Users.generate_refresh_token(user) do + {:ok, refresh_token} <- Authenticator.generate_refresh_token(user) do {:ok, %{access_token: exchanged_token, refresh_token: refresh_token}} else {:error, message} -> @@ -151,7 +150,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do {:check_confirmation_token, Email.User.check_confirmation_token(token)}, {:get_actor, actor} <- {:get_actor, Users.get_actor_for_user(user)}, {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- - Users.generate_tokens(user) do + Authenticator.generate_tokens(user) do {:ok, %{ access_token: access_token, @@ -192,10 +191,15 @@ defmodule Mobilizon.GraphQL.Resolvers.User do def send_reset_password(_parent, args, _resolution) do with email <- Map.get(args, :email), {:ok, %User{locale: locale} = user} <- Users.get_user_by_email(email, true), + {:can_reset_password, true} <- + {:can_reset_password, Authenticator.can_reset_password?(user)}, {:ok, %Bamboo.Email{} = _email_html} <- Email.User.send_password_reset_email(user, Map.get(args, :locale, locale)) do {:ok, email} else + {:can_reset_password, false} -> + {:error, "This user can't reset their password"} + {:error, :user_not_found} -> # TODO : implement rate limits for this endpoint {:error, "No user with this email was found"} @@ -209,10 +213,10 @@ defmodule Mobilizon.GraphQL.Resolvers.User do Reset the password from an user """ def reset_password(_parent, %{password: password, token: token}, _resolution) do - with {:ok, %User{} = user} <- + with {:ok, %User{email: email} = user} <- Email.User.check_reset_password_token(password, token), {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- - Users.authenticate(%{user: user, password: password}) do + Authenticator.authenticate(email, password) do {:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}} end end @@ -295,10 +299,12 @@ defmodule Mobilizon.GraphQL.Resolvers.User do def change_password( _parent, %{old_password: old_password, new_password: new_password}, - %{context: %{current_user: %User{password_hash: old_password_hash} = user}} + %{context: %{current_user: %User{} = user}} ) do - with {:current_password, true} <- - {:current_password, Argon2.verify_pass(old_password, old_password_hash)}, + with {:can_change_password, true} <- + {:can_change_password, Authenticator.can_change_password?(user)}, + {:current_password, {:ok, %User{}}} <- + {:current_password, Authenticator.login(user.email, old_password)}, {:same_password, false} <- {:same_password, old_password == new_password}, {:ok, %User{} = user} <- user @@ -306,7 +312,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do |> Repo.update() do {:ok, user} else - {:current_password, false} -> + {:current_password, _} -> {:error, "The current password is invalid"} {:same_password, true} -> @@ -323,10 +329,12 @@ defmodule Mobilizon.GraphQL.Resolvers.User do end def change_email(_parent, %{email: new_email, password: password}, %{ - context: %{current_user: %User{email: old_email, password_hash: password_hash} = user} + context: %{current_user: %User{email: old_email} = user} }) do - with {:current_password, true} <- - {:current_password, Argon2.verify_pass(password, password_hash)}, + with {:can_change_password, true} <- + {:can_change_password, Authenticator.can_change_email?(user)}, + {:current_password, {:ok, %User{}}} <- + {:current_password, Authenticator.login(user.email, password)}, {:same_email, false} <- {:same_email, new_email == old_email}, {:email_valid, true} <- {:email_valid, Email.Checker.valid?(new_email)}, {:ok, %User{} = user} <- @@ -347,7 +355,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do {:ok, user} else - {:current_password, false} -> + {:current_password, _} -> {:error, "The password provided is invalid"} {:same_email, true} -> @@ -377,14 +385,24 @@ defmodule Mobilizon.GraphQL.Resolvers.User do end end - def delete_account(_parent, %{password: password}, %{ - context: %{current_user: %User{password_hash: password_hash} = user} + def delete_account(_parent, args, %{ + context: %{current_user: %User{email: email} = user} }) do - case {:current_password, Argon2.verify_pass(password, password_hash)} do - {:current_password, true} -> + with {:user_has_password, true} <- {:user_has_password, Authenticator.has_password?(user)}, + {:confirmation_password, password} when not is_nil(password) <- + {:confirmation_password, Map.get(args, :password)}, + {:current_password, {:ok, _}} <- + {:current_password, Authenticator.authenticate(email, password)} do + do_delete_account(user) + else + # If the user hasn't got any password (3rd-party auth) + {:user_has_password, false} -> do_delete_account(user) - {:current_password, false} -> + {:confirmation_password, nil} -> + {:error, "The password provided is invalid"} + + {:current_password, _} -> {:error, "The password provided is invalid"} end end diff --git a/lib/graphql/schema/config.ex b/lib/graphql/schema/config.ex index b9cbf36da..e8070cbe6 100644 --- a/lib/graphql/schema/config.ex +++ b/lib/graphql/schema/config.ex @@ -39,6 +39,7 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do end field(:rules, :string, description: "The instance's rules") + field(:auth, :auth, description: "The instance auth methods") end object :terms do @@ -132,6 +133,16 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do field(:groups, :boolean) end + object :auth do + field(:ldap, :boolean, description: "Whether or not LDAP auth is enabled") + field(:oauth_providers, list_of(:oauth_provider), description: "List of oauth providers") + end + + object :oauth_provider do + field(:id, :string, description: "The provider ID") + field(:label, :string, description: "The label for the auth provider") + end + object :config_queries do @desc "Get the instance config" field :config, :config do diff --git a/lib/graphql/schema/user.ex b/lib/graphql/schema/user.ex index a41317b7d..511f94f45 100644 --- a/lib/graphql/schema/user.ex +++ b/lib/graphql/schema/user.ex @@ -52,6 +52,8 @@ defmodule Mobilizon.GraphQL.Schema.UserType do field(:locale, :string, description: "The user's locale") + field(:provider, :string, description: "The user's login provider") + field(:disabled, :boolean, description: "Whether the user is disabled") field(:participations, :paginated_participant_list, diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index 64dc74603..757b0eedc 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -13,6 +13,7 @@ defmodule Mobilizon.Actors do alias Mobilizon.Media.File alias Mobilizon.Service.Workers alias Mobilizon.Storage.{Page, Repo} + alias Mobilizon.Users alias Mobilizon.Federation.ActivityPub @@ -189,14 +190,19 @@ defmodule Mobilizon.Actors do Creates a new person actor. """ @spec new_person(map) :: {:ok, Actor.t()} | {:error, Ecto.Changeset.t()} - def new_person(args) do + def new_person(args, default_actor \\ false) do args = Map.put(args, :keys, Crypto.generate_rsa_2048_private_key()) - with {:ok, %Actor{} = person} <- + with {:ok, %Actor{id: person_id} = person} <- %Actor{} |> Actor.registration_changeset(args) |> Repo.insert() do - Events.create_feed_token(%{user_id: args["user_id"], actor_id: person.id}) + Events.create_feed_token(%{user_id: args.user_id, actor_id: person.id}) + + if default_actor do + user = Users.get_user!(args.user_id) + Users.update_user(user, %{default_actor_id: person_id}) + end {:ok, person} end diff --git a/lib/mobilizon/config.ex b/lib/mobilizon/config.ex index 2b8ab92ce..77e1ffadb 100644 --- a/lib/mobilizon/config.ex +++ b/lib/mobilizon/config.ex @@ -186,6 +186,24 @@ defmodule Mobilizon.Config do def anonymous_reporting?, do: Application.get_env(:mobilizon, :anonymous)[:reports][:allowed] + @spec oauth_consumer_strategies() :: list({atom(), String.t()}) + def oauth_consumer_strategies do + [:auth, :oauth_consumer_strategies] + |> get([]) + |> Enum.map(fn strategy -> + case strategy do + {id, label} when is_atom(id) -> %{id: id, label: label} + id when is_atom(id) -> %{id: id, label: nil} + end + end) + end + + @spec oauth_consumer_enabled? :: boolean() + def oauth_consumer_enabled?, do: oauth_consumer_strategies() != [] + + @spec ldap_enabled? :: boolean() + def ldap_enabled?, do: get([:ldap, :enabled], false) + def instance_resource_providers do types = get_in(Application.get_env(:mobilizon, Mobilizon.Service.ResourceProviders), [:types]) diff --git a/lib/mobilizon/users/user.ex b/lib/mobilizon/users/user.ex index 31a493a86..51b737626 100644 --- a/lib/mobilizon/users/user.ex +++ b/lib/mobilizon/users/user.ex @@ -40,14 +40,18 @@ defmodule Mobilizon.Users.User do :confirmation_token, :reset_password_sent_at, :reset_password_token, + :default_actor_id, :locale, :unconfirmed_email, - :disabled + :disabled, + :provider ] @attrs @required_attrs ++ @optional_attrs @registration_required_attrs @required_attrs ++ [:password] + @auth_provider_required_attrs @required_attrs ++ [:provider] + @password_change_required_attrs [:password] @password_reset_required_attrs @password_change_required_attrs ++ [:reset_password_token, :reset_password_sent_at] @@ -67,6 +71,7 @@ defmodule Mobilizon.Users.User do field(:unconfirmed_email, :string) field(:locale, :string, default: "en") field(:disabled, :boolean, default: false) + field(:provider, :string) belongs_to(:default_actor, Actor) has_many(:actors, Actor) @@ -116,6 +121,16 @@ defmodule Mobilizon.Users.User do ) end + @doc false + @spec auth_provider_changeset(t, map) :: Ecto.Changeset.t() + def auth_provider_changeset(%__MODULE__{} = user, attrs) do + user + |> changeset(attrs) + |> cast_assoc(:default_actor) + |> put_change(:confirmed_at, DateTime.utc_now() |> DateTime.truncate(:second)) + |> validate_required(@auth_provider_required_attrs) + end + @doc false @spec send_password_reset_changeset(t, map) :: Ecto.Changeset.t() def send_password_reset_changeset(%__MODULE__{} = user, attrs) do diff --git a/lib/mobilizon/users/users.ex b/lib/mobilizon/users/users.ex index 0ee54fd09..21bc20c9b 100644 --- a/lib/mobilizon/users/users.ex +++ b/lib/mobilizon/users/users.ex @@ -15,13 +15,6 @@ defmodule Mobilizon.Users do alias Mobilizon.Storage.{Page, Repo} alias Mobilizon.Users.{Setting, User} - alias Mobilizon.Web.Auth - - @type tokens :: %{ - required(:access_token) => String.t(), - required(:refresh_token) => String.t() - } - defenum(UserRole, :user_role, [:administrator, :moderator, :user]) defenum(NotificationPendingNotificationDelay, none: 0, direct: 1, one_hour: 5, one_day: 10) @@ -41,6 +34,18 @@ defmodule Mobilizon.Users do end end + @spec create_external(String.t(), String.t()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()} + def create_external(email, provider) do + with {:ok, %User{} = user} <- + %User{} + |> User.auth_provider_changeset(%{email: email, provider: provider}) + |> Repo.insert() do + Events.create_feed_token(%{user_id: user.id}) + + {:ok, user} + end + end + @doc """ Gets a single user. Raises `Ecto.NoResultsError` if the user does not exist. @@ -75,6 +80,16 @@ defmodule Mobilizon.Users do end end + @doc """ + Gets an user by its email. + """ + @spec get_user_by_email!(String.t(), boolean | nil) :: User.t() + def get_user_by_email!(email, activated \\ nil) do + email + |> user_by_email_query(activated) + |> Repo.one!() + end + @doc """ Get an user by its activation token. """ @@ -267,52 +282,6 @@ defmodule Mobilizon.Users do @spec count_users :: integer def count_users, do: Repo.one(from(u in User, select: count(u.id))) - @doc """ - Authenticate an user. - """ - @spec authenticate(User.t()) :: {:ok, tokens} | {:error, :unauthorized} - def authenticate(%{user: %User{password_hash: password_hash} = user, password: password}) do - # Does password match the one stored in the database? - if Argon2.verify_pass(password, password_hash) do - {:ok, _tokens} = generate_tokens(user) - else - {:error, :unauthorized} - end - end - - @doc """ - Generates access token and refresh token for an user. - """ - @spec generate_tokens(User.t()) :: {:ok, tokens} - def generate_tokens(user) do - with {:ok, access_token} <- generate_access_token(user), - {:ok, refresh_token} <- generate_refresh_token(user) do - {:ok, %{access_token: access_token, refresh_token: refresh_token}} - end - end - - @doc """ - Generates access token for an user. - """ - @spec generate_access_token(User.t()) :: {:ok, String.t()} - def generate_access_token(user) do - with {:ok, access_token, _claims} <- - Auth.Guardian.encode_and_sign(user, %{}, token_type: "access") do - {:ok, access_token} - end - end - - @doc """ - Generates refresh token for an user. - """ - @spec generate_refresh_token(User.t()) :: {:ok, String.t()} - def generate_refresh_token(user) do - with {:ok, refresh_token, _claims} <- - Auth.Guardian.encode_and_sign(user, %{}, token_type: "refresh") do - {:ok, refresh_token} - end - end - @doc """ Gets a settings for an user. diff --git a/lib/service/auth/authenticator.ex b/lib/service/auth/authenticator.ex new file mode 100644 index 000000000..15b8cec25 --- /dev/null +++ b/lib/service/auth/authenticator.ex @@ -0,0 +1,93 @@ +defmodule Mobilizon.Service.Auth.Authenticator do + @moduledoc """ + Module to handle authentification (currently through database or LDAP) + """ + alias Mobilizon.Users + alias Mobilizon.Users.User + alias Mobilizon.Web.Auth.Guardian + + @type tokens :: %{ + required(:access_token) => String.t(), + required(:refresh_token) => String.t() + } + + @type tokens_with_user :: %{ + required(:access_token) => String.t(), + required(:refresh_token) => String.t(), + required(:user) => User.t() + } + + def implementation do + Mobilizon.Config.get( + Mobilizon.Service.Auth.Authenticator, + Mobilizon.Service.Auth.MobilizonAuthenticator + ) + end + + @callback login(String.t(), String.t()) :: {:ok, User.t()} | {:error, any()} + @spec login(String.t(), String.t()) :: {:ok, User.t()} | {:error, any()} + def login(email, password), do: implementation().login(email, password) + + @callback can_change_email?(User.t()) :: boolean + def can_change_email?(%User{} = user), do: implementation().can_change_email?(user) + + @callback can_change_password?(User.t()) :: boolean + def can_change_password?(%User{} = user), do: implementation().can_change_password?(user) + + @spec has_password?(User.t()) :: boolean() + def has_password?(%User{provider: provider}), do: is_nil(provider) or provider == "ldap" + + @spec can_reset_password?(User.t()) :: boolean() + def can_reset_password?(%User{} = user), do: has_password?(user) && can_change_password?(user) + + @spec authenticate(String.t(), String.t()) :: {:ok, tokens_with_user()} + def authenticate(email, password) do + with {:ok, %User{} = user} <- login(email, password), + {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- + generate_tokens(user) do + {:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}} + end + end + + @doc """ + Generates access token and refresh token for an user. + """ + @spec generate_tokens(User.t()) :: {:ok, tokens} + def generate_tokens(user) do + with {:ok, access_token} <- generate_access_token(user), + {:ok, refresh_token} <- generate_refresh_token(user) do + {:ok, %{access_token: access_token, refresh_token: refresh_token}} + end + end + + @doc """ + Generates access token for an user. + """ + @spec generate_access_token(User.t()) :: {:ok, String.t()} + def generate_access_token(user) do + with {:ok, access_token, _claims} <- + Guardian.encode_and_sign(user, %{}, token_type: "access") do + {:ok, access_token} + end + end + + @doc """ + Generates refresh token for an user. + """ + @spec generate_refresh_token(User.t()) :: {:ok, String.t()} + def generate_refresh_token(user) do + with {:ok, refresh_token, _claims} <- + Guardian.encode_and_sign(user, %{}, token_type: "refresh") do + {:ok, refresh_token} + end + end + + @spec fetch_user(String.t()) :: User.t() | {:error, :user_not_found} + def fetch_user(nil), do: {:error, :user_not_found} + + def fetch_user(email) when not is_nil(email) do + with {:ok, %User{} = user} <- Users.get_user_by_email(email, true) do + user + end + end +end diff --git a/lib/service/auth/ldap_authenticator.ex b/lib/service/auth/ldap_authenticator.ex new file mode 100644 index 000000000..6db154376 --- /dev/null +++ b/lib/service/auth/ldap_authenticator.ex @@ -0,0 +1,180 @@ +# Portions of this file are derived from Pleroma: +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mobilizon.Service.Auth.LDAPAuthenticator do + @moduledoc """ + Authenticate Mobilizon users through LDAP accounts + """ + alias Mobilizon.Service.Auth.{Authenticator, MobilizonAuthenticator} + alias Mobilizon.Users + alias Mobilizon.Users.User + + require Logger + + import Authenticator, + only: [fetch_user: 1] + + @behaviour Authenticator + @base MobilizonAuthenticator + + @connection_timeout 10_000 + @search_timeout 10_000 + + def login(email, password) do + with {:ldap, true} <- {:ldap, Mobilizon.Config.get([:ldap, :enabled])}, + %User{} = user <- ldap_user(email, password) do + {:ok, user} + else + {:error, {:ldap_connection_error, _}} -> + # When LDAP is unavailable, try default authenticator + @base.login(email, password) + + {:ldap, _} -> + @base.login(email, password) + + error -> + error + end + end + + def can_change_email?(%User{provider: provider}), do: provider != "ldap" + + def can_change_password?(%User{provider: provider}), do: provider != "ldap" + + defp ldap_user(email, password) do + ldap = Mobilizon.Config.get(:ldap, []) + host = Keyword.get(ldap, :host, "localhost") + port = Keyword.get(ldap, :port, 389) + ssl = Keyword.get(ldap, :ssl, false) + sslopts = Keyword.get(ldap, :sslopts, []) + + options = + [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++ + if sslopts != [], do: [{:sslopts, sslopts}], else: [] + + case :eldap.open([to_charlist(host)], options) do + {:ok, connection} -> + try do + ensure_eventual_tls(connection, ldap) + + base = Keyword.get(ldap, :base) + uid_field = Keyword.get(ldap, :uid, "cn") + + # We first need to find the LDAP UID/CN for this specif email + with uid when is_binary(uid) <- search_user(connection, ldap, base, uid_field, email), + # Then we can verify the user's password + :ok <- bind_user(connection, base, uid_field, uid, password) do + case fetch_user(email) do + %User{} = user -> + user + + _ -> + register_user(email) + end + else + {:error, error} -> + {:error, error} + + error -> + {:error, error} + end + after + :eldap.close(connection) + end + + {:error, error} -> + Logger.error("Could not open LDAP connection: #{inspect(error)}") + {:error, {:ldap_connection_error, error}} + end + end + + @spec bind_user(any(), String.t(), String.t(), String.t(), String.t()) :: + User.t() | any() + defp bind_user(connection, base, uid, field, password) do + bind = "#{uid}=#{field},#{base}" + Logger.debug("Binding to LDAP with \"#{bind}\"") + :eldap.simple_bind(connection, bind, password) + end + + @spec search_user(any(), Keyword.t(), String.t(), String.t(), String.t()) :: + String.t() | {:error, :ldap_registration_missing_attributes} | any() + defp search_user(connection, ldap, base, uid, email) do + # We may need to bind before performing the search + res = + if Keyword.get(ldap, :require_bind_for_search, true) do + admin_field = Keyword.get(ldap, :bind_uid) + admin_password = Keyword.get(ldap, :bind_password) + bind_user(connection, base, uid, admin_field, admin_password) + else + :ok + end + + if res == :ok do + do_search_user(connection, base, uid, email) + else + res + end + end + + # Search an user by uid to find their CN + @spec do_search_user(any(), String.t(), String.t(), String.t()) :: + String.t() | {:error, :ldap_registration_missing_attributes} | any() + defp do_search_user(connection, base, uid, email) do + with {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} <- + :eldap.search(connection, [ + {:base, to_charlist(base)}, + {:filter, :eldap.equalityMatch(to_charlist("mail"), to_charlist(email))}, + {:scope, :eldap.wholeSubtree()}, + {:attributes, [to_charlist(uid)]}, + {:timeout, @search_timeout} + ]), + {:uid, {_, [uid]}} <- {:uid, List.keyfind(attributes, to_charlist(uid), 0)} do + :erlang.list_to_binary(uid) + else + {:ok, {:eldap_search_result, [], []}} -> + Logger.info("Unable to find user with email #{email}") + {:error, :ldap_search_email_not_found} + + {:cn, err} -> + Logger.error("Could not find LDAP attribute CN: #{inspect(err)}") + {:error, :ldap_searcy_missing_attributes} + + error -> + error + end + end + + @spec register_user(String.t()) :: User.t() | any() + defp register_user(email) do + case Users.create_external(email, "ldap") do + {:ok, %User{} = user} -> + user + + error -> + error + end + end + + @spec ensure_eventual_tls(any(), Keyword.t()) :: :ok + defp ensure_eventual_tls(connection, ldap) do + if Keyword.get(ldap, :tls, false) do + :application.ensure_all_started(:ssl) + + case :eldap.start_tls( + connection, + Keyword.get(ldap, :tlsopts, []), + @connection_timeout + ) do + :ok -> + :ok + + error -> + Logger.error("Could not start TLS: #{inspect(error)}") + end + end + + :ok + end +end diff --git a/lib/service/auth/mobilizon_authenticator.ex b/lib/service/auth/mobilizon_authenticator.ex new file mode 100644 index 000000000..bec126901 --- /dev/null +++ b/lib/service/auth/mobilizon_authenticator.ex @@ -0,0 +1,39 @@ +defmodule Mobilizon.Service.Auth.MobilizonAuthenticator do + @moduledoc """ + Authenticate Mobilizon users through database accounts + """ + alias Mobilizon.Users.User + + alias Mobilizon.Service.Auth.Authenticator + + import Authenticator, + only: [fetch_user: 1] + + @behaviour Authenticator + + def login(email, password) do + require Logger + + with {:user, %User{password_hash: password_hash, provider: nil} = user} + when not is_nil(password_hash) <- + {:user, fetch_user(email)}, + {:acceptable_password, true} <- + {:acceptable_password, not (is_nil(password) || password == "")}, + {:checkpw, true} <- {:checkpw, Argon2.verify_pass(password, password_hash)} do + {:ok, user} + else + {:user, {:error, :user_not_found}} -> + {:error, :user_not_found} + + {:acceptable_password, false} -> + {:error, :bad_password} + + {:checkpw, false} -> + {:error, :bad_password} + end + end + + def can_change_email?(%User{provider: provider}), do: is_nil(provider) + + def can_change_password?(%User{provider: provider}), do: is_nil(provider) +end diff --git a/lib/web/controllers/auth_controller.ex b/lib/web/controllers/auth_controller.ex new file mode 100644 index 000000000..9e6c9d62c --- /dev/null +++ b/lib/web/controllers/auth_controller.ex @@ -0,0 +1,82 @@ +defmodule Mobilizon.Web.AuthController do + use Mobilizon.Web, :controller + + alias Mobilizon.Service.Auth.Authenticator + alias Mobilizon.Users + alias Mobilizon.Users.User + require Logger + plug(:put_layout, false) + + plug(Ueberauth) + + def request(conn, %{"provider" => provider} = _params) do + redirect(conn, to: "/login?code=Login Provider not found&provider=#{provider}") + end + + def callback( + %{assigns: %{ueberauth_failure: fails}} = conn, + %{"provider" => provider} = _params + ) do + Logger.warn("Unable to login user with #{provider} #{inspect(fails)}") + + redirect(conn, to: "/login?code=Error with Login Provider&provider=#{provider}") + end + + def callback( + %{assigns: %{ueberauth_auth: %Ueberauth.Auth{strategy: strategy} = auth}} = conn, + _params + ) do + email = email_from_ueberauth(auth) + [_, _, _, strategy] = strategy |> to_string() |> String.split(".") + strategy = String.downcase(strategy) + + user = + with {:valid_email, false} <- {:valid_email, is_nil(email) or email == ""}, + {:error, :user_not_found} <- Users.get_user_by_email(email), + {:ok, %User{} = user} <- Users.create_external(email, strategy) do + user + else + {:ok, %User{} = user} -> + user + + {:error, error} -> + {:error, error} + + error -> + {:error, error} + end + + with %User{} = user <- user, + {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- + Authenticator.generate_tokens(user) do + Logger.info("Logged-in user \"#{email}\" through #{strategy}") + + render(conn, "callback.html", %{ + access_token: access_token, + refresh_token: refresh_token, + user: user + }) + else + err -> + Logger.warn("Unable to login user \"#{email}\" #{inspect(err)}") + redirect(conn, to: "/login?code=Error with Login Provider&provider=#{strategy}") + end + end + + # Github only give public emails as part of the user profile, + # so we explicitely request all user emails and filter on the primary one + defp email_from_ueberauth(%Ueberauth.Auth{ + strategy: Ueberauth.Strategy.Github, + extra: %Ueberauth.Auth.Extra{raw_info: %{user: %{"emails" => emails}}} + }) + when length(emails) > 0, + do: emails |> Enum.find(& &1["primary"]) |> (& &1["email"]).() + + defp email_from_ueberauth(%Ueberauth.Auth{ + extra: %Ueberauth.Auth.Extra{raw_info: %{user: %{"email" => email}}} + }) + when not is_nil(email) and email != "", + do: email + + defp email_from_ueberauth(_), do: nil +end diff --git a/lib/web/router.ex b/lib/web/router.ex index d7a565186..725afa2d8 100644 --- a/lib/web/router.ex +++ b/lib/web/router.ex @@ -150,6 +150,10 @@ defmodule Mobilizon.Web.Router do get("/groups/me", PageController, :index, as: "my_groups") get("/interact", PageController, :interact) + + get("/auth/:provider", AuthController, :request) + get("/auth/:provider/callback", AuthController, :callback) + post("/auth/:provider/callback", AuthController, :callback) end scope "/proxy/", Mobilizon.Web do diff --git a/lib/web/views/auth_view.ex b/lib/web/views/auth_view.ex new file mode 100644 index 000000000..1f94a3407 --- /dev/null +++ b/lib/web/views/auth_view.ex @@ -0,0 +1,29 @@ +defmodule Mobilizon.Web.AuthView do + @moduledoc """ + View for the auth routes + """ + + use Mobilizon.Web, :view + alias Mobilizon.Service.Metadata.Instance + alias Phoenix.HTML.Tag + import Mobilizon.Web.Views.Utils + + def render("callback.html", %{ + conn: conn, + access_token: access_token, + refresh_token: refresh_token, + user: %{id: user_id, email: user_email, role: user_role, default_actor_id: user_actor_id} + }) do + info_tags = [ + Tag.tag(:meta, name: "auth-access-token", content: access_token), + Tag.tag(:meta, name: "auth-refresh-token", content: refresh_token), + Tag.tag(:meta, name: "auth-user-id", content: user_id), + Tag.tag(:meta, name: "auth-user-email", content: user_email), + Tag.tag(:meta, name: "auth-user-role", content: user_role), + Tag.tag(:meta, name: "auth-user-actor-id", content: user_actor_id) + ] + + tags = Instance.build_tags() ++ info_tags + inject_tags(tags, get_locale(conn)) + end +end diff --git a/mix.exs b/mix.exs index 745298465..1fb048c12 100644 --- a/mix.exs +++ b/mix.exs @@ -46,6 +46,23 @@ defmodule Mobilizon.Mixfile do defp elixirc_paths(:dev), do: ["lib", "test/support/factory.ex"] defp elixirc_paths(_), do: ["lib"] + # Specifies OAuth dependencies. + defp oauth_deps do + oauth_strategy_packages = + System.get_env("OAUTH_CONSUMER_STRATEGIES") + |> to_string() + |> String.split() + |> Enum.map(fn strategy_entry -> + with [_strategy, dependency] <- String.split(strategy_entry, ":") do + dependency + else + [strategy] -> "ueberauth_#{strategy}" + end + end) + + for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"} + end + # Specifies your project dependencies. # # Type `mix help deps` for examples and options. @@ -81,7 +98,7 @@ defmodule Mobilizon.Mixfile do {:bamboo_smtp, "~> 2.0"}, {:geolix, "~> 1.0"}, {:geolix_adapter_mmdb2, "~> 0.5.0"}, - {:absinthe, "~> 1.5.1"}, + {:absinthe, "~> 1.5.2"}, {:absinthe_phoenix, "~> 2.0.0"}, {:absinthe_plug, "~> 1.5.0"}, {:dataloader, "~> 1.0.6"}, @@ -104,6 +121,16 @@ defmodule Mobilizon.Mixfile do {:floki, "~> 0.26.0"}, {:ip_reserved, "~> 0.1.0"}, {:fast_sanitize, "~> 0.1"}, + {:ueberauth, "~> 0.6"}, + {:ueberauth_twitter, "~> 0.3"}, + {:ueberauth_github, "~> 0.7"}, + {:ueberauth_facebook, "~> 0.8"}, + {:ueberauth_discord, "~> 0.5"}, + {:ueberauth_google, "~> 0.9"}, + {:ueberauth_keycloak_strategy, + git: "https://github.com/tcitworld/ueberauth_keycloak.git", branch: "upgrade-deps"}, + {:ueberauth_gitlab_strategy, + git: "https://github.com/tcitworld/ueberauth_gitlab.git", branch: "upgrade-deps"}, # Dev and test dependencies {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]}, {:ex_machina, "~> 2.3", only: [:dev, :test]}, @@ -116,7 +143,7 @@ defmodule Mobilizon.Mixfile do {:credo, "~> 1.4.0", only: [:dev, :test], runtime: false}, {:mock, "~> 0.3.4", only: :test}, {:elixir_feed_parser, "~> 2.1.0", only: :test} - ] + ] ++ oauth_deps() end # Aliases are shortcuts or tasks specific to the current project. diff --git a/mix.lock b/mix.lock index 13a34361a..9445c84ab 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "absinthe": {:hex, :absinthe, "1.5.1", "2f462f5849b2a4f72889d5a131ca6760b47ca8c5de2ba21c1dca3889634f2277", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b264eeb69605c6012f563e240edcca3d8abc5a725cab6f58ad82510a0283618b"}, + "absinthe": {:hex, :absinthe, "1.5.2", "2f9449b0c135ea61c09c11968d3d4fe6abd5bed38cf9be1c6d6b7c5ec858cfa0", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "669c84879629b7fffdc6cda9361ab9c81c9c7691e65418ba089b912a227963ac"}, "absinthe_ecto": {:hex, :absinthe_ecto, "0.1.3", "420b68129e79fe4571a4838904ba03e282330d335da47729ad52ffd7b8c5fcb1", [:mix], [{:absinthe, "~> 1.3.0 or ~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "355b9db34abfab96ae1e025434b66e11002babcf4fe6b7144d26ff7548985f52"}, "absinthe_phoenix": {:hex, :absinthe_phoenix, "2.0.0", "01c6a90af0ca12ee08d0fb93e23f9890d75bb6d3027f49ee4383bc03058ef5c3", [:mix], [{:absinthe, "~> 1.5.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.5.0", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.5", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "7ffbfe9fb82a14cafb78885cc2cef4f9d454bbbe2c95eec12b5463f5a20d1020"}, "absinthe_plug": {:hex, :absinthe_plug, "1.5.0", "018ef544cf577339018d1f482404b4bed762e1b530c78be9de4bbb88a6f3a805", [:mix], [{:absinthe, "~> 1.5.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "4c160f4ce9a1233a4219a42de946e4e05d0e8733537cd5d8d20e7d4ef8d4b7c7"}, @@ -23,7 +23,8 @@ "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"}, "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"}, - "earmark": {:hex, :earmark, "1.4.5", "62ffd3bd7722fb7a7b1ecd2419ea0b458c356e7168c1f5d65caf09b4fbdd13c8", [:mix], [], "hexpm", "b7d0e6263d83dc27141a523467799a685965bf8b13b6743413f19a7079843f4f"}, + "earmark": {:hex, :earmark, "1.4.9", "837e4c1c5302b3135e9955f2bbf52c6c52e950c383983942b68b03909356c0d9", [:mix], [{:earmark_parser, ">= 1.4.9", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "0d72df7d13a3dc8422882bed5263fdec5a773f56f7baeb02379361cb9e5b0d8e"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.9", "819bda2049e6ee1365424e4ced1ba65806eacf0d2867415f19f3f80047f8037b", [:mix], [], "hexpm", "8bf54fddabf2d7e137a0c22660e71b49d5a0a82d1fb05b5af62f2761cd6485c4"}, "ecto": {:hex, :ecto, "3.4.5", "2bcd262f57b2c888b0bd7f7a28c8a48aa11dc1a2c6a858e45dd8f8426d504265", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8c6d1d4d524559e9b7a062f0498e2c206122552d63eacff0a6567ffe7a8e8691"}, "ecto_autoslug_field": {:hex, :ecto_autoslug_field, "2.0.1", "2177c1c253f6dd3efd4b56d1cb76104d0a6ef044c6b9a7a0ad6d32665c4111e5", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "a3cc73211f2e75b89a03332183812ebe1ac08be2e25a1df5aa3d1422f92c45c3"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, @@ -31,12 +32,13 @@ "elixir_feed_parser": {:hex, :elixir_feed_parser, "2.1.0", "bb96fb6422158dc7ad59de62ef211cc69d264acbbe63941a64a5dce97bbbc2e6", [:mix], [{:timex, "~> 3.4", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "2d3c62fe7b396ee3b73d7160bc8fadbd78bfe9597c98c7d79b3f1038d9cba28f"}, "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "esaml": {:git, "git://github.com/wrren/esaml.git", "2cace5778e4323216bcff2085ca9739e42a68a42", [branch: "ueberauth_saml"]}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, "ex_cldr": {:hex, :ex_cldr, "2.16.1", "905b03c38b5fb51668a347f2e6b586bcb2c0816cd98f7d913104872c43cbc61f", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.9", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "006e500769982e57e6f3e32cbc4664345f78b014bb5ff48ddc394d67c86c1a8d"}, "ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.9.0", "ace1c57ba3850753c9ac6ddb89dc0c9a9e5e1c57ecad587e21c8925ad30a3838", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.13", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.0", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a4b07773e2a326474f44a6bc51fffbec634859a1bad5cc6e6eb55eba45115541"}, "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.5.0", "e369ae3c1cd5cd20aa20988b153fd2902b4ab08aec63ca8757d7104bdb79f867", [:mix], [{:ex_cldr, "~> 2.14", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ba16b1df60bcec52c986481bbdfa7cfaec899b610f869d2b3c5a9a8149f67668"}, "ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.5.1", "9439d1c40cfd03c3d8f3f60f5d3e3f2c6eaf0fd714541d687531cce78cfb9909", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.8", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.15", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "62a2f8d41ec6e789137bbf3ac7c944885a8ef6b7ce475905d056d1805b482427"}, - "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.15.0", "207843c6ddae802a2b5fd43eb95c4b65eae8a0a876ce23ae4413eb098b222977", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.15", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.5", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "3c6c220e03590f08e2f3cb4f3e0c2e1a78fe56a12229331edb952cbdc67935e1"}, + "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.15.1", "dced7ffee69c4830593258b69b294adb4c65cf539e1d8ae0a4de31cfc8aa56a0", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.15", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.5", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "c6a4b69ef80b8ffbb6c8fb69a2b365ba542580e0f76a15d8c6ee9142bd1b97ea"}, "ex_crypto": {:hex, :ex_crypto, "0.10.0", "af600a89b784b36613a989da6e998c1b200ff1214c3cfbaf8deca4aa2f0a1739", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "ccc7472cfe8a0f4565f97dce7e9280119bf15a5ea51c6535e5b65f00660cde1c"}, "ex_doc": {:hex, :ex_doc, "0.22.1", "9bb6d51508778193a4ea90fa16eac47f8b67934f33f8271d5e1edec2dc0eee4c", [:mix], [{:earmark, "~> 1.4.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "d957de1b75cb9f78d3ee17820733dc4460114d8b1e11f7ee4fd6546e69b1db60"}, "ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "db76473b2ae0259e6633c6c479a5a4d8603f09497f55c88f9ef4d53d2b75befb"}, @@ -91,7 +93,10 @@ "mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"}, "mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"}, "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, + "oauth2": {:hex, :oauth2, "2.0.0", "338382079fe16c514420fa218b0903f8ad2d4bfc0ad0c9f988867dfa246731b0", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "881b8364ac7385f9fddc7949379cbe3f7081da37233a1aa7aab844670a91e7e7"}, + "oauther": {:hex, :oauther, "1.1.1", "7d8b16167bb587ecbcddd3f8792beb9ec3e7b65c1f8ebd86b8dd25318d535752", [:mix], [], "hexpm", "9374f4302045321874cccdc57eb975893643bd69c3b22bf1312dab5f06e5788e"}, "oban": {:hex, :oban, "1.2.0", "7cca94d341be43d220571e28f69131c4afc21095b25257397f50973d3fc59b07", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ba5f8b3f7d76967b3e23cf8014f6a13e4ccb33431e4808f036709a7f822362ee"}, + "paddle": {:hex, :paddle, "0.1.4", "3697996d79e3d771d6f7560a23e4bad1ed7b7f7fd3e784f97bc39565963b2b13", [:mix], [], "hexpm", "fc719a9e7c86f319b9f4bf413d6f0f326b0c4930d5bc6630d074598ed38e2143"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, "phoenix": {:hex, :phoenix, "1.5.3", "bfe0404e48ea03dfe17f141eff34e1e058a23f15f109885bbdcf62be303b49ff", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8e16febeb9640d8b33895a691a56481464b82836d338bb3a23125cd7b6157c25"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"}, @@ -110,10 +115,21 @@ "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"}, "slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"}, + "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, "timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"}, "tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"}, + "ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"}, + "ueberauth_discord": {:hex, :ueberauth_discord, "0.5.0", "52421277b93fda769b51636e542b5085f3861efdc7fa48ac4bedb6dae0b645e1", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6.3", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "9a3808baf44297e26bd5042ba9ea5398aa60023e054eb9a5ac8a4eacd0467a78"}, + "ueberauth_facebook": {:hex, :ueberauth_facebook, "0.8.1", "c254be4ab367c276773c2e41d3c0fe343ae118e244afc8d5a4e3e5c438951fdc", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "c2cf210ef45bd20611234ef17517f9d1dff6b31d3fb6ad96789143eb0943f540"}, + "ueberauth_github": {:hex, :ueberauth_github, "0.8.0", "2216c8cdacee0de6245b422fb397921b64a29416526985304e345dab6a799d17", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "b65ccc001a7b0719ba069452f3333d68891f4613ae787a340cce31e2a43307a3"}, + "ueberauth_gitlab_strategy": {:git, "https://github.com/tcitworld/ueberauth_gitlab.git", "9fc5d30b5d87ff7cdef293a1c128f25777dcbe59", [branch: "upgrade-deps"]}, + "ueberauth_google": {:hex, :ueberauth_google, "0.9.0", "e098e1d6df647696b858b0289eae7e4dc8c662abee9e309d64bc115192c51bf5", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "5453ba074df7ee14fb5b121bb04a64cda5266cd23b28af8a2fdf02dd40959ab4"}, + "ueberauth_keycloak": {:git, "https://github.com/tcitworld/ueberauth_keycloak.git", "02447d8a75bd36ba26c17c7b1b8bab3538bb2e7a", [branch: "upgrade-deps"]}, + "ueberauth_keycloak_strategy": {:git, "https://github.com/tcitworld/ueberauth_keycloak.git", "d892f0f9daf9e0023319b69ac2f7c2c6edff2b14", [branch: "upgrade-deps"]}, + "ueberauth_saml": {:git, "https://github.com/wrren/ueberauth_saml.git", "dfcb4ae3f509afec0f442ce455c41feacac24511", []}, + "ueberauth_twitter": {:hex, :ueberauth_twitter, "0.4.0", "4b98620341bc91bac90459093bba093c650823b6e2df35b70255c493c17e9227", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "fb29c9047ca263038c0c61f5a0ec8597e8564aba3f2b4cb02704b60205fd4468"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"}, "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, + "uuid": {:git, "git://github.com/botsunit/erlang-uuid", "1effbbbd200f9f5d9d5154e81b83fe8e4c3fe714", [branch: "master"]}, "xml_builder": {:hex, :xml_builder, "2.0.0", "371ed27bb63bf0598dbaf3f0c466e5dc7d16cb4ecb68f06a67f953654062e21b", [:mix], [], "hexpm", "baeb5c8d42204bac2b856ffd50e8cda42d63b622984538d18d92733e4e790fbd"}, } diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 6f944ba9d..dbbd40d98 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -1177,12 +1177,12 @@ msgstr "If you didn't request this, please ignore this email." #, elixir-format, fuzzy #: lib/web/templates/email/email.text.eex:10 msgid "In the meantime, please consider this the software as not (yet) finished. Read more on the Framasoft blog:" -msgstr "In the meantime, please consider that the software is not (yet) finished. More information %{a_start}on our blog%{a_end}." +msgstr "In the meantime, please consider that the software is not (yet) finished. More information on our blog." #, elixir-format, fuzzy #: lib/web/templates/email/email.text.eex:9 msgid "Mobilizon is still under development, we will add new features along the updates, until the release of version 1 of the software in the fall of 2020." -msgstr "Mobilizon is under development, we will add new features to this site during regular updates, until the release of %{b_start}version 1 of the software in the first half of 2020%{b_end}." +msgstr "Mobilizon is under development, we will add new features to this site during regular updates, until the release of version 1 of the software in the first half of 2020." #, elixir-format, fuzzy #: lib/web/templates/email/email.text.eex:7 diff --git a/priv/repo/migrations/20200630123819_add_provider_to_user_and_make_password_mandatory.exs b/priv/repo/migrations/20200630123819_add_provider_to_user_and_make_password_mandatory.exs new file mode 100644 index 000000000..3eb536019 --- /dev/null +++ b/priv/repo/migrations/20200630123819_add_provider_to_user_and_make_password_mandatory.exs @@ -0,0 +1,17 @@ +defmodule Mobilizon.Storage.Repo.Migrations.AddProviderToUserAndMakePasswordMandatory do + use Ecto.Migration + + def up do + alter table(:users) do + add(:provider, :string, null: true) + modify(:password_hash, :string, null: true) + end + end + + def down do + alter table(:users) do + remove(:provider) + modify(:password_hash, :string, null: false) + end + end +end diff --git a/test/graphql/resolvers/participant_test.exs b/test/graphql/resolvers/participant_test.exs index 5d12cab22..3290c9f1d 100644 --- a/test/graphql/resolvers/participant_test.exs +++ b/test/graphql/resolvers/participant_test.exs @@ -991,7 +991,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do } """ - clear_config([:anonymous, :participation]) + setup do: clear_config([:anonymous, :participation]) setup %{conn: conn, actor: actor, user: user} do Mobilizon.Config.clear_config_cache() diff --git a/test/graphql/resolvers/report_test.exs b/test/graphql/resolvers/report_test.exs index 7f7e209ec..7063f3197 100644 --- a/test/graphql/resolvers/report_test.exs +++ b/test/graphql/resolvers/report_test.exs @@ -33,7 +33,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ReportTest do } """ - clear_config([:anonymous, :reports]) + setup do: clear_config([:anonymous, :reports]) setup %{conn: conn} do Mobilizon.Config.clear_config_cache() diff --git a/test/graphql/resolvers/user_test.exs b/test/graphql/resolvers/user_test.exs index 9e8fc06cc..477e9fed3 100644 --- a/test/graphql/resolvers/user_test.exs +++ b/test/graphql/resolvers/user_test.exs @@ -9,6 +9,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do alias Mobilizon.Actors.Actor alias Mobilizon.Conversations.Comment alias Mobilizon.Events.{Event, Participant} + alias Mobilizon.Service.Auth.Authenticator alias Mobilizon.Users.User alias Mobilizon.GraphQL.AbsintheHelpers @@ -45,8 +46,14 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do } """ + @send_reset_password_mutation """ + mutation SendResetPassword($email: String!) { + sendResetPassword(email: $email) + } + """ + @delete_user_account_mutation """ - mutation DeleteAccount($password: String!) { + mutation DeleteAccount($password: String) { deleteAccount (password: $password) { id } @@ -712,45 +719,50 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do end describe "Resolver: Send reset password" do - test "test send_reset_password/3 with valid email", context do - user = insert(:user) - - mutation = """ - mutation { - sendResetPassword( - email: "#{user.email}" - ) - } - """ + test "test send_reset_password/3 with valid email", %{conn: conn} do + %User{email: email} = insert(:user) res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @send_reset_password_mutation, + variables: %{email: email} + ) - assert json_response(res, 200)["data"]["sendResetPassword"] == user.email + assert res["data"]["sendResetPassword"] == email end - test "test send_reset_password/3 with invalid email", context do - mutation = """ - mutation { - sendResetPassword( - email: "oh no" - ) - } - """ + test "test send_reset_password/3 with invalid email", %{conn: conn} do + res = + conn + |> AbsintheHelpers.graphql_query( + query: @send_reset_password_mutation, + variables: %{email: "not an email"} + ) + + assert hd(res["errors"])["message"] == + "No user with this email was found" + end + + test "test send_reset_password/3 for an LDAP user", %{conn: conn} do + {:ok, %User{email: email}} = Users.create_external("some@users.com", "ldap") res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @send_reset_password_mutation, + variables: %{email: email} + ) - assert hd(json_response(res, 200)["errors"])["message"] == - "No user with this email was found" + assert hd(res["errors"])["message"] == + "This user can't reset their password" end end describe "Resolver: Reset user's password" do test "test reset_password/3 with valid email", context do {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"}) + Users.update_user(user, %{confirmed_at: DateTime.utc_now()}) %Actor{} = insert(:actor, user: user) {:ok, _email_sent} = Email.User.send_password_reset_email(user) %User{reset_password_token: reset_password_token} = Users.get_user!(user.id) @@ -772,6 +784,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do context.conn |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + assert is_nil(json_response(res, 200)["errors"]) assert json_response(res, 200)["data"]["resetPassword"]["user"]["id"] == to_string(user.id) end @@ -829,7 +842,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do end describe "Resolver: Login a user" do - test "test login_user/3 with valid credentials", context do + test "test login_user/3 with valid credentials", %{conn: conn} do {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"}) {:ok, %User{} = _user} = @@ -839,30 +852,18 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do "confirmation_token" => nil }) - mutation = """ - mutation { - login( - email: "#{user.email}", - password: "#{user.password}", - ) { - accessToken, - refreshToken, - user { - id - } - } - } - """ - res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user.password} + ) - assert login = json_response(res, 200)["data"]["login"] + assert login = res["data"]["login"] assert Map.has_key?(login, "accessToken") && not is_nil(login["accessToken"]) end - test "test login_user/3 with invalid password", context do + test "test login_user/3 with invalid password", %{conn: conn} do {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"}) {:ok, %User{} = _user} = @@ -872,79 +873,40 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do "confirmation_token" => nil }) - mutation = """ - mutation { - login( - email: "#{user.email}", - password: "bad password", - ) { - accessToken, - user { - default_actor { - preferred_username, - } - } - } - } - """ - res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: "bad password"} + ) - assert hd(json_response(res, 200)["errors"])["message"] == + assert hd(res["errors"])["message"] == "Impossible to authenticate, either your email or password are invalid." end - test "test login_user/3 with invalid email", context do - mutation = """ - mutation { - login( - email: "bad email", - password: "bad password", - ) { - accessToken, - user { - default_actor { - preferred_username, - } - } - } - } - """ - + test "test login_user/3 with invalid email", %{conn: conn} do res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: "bad email", password: "bad password"} + ) - assert hd(json_response(res, 200)["errors"])["message"] == + assert hd(res["errors"])["message"] == "No user with this email was found" end - test "test login_user/3 with unconfirmed user", context do + test "test login_user/3 with unconfirmed user", %{conn: conn} do {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"}) - mutation = """ - mutation { - login( - email: "#{user.email}", - password: "#{user.password}", - ) { - accessToken, - user { - default_actor { - preferred_username, - } - } - } - } - """ - res = - context.conn - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user.password} + ) - assert hd(json_response(res, 200)["errors"])["message"] == "User account not confirmed" + assert hd(res["errors"])["message"] == "No user with this email was found" end end @@ -970,7 +932,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do test "test refresh_token/3 with an appropriate token", context do user = insert(:user) - {:ok, refresh_token} = Users.generate_refresh_token(user) + {:ok, refresh_token} = Authenticator.generate_refresh_token(user) mutation = """ mutation { @@ -1441,6 +1403,18 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do assert is_nil(Events.get_participant(participant_id)) end + test "delete_account/3 with 3rd-party auth login", %{conn: conn} do + {:ok, %User{} = user} = Users.create_external(@email, "keycloak") + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query(query: @delete_user_account_mutation) + + assert is_nil(res["errors"]) + assert res["data"]["deleteAccount"]["id"] == to_string(user.id) + end + test "delete_account/3 with invalid password", %{conn: conn} do {:ok, %User{} = user} = Users.register(%{email: @email, password: @password}) diff --git a/test/mobilizon/users/users_test.exs b/test/mobilizon/users/users_test.exs index 01b1520e2..3f06ae066 100644 --- a/test/mobilizon/users/users_test.exs +++ b/test/mobilizon/users/users_test.exs @@ -72,14 +72,6 @@ defmodule Mobilizon.UsersTest do @email "email@domain.tld" @password "password" - test "authenticate/1 checks the user's password" do - {:ok, %User{} = user} = Users.register(%{email: @email, password: @password}) - - assert {:ok, _} = Users.authenticate(%{user: user, password: @password}) - - assert {:error, :unauthorized} == - Users.authenticate(%{user: user, password: "bad password"}) - end test "get_user_by_email/1 finds an user by its email" do {:ok, %User{email: email} = user} = Users.register(%{email: @email, password: @password}) diff --git a/test/service/auth/authentificator_test.exs b/test/service/auth/authentificator_test.exs new file mode 100644 index 000000000..e0d768c99 --- /dev/null +++ b/test/service/auth/authentificator_test.exs @@ -0,0 +1,34 @@ +defmodule Mobilizon.Service.Auth.AuthenticatorTest do + use Mobilizon.DataCase + + alias Mobilizon.Service.Auth.Authenticator + alias Mobilizon.Users + alias Mobilizon.Users.User + import Mobilizon.Factory + + @email "email@domain.tld" + @password "password" + + describe "test authentification" do + test "authenticate/1 checks the user's password" do + {:ok, %User{} = user} = Users.register(%{email: @email, password: @password}) + Users.update_user(user, %{confirmed_at: DateTime.utc_now()}) + + assert {:ok, _} = Authenticator.authenticate(@email, @password) + + assert {:error, :bad_password} == + Authenticator.authenticate(@email, "completely wrong password") + end + end + + describe "fetch_user/1" do + test "returns user by email" do + user = insert(:user) + assert Authenticator.fetch_user(user.email).id == user.id + end + + test "returns nil" do + assert Authenticator.fetch_user("email") == {:error, :user_not_found} + end + end +end diff --git a/test/service/auth/ldap_authentificator_test.exs b/test/service/auth/ldap_authentificator_test.exs new file mode 100644 index 000000000..6168f8594 --- /dev/null +++ b/test/service/auth/ldap_authentificator_test.exs @@ -0,0 +1,238 @@ +defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do + use Mobilizon.Web.ConnCase + use Mobilizon.Tests.Helpers + + alias Mobilizon.GraphQL.AbsintheHelpers + alias Mobilizon.Service.Auth.{Authenticator, LDAPAuthenticator} + alias Mobilizon.Users.User + alias Mobilizon.Web.Auth.Guardian + + import Mobilizon.Factory + import ExUnit.CaptureLog + import Mock + + @skip if !Code.ensure_loaded?(:eldap), do: :skip + @admin_password "admin_password" + + setup_all do + clear_config([:ldap, :enabled], true) + clear_config([:ldap, :bind_uid], "admin") + clear_config([:ldap, :bind_password], @admin_password) + end + + setup_all do: + clear_config( + Authenticator, + LDAPAuthenticator + ) + + @login_mutation """ + mutation Login($email: String!, $password: String!) { + login(email: $email, password: $password) { + accessToken, + refreshToken, + user { + id + } + } + } + """ + + describe "login" do + @tag @skip + test "authorizes the existing user using LDAP credentials", %{conn: conn} do + user_password = "testpassword" + admin_password = "admin_password" + user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password)) + + host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist + port = Mobilizon.Config.get([:ldap, :port]) + + with_mocks [ + {:eldap, [], + [ + open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, + simple_bind: fn _connection, _dn, password -> + case password do + ^admin_password -> :ok + ^user_password -> :ok + end + end, + equalityMatch: fn _type, _value -> :ok end, + wholeSubtree: fn -> :ok end, + search: fn _connection, _options -> + {:ok, + {:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], []}} + end, + close: fn _connection -> + send(self(), :close_connection) + :ok + end + ]} + ] do + res = + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user_password} + ) + + assert is_nil(res["error"]) + assert token = res["data"]["login"]["accessToken"] + + {:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token) + + assert user_from_token.id == user.id + assert_received :close_connection + end + end + + @tag @skip + test "creates a new user after successful LDAP authorization", %{conn: conn} do + user_password = "testpassword" + admin_password = "admin_password" + user = build(:user) + + host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist + port = Mobilizon.Config.get([:ldap, :port]) + + with_mocks [ + {:eldap, [], + [ + open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, + simple_bind: fn _connection, _dn, password -> + case password do + ^admin_password -> :ok + ^user_password -> :ok + end + end, + equalityMatch: fn _type, _value -> :ok end, + wholeSubtree: fn -> :ok end, + search: fn _connection, _options -> + {:ok, + {:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], []}} + end, + close: fn _connection -> + send(self(), :close_connection) + :ok + end + ]} + ] do + res = + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user_password} + ) + + assert is_nil(res["error"]) + assert token = res["data"]["login"]["accessToken"] + + {:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token) + + assert user_from_token.email == user.email + assert_received :close_connection + end + end + + @tag @skip + test "falls back to the default authorization when LDAP is unavailable", %{conn: conn} do + user_password = "testpassword" + admin_password = "admin_password" + user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password)) + + host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist + port = Mobilizon.Config.get([:ldap, :port]) + + with_mocks [ + {:eldap, [], + [ + open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:error, 'connect failed'} end, + simple_bind: fn _connection, _dn, password -> + case password do + ^admin_password -> :ok + ^user_password -> :ok + end + end, + equalityMatch: fn _type, _value -> :ok end, + wholeSubtree: fn -> :ok end, + search: fn _connection, _options -> + {:ok, + {:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], []}} + end, + close: fn _connection -> + send(self(), :close_connection) + :ok + end + ]} + ] do + log = + capture_log(fn -> + res = + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user_password} + ) + + assert is_nil(res["error"]) + assert token = res["data"]["login"]["accessToken"] + + {:ok, %User{} = user_from_token, _claims} = Guardian.resource_from_token(token) + + assert user_from_token.email == user.email + end) + + assert log =~ "Could not open LDAP connection: 'connect failed'" + refute_received :close_connection + end + end + + @tag @skip + test "disallow authorization for wrong LDAP credentials", %{conn: conn} do + user_password = "testpassword" + user = insert(:user, password_hash: Argon2.hash_pwd_salt(user_password)) + + host = [:ldap, :host] |> Mobilizon.Config.get() |> to_charlist + port = Mobilizon.Config.get([:ldap, :port]) + + with_mocks [ + {:eldap, [], + [ + open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end, + simple_bind: fn _connection, _dn, _password -> {:error, :invalidCredentials} end, + close: fn _connection -> + send(self(), :close_connection) + :ok + end + ]} + ] do + res = + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user_password} + ) + + refute is_nil(res["errors"]) + + assert assert hd(res["errors"])["message"] == + "Impossible to authenticate, either your email or password are invalid." + + assert_received :close_connection + end + end + end + + describe "can change" do + test "password" do + assert LDAPAuthenticator.can_change_password?(%User{provider: "ldap"}) == false + assert LDAPAuthenticator.can_change_password?(%User{provider: nil}) == true + end + + test "email" do + assert LDAPAuthenticator.can_change_password?(%User{provider: "ldap"}) == false + assert LDAPAuthenticator.can_change_password?(%User{provider: nil}) == true + end + end +end diff --git a/test/service/auth/mobilizon_authentificator_test.exs b/test/service/auth/mobilizon_authentificator_test.exs new file mode 100644 index 000000000..4019f17b3 --- /dev/null +++ b/test/service/auth/mobilizon_authentificator_test.exs @@ -0,0 +1,29 @@ +defmodule Mobilizon.Service.Auth.MobilizonAuthenticatorTest do + use Mobilizon.DataCase + + alias Mobilizon.Service.Auth.MobilizonAuthenticator + alias Mobilizon.Users.User + import Mobilizon.Factory + + setup do + password = "testpassword" + email = "someone@somewhere.tld" + user = insert(:user, email: email, password_hash: Argon2.hash_pwd_salt(password)) + {:ok, [user: user, email: email, password: password]} + end + + test "login", %{email: email, password: password, user: user} do + assert {:ok, %User{} = returned_user} = MobilizonAuthenticator.login(email, password) + assert returned_user.id == user.id + end + + test "login with invalid password", %{email: email} do + assert {:error, :bad_password} == MobilizonAuthenticator.login(email, "invalid") + assert {:error, :bad_password} == MobilizonAuthenticator.login(email, nil) + end + + test "login with no credentials" do + assert {:error, :user_not_found} == MobilizonAuthenticator.login("some@email.com", nil) + assert {:error, :user_not_found} == MobilizonAuthenticator.login(nil, nil) + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 184b78813..220e7755d 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -18,7 +18,8 @@ defmodule Mobilizon.Factory do role: :user, confirmed_at: DateTime.utc_now() |> DateTime.truncate(:second), confirmation_sent_at: nil, - confirmation_token: nil + confirmation_token: nil, + provider: nil } end diff --git a/test/support/helpers.ex b/test/support/helpers.ex index a58f382d8..ffa59e4a4 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -7,6 +7,7 @@ defmodule Mobilizon.Tests.Helpers do @moduledoc """ Helpers for use in tests. """ + alias Mobilizon.Config defmacro clear_config(config_path) do quote do @@ -17,11 +18,17 @@ defmodule Mobilizon.Tests.Helpers do defmacro clear_config(config_path, do: yield) do quote do - setup do - initial_setting = Mobilizon.Config.get(unquote(config_path)) - unquote(yield) - on_exit(fn -> Mobilizon.Config.put(unquote(config_path), initial_setting) end) - :ok + initial_setting = Config.get(unquote(config_path)) + unquote(yield) + on_exit(fn -> Config.put(unquote(config_path), initial_setting) end) + :ok + end + end + + defmacro clear_config(config_path, temp_setting) do + quote do + clear_config(unquote(config_path)) do + Config.put(unquote(config_path), unquote(temp_setting)) end end end diff --git a/test/web/controllers/auth_controller_test.exs b/test/web/controllers/auth_controller_test.exs new file mode 100644 index 000000000..ca2bad443 --- /dev/null +++ b/test/web/controllers/auth_controller_test.exs @@ -0,0 +1,54 @@ +defmodule Mobilizon.Web.AuthControllerTest do + use Mobilizon.Web.ConnCase + alias Mobilizon.Service.Auth.Authenticator + alias Mobilizon.Users.User + + @email "someone@somewhere.tld" + + test "login and registration", + %{conn: conn} do + conn = + conn + |> assign(:ueberauth_auth, %Ueberauth.Auth{ + strategy: Ueberauth.Strategy.Twitter, + extra: %Ueberauth.Auth.Extra{raw_info: %{user: %{"email" => @email}}} + }) + |> get("/auth/twitter/callback") + + assert html_response(conn, 200) =~ "auth-access-token" + + assert %User{confirmed_at: confirmed_at, email: @email} = Authenticator.fetch_user(@email) + + refute is_nil(confirmed_at) + end + + test "on bad provider error", %{ + conn: conn + } do + conn = + conn + |> assign(:ueberauth_failure, %{errors: [%{message: "Some error"}]}) + |> get("/auth/nothing") + + assert "/login?code=Login Provider not found&provider=nothing" = + redirection = redirected_to(conn, 302) + + conn = get(recycle(conn), redirection) + assert html_response(conn, 200) + end + + test "on authentication error", %{ + conn: conn + } do + conn = + conn + |> assign(:ueberauth_failure, %{errors: [%{message: "Some error"}]}) + |> get("/auth/twitter/callback") + + assert "/login?code=Error with Login Provider&provider=twitter" = + redirection = redirected_to(conn, 302) + + conn = get(recycle(conn), redirection) + assert html_response(conn, 200) + end +end