From eefb4b5e2e9b62a1bbd892040b961fc1848f09c9 Mon Sep 17 00:00:00 2001 From: Alexey Bannov Date: Fri, 16 Jun 2023 19:46:14 +0300 Subject: [PATCH 001/362] refactoring:Authorization replace mvc filter to route --- common/ASC.Api.Core/Core/BaseStartup.cs | 3 --- common/ASC.Api.Core/Core/CustomEndpointDataSource.cs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/common/ASC.Api.Core/Core/BaseStartup.cs b/common/ASC.Api.Core/Core/BaseStartup.cs index a4412a25f3..3790b52911 100644 --- a/common/ASC.Api.Core/Core/BaseStartup.cs +++ b/common/ASC.Api.Core/Core/BaseStartup.cs @@ -191,9 +191,6 @@ public abstract class BaseStartup { config.Conventions.Add(new ControllerNameAttributeConvention()); - var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); - - config.Filters.Add(new AuthorizeFilter(policy)); config.Filters.Add(new TypeFilterAttribute(typeof(TenantStatusFilter))); config.Filters.Add(new TypeFilterAttribute(typeof(PaymentFilter))); config.Filters.Add(new TypeFilterAttribute(typeof(IpSecurityFilter))); diff --git a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs index 522280ac9b..2338a98aa4 100644 --- a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs +++ b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs @@ -77,7 +77,7 @@ public static class EndpointExtension { public static async Task MapCustomAsync(this IEndpointRouteBuilder endpoints, bool webhooksEnabled = false, IServiceProvider serviceProvider = null) { - endpoints.MapControllers(); + endpoints.MapControllers().RequireAuthorization(); if (webhooksEnabled && serviceProvider != null) { From d5b009554efb3b07eda6e0d72afd755a326a7339 Mon Sep 17 00:00:00 2001 From: Alexey Bannov Date: Thu, 29 Jun 2023 20:47:47 +0300 Subject: [PATCH 002/362] backend: update JWT dll. Added authorize via JWT token --- common/ASC.Api.Core/ASC.Api.Core.csproj | 2 +- .../Auth/AuthorizationExtension.cs | 200 ++++++++++++++++++ .../Auth/AuthorizationPolicyProvider.cs | 57 +++++ common/ASC.Api.Core/Auth/BasicAuthHandler.cs | 10 +- .../ASC.Api.Core/Auth/ConfirmAuthHandler.cs | 5 +- .../Auth/ScopesAuthorizationHandler.cs | 81 +++++++ common/ASC.Api.Core/Auth/ScopesRequirement.cs | 36 ++++ common/ASC.Api.Core/Core/BaseStartup.cs | 49 +---- .../Core/CustomEndpointDataSource.cs | 4 +- common/ASC.Api.Core/Log/BaseStartupLogger.cs | 44 ++++ common/ASC.Common/ASC.Common.csproj | 2 +- .../{Constants.cs => AuthConstants.cs} | 7 +- common/ASC.Common/Utils/JsonWebToken.cs | 2 +- .../Context/Impl/SubscriptionManager.cs | 10 +- .../Context/SecurityContext.cs | 19 +- .../Security/Authorizing/AzManager.cs | 2 +- .../Security/Authorizing/RoleProvider.cs | 6 +- common/ASC.Core.Common/Security/Security.cs | 16 +- .../Security/UserGroupObject.cs | 2 +- .../Security/UserSecurityProvider.cs | 2 +- common/ASC.Core.Common/Users/Constants.cs | 21 +- .../ASC.FederatedLogin.csproj | 2 +- config/nlog.config | 4 +- .../Core/HttpHandlers/FileHandler.ashx.cs | 8 +- .../Server/Api/PeopleControllerBase.cs | 3 +- .../ASC.People/Server/Api/UserController.cs | 13 ++ web/ASC.Web.Studio/Startup.cs | 4 +- 27 files changed, 514 insertions(+), 97 deletions(-) create mode 100644 common/ASC.Api.Core/Auth/AuthorizationExtension.cs create mode 100644 common/ASC.Api.Core/Auth/AuthorizationPolicyProvider.cs create mode 100644 common/ASC.Api.Core/Auth/ScopesAuthorizationHandler.cs create mode 100644 common/ASC.Api.Core/Auth/ScopesRequirement.cs create mode 100644 common/ASC.Api.Core/Log/BaseStartupLogger.cs rename common/ASC.Common/Security/Authorizing/{Constants.cs => AuthConstants.cs} (94%) diff --git a/common/ASC.Api.Core/ASC.Api.Core.csproj b/common/ASC.Api.Core/ASC.Api.Core.csproj index 1be535aed0..8bacc9e7c1 100644 --- a/common/ASC.Api.Core/ASC.Api.Core.csproj +++ b/common/ASC.Api.Core/ASC.Api.Core.csproj @@ -20,7 +20,7 @@ - + diff --git a/common/ASC.Api.Core/Auth/AuthorizationExtension.cs b/common/ASC.Api.Core/Auth/AuthorizationExtension.cs new file mode 100644 index 0000000000..02419c6285 --- /dev/null +++ b/common/ASC.Api.Core/Auth/AuthorizationExtension.cs @@ -0,0 +1,200 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +using System.Collections.Specialized; + +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; + +namespace ASC.Api.Core.Auth; + +public static class AuthorizationExtension +{ + private static readonly NameValueCollection _scopesMap = new NameValueCollection() + { + { "GET api/[0-9].[0-9]/files/rooms", "rooms:read,rooms:write" }, + { "(POST|PUT|DELETE|UPDATE) api/[0-9].[0-9]/files/rooms", "rooms:write" }, + { "GET api/[0-9].[0-9]/files", "files:read,files:write" }, + { "(POST|PUT|DELETE|UPDATE) api/[0-9].[0-9]/files", "files:write" }, + { "GET api/[0-9].[0-9]/people/@self", "account.self:read,account.self:write" }, + { "(POST|PUT|DELETE|UPDATE) api/[0-9].[0-9]/people/@self", "account.self:write" }, + { "GET api/[0-9].[0-9]/people", "accounts:read,accounts:write" }, + { "(POST|PUT|DELETE|UPDATE) api/[0-9].[0-9]/people", "accounts:write" }, + }; + + private static readonly string[] _allScopes = new[] { + "files:read", + "files:write", + "rooms:read", + "rooms:write", + "account.self:read", + "account.self:write", + "accounts:read", + "accounts:write" }; + + private static string GetAuthorizePolicy(string routePattern, string httpMethod) + { + foreach (var regexPattern in _scopesMap.AllKeys) + { + var regex = new Regex(regexPattern); + + if (!regex.IsMatch($"{httpMethod} {routePattern}")) continue; + + var scopes = _scopesMap[regexPattern]; + + return scopes; + } + + return null; + } + + public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + + services.AddAuthentication() + .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => + { +#if DEBUG + + options.IncludeErrorDetails = true; +#endif + options.Configuration = new OpenIdConnectConfiguration(); + + IdentityModelEventSource.ShowPII = true; + options.MapInboundClaims = false; + + options.TokenValidationParameters.RoleClaimType = "role"; + options.TokenValidationParameters.NameClaimType = "name"; + + options.TokenValidationParameters = new TokenValidationParameters + { + // Clock skew compensates for server time drift. + // We recommend 5 minutes or less: + ClockSkew = TimeSpan.FromMinutes(5), + // Specify the key used to sign the token: + // IssuerSigningKey = signingKey, + RequireSignedTokens = false, + RequireAudience = false, + // Ensure the token hasn't expired: + RequireExpirationTime = false, + ValidateLifetime = false, + // Ensure the token audience matches our audience value (default true): + ValidateAudience = false, + ValidAudience = "4testing", + // Ensure the token was issued by a trusted authorization server (default true): + ValidateIssuer = false, + // ValidIssuer = "https://{yourOktaDomain}/oauth2/default", + ValidateIssuerSigningKey = false, + SignatureValidator = delegate (string token, TokenValidationParameters parameters) + { + var jwt = new JwtSecurityToken(token); + + return jwt; + } + }; + + options.Events = new JwtBearerEvents + { + OnTokenValidated = async ctx => + { + using var scope = ctx.HttpContext.RequestServices.CreateScope(); + + var securityContext = scope.ServiceProvider.GetService(); + + var logger = scope.ServiceProvider.GetService>(); + + logger.DebugOnTokenValidatedCallback(); + + if (ctx?.Principal != null) + { + foreach (var claim in ctx.Principal.Claims) + { + logger.DebugOnTokenValidatedCallback(claim.Type, claim.Value); + } + } + + var claimSid = ctx.Principal.Claims.FirstOrDefault(x => x.Type == "userId"); + + if (claimSid == null || !Guid.TryParse(claimSid.Value, out var userId)) + { + throw new AuthenticationException($"Claim 'Sid' is not present in JWT"); + } + + await securityContext.AuthenticateMeWithoutCookieAsync(userId, ctx.Principal.Claims.ToList()); + }, + OnMessageReceived = msg => + { + using var scope = msg?.HttpContext.RequestServices.CreateScope(); + + var logger = scope?.ServiceProvider.GetService>(); + + var token = msg?.Request.Headers.Authorization.ToString(); + string path = msg?.Request.Path ?? ""; + + logger.DebugOnMessageReceivedCallback(path); + + if (!string.IsNullOrEmpty(token)) + { + logger.DebugOnMessageReceivedCallbackAccessToken(token); + } + else + { + logger.DebugOnMessageReceivedCallbackNoAccessToken(); + } + + return Task.CompletedTask; + } + }; + }); + + + return services; + + } + + public static TBuilder WithRequirementAuthorization(this TBuilder builder) where TBuilder : IEndpointConventionBuilder + { + builder.Add(endpointBuilder => + { + var httpMethodMetadata = endpointBuilder.Metadata.OfType().FirstOrDefault(); + var authorizeAttribute = endpointBuilder.Metadata.OfType().FirstOrDefault(); + var httpMethod = httpMethodMetadata?.HttpMethods.FirstOrDefault(); + + var authorizePolicy = GetAuthorizePolicy(((RouteEndpointBuilder)endpointBuilder).RoutePattern.RawText, httpMethod); + + if (authorizeAttribute == null && authorizePolicy != null) + { + authorizeAttribute = new AuthorizeAttribute(authorizePolicy); + + endpointBuilder.Metadata.Add(authorizeAttribute); + } + }); + + return builder; + } +} diff --git a/common/ASC.Api.Core/Auth/AuthorizationPolicyProvider.cs b/common/ASC.Api.Core/Auth/AuthorizationPolicyProvider.cs new file mode 100644 index 0000000000..dea088c4ef --- /dev/null +++ b/common/ASC.Api.Core/Auth/AuthorizationPolicyProvider.cs @@ -0,0 +1,57 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Api.Core.Auth; +public class AuthorizationPolicyProvider : IAuthorizationPolicyProvider +{ + public AuthorizationPolicyProvider(IOptions options) + { + FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); + } + + public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } + + public Task GetDefaultPolicyAsync() + { + var basePolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser(); + + basePolicy.AddRequirements(new ScopesRequirement(AuthConstants.Claim_ScopeRootWrite.Value)); + + return Task.FromResult(basePolicy.Build()); + } + + public Task GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync(); + + public Task GetPolicyAsync(string policyName) + { + var policy = new AuthorizationPolicyBuilder(); + + policy.AddRequirements(new ScopesRequirement(policyName)); + + return Task.FromResult(policy.Build()); + } +} \ No newline at end of file diff --git a/common/ASC.Api.Core/Auth/BasicAuthHandler.cs b/common/ASC.Api.Core/Auth/BasicAuthHandler.cs index c70bb1c8fb..4e0a453101 100644 --- a/common/ASC.Api.Core/Auth/BasicAuthHandler.cs +++ b/common/ASC.Api.Core/Auth/BasicAuthHandler.cs @@ -85,10 +85,14 @@ public class BasicAuthHandler : AuthenticationHandler() + { + AuthConstants.Claim_ScopeRootWrite + }; + await _securityContext.AuthenticateMeAsync(userInfo.Email, passwordHash, null, claims); } catch (Exception) { diff --git a/common/ASC.Api.Core/Auth/ConfirmAuthHandler.cs b/common/ASC.Api.Core/Auth/ConfirmAuthHandler.cs index 822fd7f5e2..18c37fafca 100644 --- a/common/ASC.Api.Core/Auth/ConfirmAuthHandler.cs +++ b/common/ASC.Api.Core/Auth/ConfirmAuthHandler.cs @@ -81,9 +81,10 @@ public class ConfirmAuthHandler : AuthenticationHandler() { - new Claim(ClaimTypes.Role, emailValidationKeyModel.Type.ToString()) + new Claim(ClaimTypes.Role, emailValidationKeyModel.Type.ToString()), + AuthConstants.Claim_ScopeRootWrite }; - + if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Ok) { Guid userId; diff --git a/common/ASC.Api.Core/Auth/ScopesAuthorizationHandler.cs b/common/ASC.Api.Core/Auth/ScopesAuthorizationHandler.cs new file mode 100644 index 0000000000..0a5e565ee2 --- /dev/null +++ b/common/ASC.Api.Core/Auth/ScopesAuthorizationHandler.cs @@ -0,0 +1,81 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Api.Core.Auth; + +public class ScopesAuthorizationHandler : AuthorizationHandler +{ + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ScopesRequirement requirement) + { + if (!context.User.Identity.IsAuthenticated) + { + return Task.CompletedTask; + } + + if (context.HasSucceeded) + { + return Task.CompletedTask; + } + + if (context.User == null || requirement == null || string.IsNullOrWhiteSpace(requirement.Scopes)) + { + return Task.CompletedTask; + } + + var requirementScopes = requirement.Scopes.Split(",", StringSplitOptions.RemoveEmptyEntries); + + if (requirementScopes?.Any() != true) + { + return Task.CompletedTask; + } + + var expectedRequirements = requirementScopes.ToList(); + + if (expectedRequirements.Count == 0) + { + return Task.CompletedTask; + } + + var userScopeClaims = context.User.Claims?.Where(c => string.Equals(c.Type, "scope", StringComparison.OrdinalIgnoreCase)); + + foreach (var claim in userScopeClaims ?? Enumerable.Empty()) + { + var match = expectedRequirements + .Where(r => string.Equals(r, claim.Value, StringComparison.OrdinalIgnoreCase) || + string.Equals(AuthConstants.Claim_ScopeRootWrite.Value, claim.Value, StringComparison.OrdinalIgnoreCase)); + + if (match.Any()) + { + context.Succeed(requirement); + + break; + } + } + + return Task.CompletedTask; + } +} + diff --git a/common/ASC.Api.Core/Auth/ScopesRequirement.cs b/common/ASC.Api.Core/Auth/ScopesRequirement.cs new file mode 100644 index 0000000000..4d2e1f85be --- /dev/null +++ b/common/ASC.Api.Core/Auth/ScopesRequirement.cs @@ -0,0 +1,36 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Api.Core.Auth; +public class ScopesRequirement : IAuthorizationRequirement +{ + public string Scopes { get; } + + public ScopesRequirement(string scopes) + { + Scopes = scopes ?? throw new ArgumentNullException(nameof(scopes)); + } +} \ No newline at end of file diff --git a/common/ASC.Api.Core/Core/BaseStartup.cs b/common/ASC.Api.Core/Core/BaseStartup.cs index 3790b52911..01ef3815b5 100644 --- a/common/ASC.Api.Core/Core/BaseStartup.cs +++ b/common/ASC.Api.Core/Core/BaseStartup.cs @@ -199,45 +199,14 @@ public abstract class BaseStartup config.Filters.Add(new CustomExceptionFilterAttribute()); config.Filters.Add(new TypeFilterAttribute(typeof(WebhooksGlobalFilterAttribute))); }); - - var authBuilder = services.AddAuthentication(options => + + services.AddAuthentication(options => { options.DefaultScheme = MultiAuthSchemes; options.DefaultChallengeScheme = MultiAuthSchemes; }).AddScheme(CookieAuthenticationDefaults.AuthenticationScheme, a => { }) .AddScheme(BasicAuthScheme, a => { }) .AddScheme("confirm", a => { }) - .AddJwtBearer("Bearer", options => - { - options.Authority = _configuration["core:oidc:authority"]; - options.IncludeErrorDetails = true; - - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateAudience = false - }; - - options.Events = new JwtBearerEvents - { - OnTokenValidated = async ctx => - { - using var scope = ctx.HttpContext.RequestServices.CreateScope(); - - var securityContext = scope.ServiceProvider.GetService(); - - var claimUserId = ctx.Principal.FindFirstValue("userId"); - - if (string.IsNullOrEmpty(claimUserId)) - { - throw new Exception("Claim 'UserId' is not present in claim list"); - } - - var userId = new Guid(claimUserId); - - await securityContext.AuthenticateMeWithoutCookieAsync(userId, ctx.Principal.Claims.ToList()); - } - }; - }) .AddPolicyScheme(MultiAuthSchemes, JwtBearerDefaults.AuthenticationScheme, options => { options.ForwardDefaultSelector = context => @@ -261,11 +230,7 @@ public abstract class BaseStartup if (jwtHandler.CanReadToken(token)) { - var issuer = jwtHandler.ReadJwtToken(token).Issuer; - if (!string.IsNullOrEmpty(issuer) && issuer.Equals(_configuration["core:oidc:authority"])) - { - return JwtBearerDefaults.AuthenticationScheme; - } + return JwtBearerDefaults.AuthenticationScheme; } } @@ -273,6 +238,8 @@ public abstract class BaseStartup }; }); + services.AddJwtBearerAuthentication(); + services.AddAutoMapper(GetAutoMapperProfileAssemblies()); if (!_hostEnvironment.IsDevelopment()) @@ -305,16 +272,16 @@ public abstract class BaseStartup app.UseSynchronizationContextMiddleware(); - app.UseAuthentication(); - + app.UseAuthorization(); app.UseAuthorization(); app.UseCultureMiddleware(); app.UseLoggerMiddleware(); - + app.UseEndpoints(async endpoints => { + await endpoints.MapCustomAsync(WebhooksEnabled, app.ApplicationServices); endpoints.MapHealthChecks("/health", new HealthCheckOptions() diff --git a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs index 2338a98aa4..8a98150df0 100644 --- a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs +++ b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs @@ -25,7 +25,6 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode namespace ASC.Api.Core.Core; - public class CustomEndpointDataSource : EndpointDataSource { private readonly EndpointDataSource _source; @@ -77,7 +76,8 @@ public static class EndpointExtension { public static async Task MapCustomAsync(this IEndpointRouteBuilder endpoints, bool webhooksEnabled = false, IServiceProvider serviceProvider = null) { - endpoints.MapControllers().RequireAuthorization(); + endpoints.MapControllers() + .WithRequirementAuthorization(); if (webhooksEnabled && serviceProvider != null) { diff --git a/common/ASC.Api.Core/Log/BaseStartupLogger.cs b/common/ASC.Api.Core/Log/BaseStartupLogger.cs new file mode 100644 index 0000000000..034666efb1 --- /dev/null +++ b/common/ASC.Api.Core/Log/BaseStartupLogger.cs @@ -0,0 +1,44 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Api.Core.Log; +internal static partial class BaseStartupLogger +{ + [LoggerMessage(Level = LogLevel.Debug, Message = "OnTokenValidatedCallback: Claims from the access token")] + public static partial void DebugOnTokenValidatedCallback(this ILogger logger); + + [LoggerMessage(Level = LogLevel.Debug, Message = "OnTokenValidatedCallback: {claimType} - {claimValue}")] + public static partial void DebugOnTokenValidatedCallback(this ILogger logger, string claimType, string claimValue); + + [LoggerMessage(Level = LogLevel.Debug, Message = "OnMessageReceived: Access token from {url}")] + public static partial void DebugOnMessageReceivedCallback(this ILogger logger, string url); + + [LoggerMessage(Level = LogLevel.Debug, Message = "Access token: {token}")] + public static partial void DebugOnMessageReceivedCallbackAccessToken(this ILogger logger, String token); + + [LoggerMessage(Level = LogLevel.Debug, Message = "Token: No access token provided")] + public static partial void DebugOnMessageReceivedCallbackNoAccessToken(this ILogger logger); +} diff --git a/common/ASC.Common/ASC.Common.csproj b/common/ASC.Common/ASC.Common.csproj index c84ddae3cb..c57ca0ab98 100644 --- a/common/ASC.Common/ASC.Common.csproj +++ b/common/ASC.Common/ASC.Common.csproj @@ -36,7 +36,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/common/ASC.Common/Security/Authorizing/Constants.cs b/common/ASC.Common/Security/Authorizing/AuthConstants.cs similarity index 94% rename from common/ASC.Common/Security/Authorizing/Constants.cs rename to common/ASC.Common/Security/Authorizing/AuthConstants.cs index 9654f48651..98a1933f1d 100644 --- a/common/ASC.Common/Security/Authorizing/Constants.cs +++ b/common/ASC.Common/Security/Authorizing/AuthConstants.cs @@ -24,9 +24,11 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode +using System.Security.Claims; + namespace ASC.Common.Security.Authorizing; -public static class Constants +public static class AuthConstants { public static readonly Role DocSpaceAdmin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "DocSpaceAdmin"); public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone"); @@ -36,4 +38,7 @@ public static class Constants public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member"); public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner"); public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self"); + + public static readonly Claim Claim_ScopeRootWrite = new Claim("scope", "root_write"); + } diff --git a/common/ASC.Common/Utils/JsonWebToken.cs b/common/ASC.Common/Utils/JsonWebToken.cs index 18b5409087..65e350b239 100644 --- a/common/ASC.Common/Utils/JsonWebToken.cs +++ b/common/ASC.Common/Utils/JsonWebToken.cs @@ -60,7 +60,7 @@ public static class JsonWebToken } } -public class DictionaryStringObjectJsonConverter : JsonConverter> +public class DictionaryStringObjectJsonConverter : System.Text.Json.Serialization.JsonConverter> { public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/common/ASC.Core.Common/Context/Impl/SubscriptionManager.cs b/common/ASC.Core.Common/Context/Impl/SubscriptionManager.cs index 25e87c02e2..675660d8dd 100644 --- a/common/ASC.Core.Common/Context/Impl/SubscriptionManager.cs +++ b/common/ASC.Core.Common/Context/Impl/SubscriptionManager.cs @@ -24,7 +24,7 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using Constants = ASC.Common.Security.Authorizing.Constants; +using AuthConstants = ASC.Common.Security.Authorizing.AuthConstants; namespace ASC.Core; @@ -37,10 +37,10 @@ public class SubscriptionManager private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1); public static readonly List Groups = Groups = new List { - Constants.DocSpaceAdmin.ID, - Constants.Everyone.ID, - Constants.RoomAdmin.ID, - Constants.Collaborator.ID, + AuthConstants.DocSpaceAdmin.ID, + AuthConstants.Everyone.ID, + AuthConstants.RoomAdmin.ID, + AuthConstants.Collaborator.ID, }; public SubscriptionManager(CachedSubscriptionService service, TenantManager tenantManager, ICache cache) diff --git a/common/ASC.Core.Common/Context/SecurityContext.cs b/common/ASC.Core.Common/Context/SecurityContext.cs index e3f9cfcd7b..1ea1dfafcf 100644 --- a/common/ASC.Core.Common/Context/SecurityContext.cs +++ b/common/ASC.Core.Common/Context/SecurityContext.cs @@ -84,7 +84,7 @@ public class SecurityContext } - public async Task AuthenticateMeAsync(string login, string passwordHash, Func> funcLoginEvent = null) + public async Task AuthenticateMeAsync(string login, string passwordHash, Func> funcLoginEvent = null, List additionalClaims = null) { ArgumentNullException.ThrowIfNull(login); ArgumentNullException.ThrowIfNull(passwordHash); @@ -92,7 +92,7 @@ public class SecurityContext var tenantid = await _tenantManager.GetCurrentTenantIdAsync(); var u = await _userManager.GetUsersByPasswordHashAsync(tenantid, login, passwordHash); - return await AuthenticateMeAsync(new UserAccount(u, tenantid, _userFormatter), funcLoginEvent); + return await AuthenticateMeAsync(new UserAccount(u, tenantid, _userFormatter), funcLoginEvent,additionalClaims); } public async Task AuthenticateMe(string cookie) @@ -168,7 +168,13 @@ public class SecurityContext return false; } - await AuthenticateMeWithoutCookieAsync(new UserAccount(new UserInfo { Id = userid }, tenant, _userFormatter)); + var claims = new List() + { + AuthConstants.Claim_ScopeRootWrite + }; + + await AuthenticateMeWithoutCookieAsync(new UserAccount(new UserInfo { Id = userid }, tenant, _userFormatter), claims); + return true; } catch (InvalidCredentialException ice) @@ -381,10 +387,13 @@ public class AuthContext internal ClaimsPrincipal Principal { - get => CustomSynchronizationContext.CurrentContext.CurrentPrincipal as ClaimsPrincipal ?? HttpContextAccessor?.HttpContext?.User; + get => CustomSynchronizationContext.CurrentContext?.CurrentPrincipal as ClaimsPrincipal ?? HttpContextAccessor?.HttpContext?.User; set { - CustomSynchronizationContext.CurrentContext.CurrentPrincipal = value; + if (CustomSynchronizationContext.CurrentContext != null) + { + CustomSynchronizationContext.CurrentContext.CurrentPrincipal = value; + } if (HttpContextAccessor?.HttpContext != null) { diff --git a/common/ASC.Core.Common/Security/Authorizing/AzManager.cs b/common/ASC.Core.Common/Security/Authorizing/AzManager.cs index 973f133c11..3d95c55210 100644 --- a/common/ASC.Core.Common/Security/Authorizing/AzManager.cs +++ b/common/ASC.Core.Common/Security/Authorizing/AzManager.cs @@ -56,7 +56,7 @@ public class AzManager internal async Task GetAzManagerAclAsync(ISubject subject, IAction action, ISecurityObjectId objectId, ISecurityObjectProvider securityObjProvider) { - if (action.AdministratorAlwaysAllow && (Constants.DocSpaceAdmin.ID == subject.ID || await _roleProvider.IsSubjectInRoleAsync(subject, Constants.DocSpaceAdmin) + if (action.AdministratorAlwaysAllow && (AuthConstants.DocSpaceAdmin.ID == subject.ID || await _roleProvider.IsSubjectInRoleAsync(subject, AuthConstants.DocSpaceAdmin) || (objectId is SecurityObject obj && await obj.IsMatchDefaultRulesAsync(subject, action, _roleProvider)))) { return AzManagerAcl.Allow; diff --git a/common/ASC.Core.Common/Security/Authorizing/RoleProvider.cs b/common/ASC.Core.Common/Security/Authorizing/RoleProvider.cs index 31f6ba2fe0..ead75ebbea 100644 --- a/common/ASC.Core.Common/Security/Authorizing/RoleProvider.cs +++ b/common/ASC.Core.Common/Security/Authorizing/RoleProvider.cs @@ -24,7 +24,7 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using Constants = ASC.Common.Security.Authorizing.Constants; +using AuthConstants = ASC.Common.Security.Authorizing.AuthConstants; namespace ASC.Core.Security.Authorizing; @@ -53,9 +53,9 @@ class RoleProvider : IRoleProvider } } - if (roles.Any(r => r.ID == Constants.Collaborator.ID || r.ID == Constants.User.ID)) + if (roles.Any(r => r.ID == AuthConstants.Collaborator.ID || r.ID == AuthConstants.User.ID)) { - roles = roles.Where(r => r.ID != Constants.RoomAdmin.ID).ToList(); + roles = roles.Where(r => r.ID != AuthConstants.RoomAdmin.ID).ToList(); } return roles; diff --git a/common/ASC.Core.Common/Security/Security.cs b/common/ASC.Core.Common/Security/Security.cs index 342ae4d753..9ebd8ec6b1 100644 --- a/common/ASC.Core.Common/Security/Security.cs +++ b/common/ASC.Core.Common/Security/Security.cs @@ -25,7 +25,7 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode using UserConstants = ASC.Core.Users.Constants; -using Constants = ASC.Common.Security.Authorizing.Constants; +using AuthConstants = ASC.Common.Security.Authorizing.AuthConstants; namespace ASC.Core.Common.Security; @@ -34,26 +34,26 @@ public static class Security public static readonly Dictionary>> Rules = new() { { - Constants.RoomAdmin.ID, new Dictionary> + AuthConstants.RoomAdmin.ID, new Dictionary> { { - Constants.User.ID, new HashSet + AuthConstants.User.ID, new HashSet { - new(UserConstants.Action_EditGroups.ID, Constants.User), + new(UserConstants.Action_EditGroups.ID, AuthConstants.User), new(UserConstants.Action_AddRemoveUser.ID), } }, { - Constants.RoomAdmin.ID, new HashSet + AuthConstants.RoomAdmin.ID, new HashSet { - new(UserConstants.Action_EditGroups.ID, Constants.User), + new(UserConstants.Action_EditGroups.ID, AuthConstants.User), new(UserConstants.Action_AddRemoveUser.ID), } }, { - Constants.Collaborator.ID, new HashSet + AuthConstants.Collaborator.ID, new HashSet { - new(UserConstants.Action_EditGroups.ID, Constants.Collaborator), + new(UserConstants.Action_EditGroups.ID, AuthConstants.Collaborator), new(UserConstants.Action_AddRemoveUser.ID), } } diff --git a/common/ASC.Core.Common/Security/UserGroupObject.cs b/common/ASC.Core.Common/Security/UserGroupObject.cs index 18b314194c..c259959ddc 100644 --- a/common/ASC.Core.Common/Security/UserGroupObject.cs +++ b/common/ASC.Core.Common/Security/UserGroupObject.cs @@ -24,7 +24,7 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using AuthConstants = ASC.Common.Security.Authorizing.Constants; +using AuthConstants = ASC.Common.Security.Authorizing.AuthConstants; namespace ASC.Core.Common.Security; diff --git a/common/ASC.Core.Common/Security/UserSecurityProvider.cs b/common/ASC.Core.Common/Security/UserSecurityProvider.cs index 0821ca7e31..e342e92737 100644 --- a/common/ASC.Core.Common/Security/UserSecurityProvider.cs +++ b/common/ASC.Core.Common/Security/UserSecurityProvider.cs @@ -24,7 +24,7 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using AuthConstants = ASC.Common.Security.Authorizing.Constants; +using AuthConstants = ASC.Common.Security.Authorizing.AuthConstants; namespace ASC.Core.Users; diff --git a/common/ASC.Core.Common/Users/Constants.cs b/common/ASC.Core.Common/Users/Constants.cs index cd2f126a91..28436d1a78 100644 --- a/common/ASC.Core.Common/Users/Constants.cs +++ b/common/ASC.Core.Common/Users/Constants.cs @@ -25,7 +25,6 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode using Action = ASC.Common.Security.Authorizing.Action; -using AuthConst = ASC.Common.Security.Authorizing.Constants; namespace ASC.Core.Users; @@ -65,32 +64,32 @@ public sealed class Constants public static readonly GroupInfo GroupEveryone = new GroupInfo(SysGroupCategoryId) { - ID = AuthConst.Everyone.ID, - Name = AuthConst.Everyone.Name, + ID = AuthConstants.Everyone.ID, + Name = AuthConstants.Everyone.Name, }; public static readonly GroupInfo GroupUser = new GroupInfo(SysGroupCategoryId) { - ID = AuthConst.User.ID, - Name = AuthConst.User.Name, + ID = AuthConstants.User.ID, + Name = AuthConstants.User.Name, }; public static readonly GroupInfo GroupManager = new GroupInfo(SysGroupCategoryId) { - ID = AuthConst.RoomAdmin.ID, - Name = AuthConst.RoomAdmin.Name, + ID = AuthConstants.RoomAdmin.ID, + Name = AuthConstants.RoomAdmin.Name, }; public static readonly GroupInfo GroupAdmin = new GroupInfo(SysGroupCategoryId) { - ID = AuthConst.DocSpaceAdmin.ID, - Name = AuthConst.DocSpaceAdmin.Name, + ID = AuthConstants.DocSpaceAdmin.ID, + Name = AuthConstants.DocSpaceAdmin.Name, }; public static readonly GroupInfo GroupCollaborator = new(SysGroupCategoryId) { - ID = AuthConst.Collaborator.ID, - Name = AuthConst.Collaborator.Name, + ID = AuthConstants.Collaborator.ID, + Name = AuthConstants.Collaborator.Name, }; public static readonly GroupInfo[] BuildinGroups = new[] diff --git a/common/ASC.FederatedLogin/ASC.FederatedLogin.csproj b/common/ASC.FederatedLogin/ASC.FederatedLogin.csproj index 7ddabedbaa..b69553d5f9 100644 --- a/common/ASC.FederatedLogin/ASC.FederatedLogin.csproj +++ b/common/ASC.FederatedLogin/ASC.FederatedLogin.csproj @@ -31,7 +31,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/config/nlog.config b/config/nlog.config index 59fec170c0..8d9a3fd498 100644 --- a/config/nlog.config +++ b/config/nlog.config @@ -44,6 +44,8 @@ - + + + \ No newline at end of file diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index 773d9d3991..c092387861 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -665,7 +665,7 @@ public class FileHandlerService #pragma warning disable CS0618 // Type or member is obsolete var stringPayload = JwtBuilder.Create() .WithAlgorithm(new HMACSHA256Algorithm()) - .WithSerializer(new JwtSerializer()) + .WithJsonSerializer(new JwtSerializer()) .WithSecret(_fileUtility.SignatureSecret) .MustVerifySignature() .Decode(header); @@ -779,8 +779,8 @@ public class FileHandlerService #pragma warning disable CS0618 // Type or member is obsolete var stringPayload = JwtBuilder.Create() .WithAlgorithm(new HMACSHA256Algorithm()) - .WithSerializer(new JwtSerializer()) .WithSecret(_fileUtility.SignatureSecret) + .WithJsonSerializer(new JwtSerializer()) .MustVerifySignature() .Decode(header); #pragma warning restore CS0618 // Type or member is obsolete @@ -1516,7 +1516,7 @@ public class FileHandlerService #pragma warning disable CS0618 // Type or member is obsolete var dataString = JwtBuilder.Create() .WithAlgorithm(new HMACSHA256Algorithm()) - .WithSerializer(new JwtSerializer()) + .WithJsonSerializer(new JwtSerializer()) .WithSecret(_fileUtility.SignatureSecret) .MustVerifySignature() .Decode(fileData.Token); @@ -1551,7 +1551,7 @@ public class FileHandlerService #pragma warning disable CS0618 // Type or member is obsolete var stringPayload = JwtBuilder.Create() .WithAlgorithm(new HMACSHA256Algorithm()) - .WithSerializer(new JwtSerializer()) + .WithJsonSerializer(new JwtSerializer()) .WithSecret(_fileUtility.SignatureSecret) .MustVerifySignature() .Decode(header); diff --git a/products/ASC.People/Server/Api/PeopleControllerBase.cs b/products/ASC.People/Server/Api/PeopleControllerBase.cs index 3bdcd06a7d..b335ea2da4 100644 --- a/products/ASC.People/Server/Api/PeopleControllerBase.cs +++ b/products/ASC.People/Server/Api/PeopleControllerBase.cs @@ -49,7 +49,8 @@ public abstract class PeopleControllerBase : ApiControllerBase _userPhotoManager = userPhotoManager; _httpClientFactory = httpClientFactory; _httpContextAccessor = httpContextAccessor; - } + } + protected async Task GetUserInfoAsync(string userNameOrId) { diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs index 3d7fcc7a66..6bbb2d5668 100644 --- a/products/ASC.People/Server/Api/UserController.cs +++ b/products/ASC.People/Server/Api/UserController.cs @@ -144,6 +144,19 @@ public class UserController : PeopleControllerBase _usersQuotaSyncOperation = usersQuotaSyncOperation; } + [HttpGet("tokendiagnostics")] + public object GetClaims() + { + var result = new + { + Name = User.Identity?.Name ?? "Unknown Name", + Claims = (from c in User.Claims select c.Type + ":" + c.Value).ToList() + }; + + return result; + } + + [HttpPost("active")] public async Task AddMemberAsActivatedAsync(MemberRequestDto inDto) { diff --git a/web/ASC.Web.Studio/Startup.cs b/web/ASC.Web.Studio/Startup.cs index 19f1590396..ebcdc14aca 100644 --- a/web/ASC.Web.Studio/Startup.cs +++ b/web/ASC.Web.Studio/Startup.cs @@ -36,9 +36,7 @@ public class Startup : BaseStartup base.Configure(app, env); app.UseRouting(); - - app.UseAuthentication(); - + app.UseEndpoints(endpoints => { endpoints.InitializeHttpHandlers(); From 06c63bdb6fdc2367a7eb49d3505a50ea9d741b0b Mon Sep 17 00:00:00 2001 From: Alexey Bannov Date: Thu, 6 Jul 2023 19:40:10 +0300 Subject: [PATCH 003/362] ASC.MigrationPersonalToDocspace: fixed --- .../Tools/ASC.MigrationPersonalToDocspace/MigrationCreator.cs | 2 +- common/Tools/ASC.MigrationPersonalToDocspace/MigrationRunner.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/Tools/ASC.MigrationPersonalToDocspace/MigrationCreator.cs b/common/Tools/ASC.MigrationPersonalToDocspace/MigrationCreator.cs index 2ce8215e48..d274b53a1a 100644 --- a/common/Tools/ASC.MigrationPersonalToDocspace/MigrationCreator.cs +++ b/common/Tools/ASC.MigrationPersonalToDocspace/MigrationCreator.cs @@ -192,7 +192,7 @@ public class MigrationCreator using var userDbContextToregion = _creatorDbContext.CreateDbContext(_toRegion); var usersCount = userDbContextToregion.Users .Join(userDbContextToregion.UserGroups, u => u.Id, ug => ug.Userid, (u, ug) => new { u, ug }) - .Where(q => q.u.Tenant == tenant.Id && q.ug.UserGroupId == Common.Security.Authorizing.Constants.DocSpaceAdmin.ID).Count(); + .Where(q => q.u.Tenant == tenant.Id && q.ug.UserGroupId == Common.Security.Authorizing.AuthConstants.DocSpaceAdmin.ID).Count(); if (usersCount > qouta.CountRoomAdmin) { throw new ArgumentException("user count exceed"); diff --git a/common/Tools/ASC.MigrationPersonalToDocspace/MigrationRunner.cs b/common/Tools/ASC.MigrationPersonalToDocspace/MigrationRunner.cs index 2ce6846394..eed07fa8fa 100644 --- a/common/Tools/ASC.MigrationPersonalToDocspace/MigrationRunner.cs +++ b/common/Tools/ASC.MigrationPersonalToDocspace/MigrationRunner.cs @@ -190,7 +190,7 @@ public class MigrationRunner LastModified = DateTime.UtcNow, RefType = Core.UserGroupRefType.Contains, Removed = false, - UserGroupId = ASC.Common.Security.Authorizing.Constants.DocSpaceAdmin.ID, + UserGroupId = ASC.Common.Security.Authorizing.AuthConstants.DocSpaceAdmin.ID, Userid = tenant.OwnerId.Value }; From a0b9e560976b58a68e949f6adec47e565c5a1576 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Mon, 26 Jun 2023 14:57:55 +0300 Subject: [PATCH 004/362] Web: Client: PortalSettings: Added base OAuth page --- .../OAuth/OAuthDetails/index.js | 45 +++++ .../categories/developer-tools/OAuth/index.js | 41 +++++ .../OAuth/sub-components/List/RowView/Row.js | 109 ++++++++++++ .../sub-components/List/RowView/RowContent.js | 78 +++++++++ .../sub-components/List/RowView/index.js | 60 +++++++ .../List/TableView/TableHeader.js | 105 ++++++++++++ .../sub-components/List/TableView/TableRow.js | 155 ++++++++++++++++++ .../sub-components/List/TableView/index.js | 117 +++++++++++++ .../OAuth/sub-components/List/index.js | 38 +++++ .../categories/developer-tools/index.js | 14 +- .../PortalSettings/utils/settingsTree.js | 8 + packages/client/src/routes/portalSettings.js | 89 +++++++--- 12 files changed, 833 insertions(+), 26 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js new file mode 100644 index 0000000000..296c3669bb --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js @@ -0,0 +1,45 @@ +import React, { useState, useEffect } from "react"; +import { withTranslation } from "react-i18next"; +import styled from "styled-components"; +import Box from "@docspace/components/box"; +import TextInput from "@docspace/components/text-input"; +import Textarea from "@docspace/components/textarea"; +import Label from "@docspace/components/label"; +import Checkbox from "@docspace/components/checkbox"; +import Button from "@docspace/components/button"; +import ComboBox from "@docspace/components/combobox"; +import Heading from "@docspace/components/heading"; +import { inject, observer } from "mobx-react"; +import { isMobile } from "react-device-detect"; +import BreakpointWarning from "SRC_DIR/components/BreakpointWarning"; + +const Container = styled.div` + width: 100%; + margin-top: 5px; +`; + +const OAuthDetails = (props) => { + const { t, setDocumentTitle } = props; + + setDocumentTitle("OAuth"); + + return ( + <> + {isMobile ? ( + + ) : ( + Test + )} + + ); +}; + +export default inject(({ setup, auth }) => { + const { settingsStore, setDocumentTitle } = auth; + const { theme } = settingsStore; + + return { + theme, + setDocumentTitle, + }; +})(withTranslation(["Common"])(observer(OAuthDetails))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js new file mode 100644 index 0000000000..03c7918736 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js @@ -0,0 +1,41 @@ +import React, { useState, useEffect } from "react"; +import { withTranslation } from "react-i18next"; +import styled from "styled-components"; +import Box from "@docspace/components/box"; +import TextInput from "@docspace/components/text-input"; +import Textarea from "@docspace/components/textarea"; +import Label from "@docspace/components/label"; +import Checkbox from "@docspace/components/checkbox"; +import Button from "@docspace/components/button"; +import ComboBox from "@docspace/components/combobox"; +import Heading from "@docspace/components/heading"; +import { inject, observer } from "mobx-react"; +import { isMobile } from "react-device-detect"; +import BreakpointWarning from "SRC_DIR/components/BreakpointWarning"; +import List from "./sub-components/List"; + +const OAuth = (props) => { + const { t, setDocumentTitle } = props; + + setDocumentTitle("OAuth"); + + return ( + <> + {isMobile ? ( + + ) : ( + {}} openDeleteModal={() => {}} /> + )} + + ); +}; + +export default inject(({ setup, auth }) => { + const { settingsStore, setDocumentTitle } = auth; + const { theme } = settingsStore; + + return { + theme, + setDocumentTitle, + }; +})(withTranslation(["Common"])(observer(OAuth))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js new file mode 100644 index 0000000000..fcc13b3ebc --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js @@ -0,0 +1,109 @@ +import React, { useState } from "react"; +import { inject, observer } from "mobx-react"; + +import { Row as ComponentRow } from "@docspace/components/row"; + +import { RowContent } from "./RowContent"; + +import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; +import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url"; +import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; + +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +export const Row = (props) => { + const { + webhook, + sectionWidth, + toggleEnabled, + openSettingsModal, + openDeleteModal, + setCurrentWebhook, + } = props; + const navigate = useNavigate(); + const { t } = useTranslation(["Webhooks", "Common"]); + + const [isChecked, setIsChecked] = useState(webhook.enabled); + + const handleToggleEnabled = () => { + toggleEnabled(webhook); + setIsChecked((prevIsChecked) => !prevIsChecked); + }; + + const redirectToHistory = () => { + navigate(window.location.pathname + `/${webhook.id}`); + }; + const handleRowClick = (e) => { + if ( + e.target.closest(".table-container_row-context-menu-wrapper") || + e.target.closest(".toggleButton") || + e.target.closest(".row_context-menu-wrapper") || + e.detail === 0 + ) { + return; + } + + redirectToHistory(); + }; + + const onSettingsOpen = () => { + setCurrentWebhook(webhook); + openSettingsModal(); + }; + const onDeleteOpen = () => { + setCurrentWebhook(webhook); + openDeleteModal(); + }; + + const contextOptions = [ + { + key: "Settings dropdownItem", + label: t("Common:Settings"), + icon: SettingsIcon, + onClick: onSettingsOpen, + }, + { + key: "Webhook history dropdownItem", + label: t("WebhookHistory"), + icon: HistoryIcon, + onClick: redirectToHistory, + }, + { + key: "Separator dropdownItem", + isSeparator: true, + }, + { + key: "Delete webhook dropdownItem", + label: t("DeleteWebhook"), + icon: DeleteIcon, + onClick: onDeleteOpen, + }, + ]; + + return ( + <> + + + + + ); +}; + +export default inject(({ webhooksStore }) => { + const { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook } = + webhooksStore; + + return { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook }; +})(observer(Row)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js new file mode 100644 index 0000000000..1bdbca8ae2 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js @@ -0,0 +1,78 @@ +import React from "react"; +import styled from "styled-components"; + +import Text from "@docspace/components/text"; +import { RowContent as ComponentRowContent } from "@docspace/components/row-content"; +import ToggleButton from "@docspace/components/toggle-button"; + +//import StatusBadge from "../../StatusBadge"; + +import { isMobileOnly } from "react-device-detect"; + +const StyledRowContent = styled(ComponentRowContent)` + display: flex; + padding-bottom: 10px; + + .rowMainContainer { + height: 100%; + width: 100%; + } + + .mainIcons { + min-width: 76px; + } +`; + +const ContentWrapper = styled.div` + display: flex; + flex-direction: column; + justify-items: center; +`; + +const ToggleButtonWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; + margin-left: -52px; +`; + +const FlexWrapper = styled.div` + display: flex; +`; + +export const RowContent = ({ + sectionWidth, + webhook, + isChecked, + handleToggleEnabled, +}) => { + return ( + + + + + {webhook.name} + + {/* */} + + + {!isMobileOnly && ( + + {webhook.uri} + + )} + + + + + + + ); +}; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js new file mode 100644 index 0000000000..253f7e761f --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js @@ -0,0 +1,60 @@ +import React, { useEffect } from "react"; +import styled from "styled-components"; +import { inject, observer } from "mobx-react"; + +import { isMobile } from "react-device-detect"; + +import RowContainer from "@docspace/components/row-container"; + +import Row from "./Row"; + +const StyledRowContainer = styled(RowContainer)` + margin-top: 16px; +`; + +const RowView = (props) => { + const { + webhooks, + sectionWidth, + viewAs, + setViewAs, + openSettingsModal, + openDeleteModal, + } = props; + + useEffect(() => { + if (viewAs !== "table" && viewAs !== "row") return; + + if (sectionWidth < 1025 || isMobile) { + viewAs !== "row" && setViewAs("row"); + } else { + viewAs !== "table" && setViewAs("table"); + } + }, [sectionWidth]); + + return ( + + {webhooks.map((webhook) => ( + + ))} + + ); +}; + +export default inject(({ webhooksStore, setup }) => { + const { webhooks } = webhooksStore; + + const { viewAs, setViewAs } = setup; + + return { + webhooks, + viewAs, + setViewAs, + }; +})(observer(RowView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js new file mode 100644 index 0000000000..9786e9e223 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js @@ -0,0 +1,105 @@ +import React, { useState } from "react"; +import { TableHeader as Header } from "@docspace/components/table-container/TableHeader"; + +import { useTranslation } from "react-i18next"; +import { inject, observer } from "mobx-react"; + +const TABLE_VERSION = "5"; +const TABLE_COLUMNS = `webhooksConfigColumns_ver-${TABLE_VERSION}`; + +const getColumns = (defaultColumns, userId) => { + const storageColumns = localStorage.getItem(`${TABLE_COLUMNS}=${userId}`); + const columns = []; + + if (storageColumns) { + const splitColumns = storageColumns.split(","); + + for (let col of defaultColumns) { + const column = splitColumns.find((key) => key === col.key); + column ? (col.enable = true) : (col.enable = false); + + columns.push(col); + } + return columns; + } else { + return defaultColumns; + } +}; + +const TableHeader = (props) => { + const { + userId, + sectionWidth, + tableRef, + columnStorageName, + columnInfoPanelStorageName, + setHideColumns, + } = props; + const { t } = useTranslation(["Webhooks", "Common"]); + + const defaultColumns = [ + { + key: "Name", + title: t("Common:Name"), + resizable: true, + enable: true, + default: true, + active: true, + minWidth: 150, + onChange: onColumnChange, + }, + { + key: "URL", + title: t("URL"), + enable: true, + resizable: true, + onChange: onColumnChange, + }, + { + key: "State", + title: t("State"), + enable: true, + resizable: true, + onChange: onColumnChange, + }, + ]; + + const [columns, setColumns] = useState(getColumns(defaultColumns, userId)); + + function onColumnChange(key, e) { + const columnIndex = columns.findIndex((c) => c.key === key); + + if (columnIndex === -1) return; + + setColumns((prevColumns) => + prevColumns.map((item, index) => + index === columnIndex ? { ...item, enable: !item.enable } : item + ) + ); + + const tableColumns = columns.map((c) => c.enable && c.key); + localStorage.setItem(`${TABLE_COLUMNS}=${userId}`, tableColumns); + } + + return ( +
+ ); +}; + +export default inject(({ auth }) => { + return { + userId: auth.userStore.user.id, + }; +})(observer(TableHeader)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js new file mode 100644 index 0000000000..2191a85e1e --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js @@ -0,0 +1,155 @@ +import React, { useState } from "react"; +import styled from "styled-components"; +import { TableRow as Row } from "@docspace/components/table-container/TableRow"; +import TableCell from "@docspace/components/table-container/TableCell"; +import Text from "@docspace/components/text"; + +import ToggleButton from "@docspace/components/toggle-button"; +import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; +import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url"; +import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; +//import StatusBadge from "../../StatusBadge"; + +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +import { inject, observer } from "mobx-react"; + +const StyledWrapper = styled.div` + display: contents; +`; + +const StyledTableRow = styled(Row)` + .table-container_cell { + padding-right: 30px; + text-overflow: ellipsis; + } + + .mr-8 { + margin-right: 8px; + } + .textOverflow { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +`; + +const TableRow = (props) => { + const { + webhook, + toggleEnabled, + openSettingsModal, + openDeleteModal, + setCurrentWebhook, + hideColumns, + } = props; + const navigate = useNavigate(); + + const { t } = useTranslation(["Webhooks", "Common"]); + + const [isChecked, setIsChecked] = useState(webhook.enabled); + + const redirectToHistory = () => { + navigate(window.location.pathname + `/${webhook.id}`); + }; + + const handleRowClick = (e) => { + if ( + e.target.closest(".checkbox") || + e.target.closest(".table-container_row-checkbox") || + e.target.closest(".type-combobox") || + e.target.closest(".table-container_row-context-menu-wrapper") || + e.target.closest(".toggleButton") || + e.detail === 0 + ) { + return; + } + + redirectToHistory(); + }; + const handleToggleEnabled = () => { + toggleEnabled(webhook); + setIsChecked((prevIsChecked) => !prevIsChecked); + }; + + const onSettingsOpen = () => { + setCurrentWebhook(webhook); + openSettingsModal(); + }; + const onDeleteOpen = () => { + setCurrentWebhook(webhook); + openDeleteModal(); + }; + + const contextOptions = [ + { + key: "Settings dropdownItem", + label: t("Common:Settings"), + icon: SettingsIcon, + onClick: onSettingsOpen, + }, + { + key: "Webhook history dropdownItem", + label: t("WebhookHistory"), + icon: HistoryIcon, + onClick: redirectToHistory, + }, + { + key: "Separator dropdownItem", + isSeparator: true, + }, + { + key: "Delete webhook dropdownItem", + label: t("DeleteWebhook"), + icon: DeleteIcon, + onClick: onDeleteOpen, + }, + ]; + + return ( + <> + + + + + {webhook.name}{" "} + + {/* */} + + + + {webhook.uri} + + + + + + + + + ); +}; + +export default inject(({ webhooksStore }) => { + const { toggleEnabled, setCurrentWebhook } = webhooksStore; + + return { + toggleEnabled, + setCurrentWebhook, + }; +})(observer(TableRow)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js new file mode 100644 index 0000000000..d0367f0a46 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js @@ -0,0 +1,117 @@ +import React, { useState, useRef, useEffect } from "react"; +import { inject, observer } from "mobx-react"; +import { isMobile } from "react-device-detect"; + +import styled from "styled-components"; + +import TableContainer from "@docspace/components/table-container/TableContainer"; +import TableBody from "@docspace/components/table-container/TableBody"; + +import TableRow from "./TableRow"; +import TableHeader from "./TableHeader"; + +import { Base } from "@docspace/components/themes"; + +const TableWrapper = styled(TableContainer)` + margin-top: 16px; + + .header-container-text { + font-size: 12px; + } + + .table-container_header { + position: absolute; + } + + .table-list-item { + margin-top: -1px; + &:hover { + cursor: pointer; + background-color: ${(props) => + props.theme.isBase ? "#F8F9F9" : "#282828"}; + } + } +`; + +TableWrapper.defaultProps = { theme: Base }; + +const TABLE_VERSION = "5"; +const COLUMNS_SIZE = `webhooksConfigColumnsSize_ver-${TABLE_VERSION}`; +const INFO_PANEL_COLUMNS_SIZE = `infoPanelWebhooksConfigColumnsSize_ver-${TABLE_VERSION}`; + +const TableView = (props) => { + const { + webhooks, + loadWebhooks, + sectionWidth, + viewAs, + setViewAs, + openSettingsModal, + openDeleteModal, + userId, + } = props; + + const tableRef = useRef(null); + const [hideColumns, setHideColumns] = useState(false); + + useEffect(() => { + if (!sectionWidth) return; + if (sectionWidth < 1025 || isMobile) { + viewAs !== "row" && setViewAs("row"); + } else { + viewAs !== "table" && setViewAs("table"); + } + }, [sectionWidth]); + + const columnStorageName = `${COLUMNS_SIZE}=${userId}`; + const columnInfoPanelStorageName = `${INFO_PANEL_COLUMNS_SIZE}=${userId}`; + + return ( + + + + {webhooks.map((webhook, index) => ( + + ))} + + + ); +}; + +export default inject(({ webhooksStore, setup, auth }) => { + const { webhooks, loadWebhooks } = webhooksStore; + + const { viewAs, setViewAs } = setup; + const { id: userId } = auth.userStore.user; + + return { + webhooks, + viewAs, + setViewAs, + loadWebhooks, + userId, + }; +})(observer(TableView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js new file mode 100644 index 0000000000..17f9245c77 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js @@ -0,0 +1,38 @@ +import React from "react"; + +import { inject, observer } from "mobx-react"; +import { Consumer } from "@docspace/components/utils/context"; + +import TableView from "./TableView"; +import RowView from "./RowView"; + +const List = (props) => { + const { viewAs, openSettingsModal, openDeleteModal } = props; + + return ( + + {(context) => + viewAs === "table" ? ( + + ) : ( + + ) + } + + ); +}; +export default inject(({ setup }) => { + const { viewAs } = setup; + + return { + viewAs, + }; +})(observer(List)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js index f18e18a7e4..04a918b43d 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js @@ -9,6 +9,7 @@ import { useNavigate } from "react-router-dom"; import JavascriptSDK from "./JavascriptSDK"; import Webhooks from "./Webhooks"; +import OAuth from "./OAuth"; import AppLoader from "@docspace/common/components/AppLoader"; import SSOLoader from "./sub-components/ssoLoader"; @@ -48,6 +49,11 @@ const DeveloperToolsWrapper = (props) => { name: t("Webhooks:Webhooks"), content: , }, + { + id: "oauth", + name: "OAuth", + content: , + }, ]; const load = async () => { @@ -71,8 +77,8 @@ const DeveloperToolsWrapper = (props) => { combineUrl( window.DocSpaceConfig?.proxy?.url, config.homepage, - `/portal-settings/developer-tools/${e.id}`, - ), + `/portal-settings/developer-tools/${e.id}` + ) ); }; @@ -85,7 +91,9 @@ const DeveloperToolsWrapper = (props) => { ); - return ; + return ( + + ); }; export default inject(({ setup, webhooksStore }) => { diff --git a/packages/client/src/pages/PortalSettings/utils/settingsTree.js b/packages/client/src/pages/PortalSettings/utils/settingsTree.js index 4ee7be4cba..7f55dfa4d7 100644 --- a/packages/client/src/pages/PortalSettings/utils/settingsTree.js +++ b/packages/client/src/pages/PortalSettings/utils/settingsTree.js @@ -304,6 +304,14 @@ export const settingsTree = [ tKey: "DeveloperTools", isCategory: true, }, + { + id: "portal-settings_catalog-oauth", + key: "5-2", + icon: "", + link: "oauth", + tKey: "OAuth", + isCategory: true, + }, ], }, { diff --git a/packages/client/src/routes/portalSettings.js b/packages/client/src/routes/portalSettings.js index 09d42b06a7..118117d8ab 100644 --- a/packages/client/src/routes/portalSettings.js +++ b/packages/client/src/routes/portalSettings.js @@ -12,65 +12,100 @@ import { generalRoutes } from "./general"; const PortalSettings = loadable(() => import("../pages/PortalSettings")); const CustomizationSettings = loadable(() => - import("../pages/PortalSettings/categories/common/index.js"), + import("../pages/PortalSettings/categories/common/index.js") ); const LanguageAndTimeZoneSettings = loadable(() => - import("../pages/PortalSettings/categories/common/Customization/language-and-time-zone"), + import( + "../pages/PortalSettings/categories/common/Customization/language-and-time-zone" + ) ); const WelcomePageSettings = loadable(() => - import("../pages/PortalSettings/categories/common/Customization/welcome-page-settings"), + import( + "../pages/PortalSettings/categories/common/Customization/welcome-page-settings" + ) ); const DNSSettings = loadable(() => - import("../pages/PortalSettings/categories/common/Customization/dns-settings"), + import("../pages/PortalSettings/categories/common/Customization/dns-settings") ); const PortalRenaming = loadable(() => - import("../pages/PortalSettings/categories/common/Customization/portal-renaming"), + import( + "../pages/PortalSettings/categories/common/Customization/portal-renaming" + ) ); const WhiteLabel = loadable(() => - import("../pages/PortalSettings/categories/common/Branding/whitelabel"), + import("../pages/PortalSettings/categories/common/Branding/whitelabel") ); const SecuritySettings = loadable(() => - import("../pages/PortalSettings/categories/security/index.js"), + import("../pages/PortalSettings/categories/security/index.js") ); const TfaPage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/tfa"), + import("../pages/PortalSettings/categories/security/access-portal/tfa") ); const PasswordStrengthPage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/passwordStrength"), + import( + "../pages/PortalSettings/categories/security/access-portal/passwordStrength" + ) ); const TrustedMailPage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/trustedMail"), + import( + "../pages/PortalSettings/categories/security/access-portal/trustedMail" + ) ); const IpSecurityPage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/ipSecurity"), + import("../pages/PortalSettings/categories/security/access-portal/ipSecurity") ); const AdminMessagePage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/adminMessage"), + import( + "../pages/PortalSettings/categories/security/access-portal/adminMessage" + ) ); const SessionLifetimePage = loadable(() => - import("../pages/PortalSettings/categories/security/access-portal/sessionLifetime"), + import( + "../pages/PortalSettings/categories/security/access-portal/sessionLifetime" + ) +); +const Integration = loadable(() => + import("../pages/PortalSettings/categories/integration") +); +const Payments = loadable(() => + import("../pages/PortalSettings/categories/payments") ); -const Integration = loadable(() => import("../pages/PortalSettings/categories/integration")); -const Payments = loadable(() => import("../pages/PortalSettings/categories/payments")); const ThirdParty = loadable(() => - import("../pages/PortalSettings/categories/integration/ThirdPartyServicesSettings"), + import( + "../pages/PortalSettings/categories/integration/ThirdPartyServicesSettings" + ) ); const SingleSignOn = loadable(() => - import("../pages/PortalSettings/categories/integration/SingleSignOn"), + import("../pages/PortalSettings/categories/integration/SingleSignOn") ); const DeveloperTools = loadable(() => - import("../pages/PortalSettings/categories/developer-tools/index.js"), + import("../pages/PortalSettings/categories/developer-tools/index.js") ); const WebhookHistory = loadable(() => - import("../pages/PortalSettings/categories/developer-tools/Webhooks/WebhookHistory"), + import( + "../pages/PortalSettings/categories/developer-tools/Webhooks/WebhookHistory" + ) ); const WebhookDetails = loadable(() => - import("../pages/PortalSettings/categories/developer-tools/Webhooks/WebhookEventDetails"), + import( + "../pages/PortalSettings/categories/developer-tools/Webhooks/WebhookEventDetails" + ) +); +const OAuthDetails = loadable(() => + import( + "../pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails" + ) +); +const Backup = loadable(() => + import("../pages/PortalSettings/categories/data-management/index") +); +const DeleteDataPage = loadable(() => + import("../pages/PortalSettings/categories/delete-data") ); -const Backup = loadable(() => import("../pages/PortalSettings/categories/data-management/index")); -const DeleteDataPage = loadable(() => import("../pages/PortalSettings/categories/delete-data")); const RestoreBackup = loadable(() => - import("../pages/PortalSettings/categories/data-management/backup/restore-backup/index"), + import( + "../pages/PortalSettings/categories/data-management/backup/restore-backup/index" + ) ); const PortalSettingsRoutes = { @@ -192,6 +227,14 @@ const PortalSettingsRoutes = { path: "developer-tools/webhooks", element: , }, + { + path: "developer-tools/oauth", + element: , + }, + { + path: "developer-tools/oauth/:id", + element: , + }, { path: "developer-tools/webhooks/:id", element: , From fbaace1941c283c24c8725556b1dd26b0f35a6ab Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Tue, 27 Jun 2023 10:10:13 +0300 Subject: [PATCH 005/362] Web: Client: PortalSettings: Fixed OAuth settings page --- .../OAuth/sub-components/List/RowView/Row.js | 109 ------------------ .../sub-components/List/RowView/RowContent.js | 78 ------------- .../sub-components/List/RowView/index.js | 60 ---------- .../TableView/{TableHeader.js => Header.js} | 35 ++++-- .../List/TableView/{TableRow.js => Row.js} | 76 ++++++------ .../sub-components/List/TableView/index.js | 37 +++--- .../OAuth/sub-components/List/index.js | 32 ++--- packages/client/src/store/OAuthStore.js | 80 +++++++++++++ packages/client/src/store/index.js | 4 + 9 files changed, 171 insertions(+), 340 deletions(-) delete mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js delete mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js delete mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js rename packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/{TableHeader.js => Header.js} (79%) rename packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/{TableRow.js => Row.js} (67%) create mode 100644 packages/client/src/store/OAuthStore.js diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js deleted file mode 100644 index fcc13b3ebc..0000000000 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.js +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useState } from "react"; -import { inject, observer } from "mobx-react"; - -import { Row as ComponentRow } from "@docspace/components/row"; - -import { RowContent } from "./RowContent"; - -import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; -import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url"; -import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; - -import { useNavigate } from "react-router-dom"; -import { useTranslation } from "react-i18next"; - -export const Row = (props) => { - const { - webhook, - sectionWidth, - toggleEnabled, - openSettingsModal, - openDeleteModal, - setCurrentWebhook, - } = props; - const navigate = useNavigate(); - const { t } = useTranslation(["Webhooks", "Common"]); - - const [isChecked, setIsChecked] = useState(webhook.enabled); - - const handleToggleEnabled = () => { - toggleEnabled(webhook); - setIsChecked((prevIsChecked) => !prevIsChecked); - }; - - const redirectToHistory = () => { - navigate(window.location.pathname + `/${webhook.id}`); - }; - const handleRowClick = (e) => { - if ( - e.target.closest(".table-container_row-context-menu-wrapper") || - e.target.closest(".toggleButton") || - e.target.closest(".row_context-menu-wrapper") || - e.detail === 0 - ) { - return; - } - - redirectToHistory(); - }; - - const onSettingsOpen = () => { - setCurrentWebhook(webhook); - openSettingsModal(); - }; - const onDeleteOpen = () => { - setCurrentWebhook(webhook); - openDeleteModal(); - }; - - const contextOptions = [ - { - key: "Settings dropdownItem", - label: t("Common:Settings"), - icon: SettingsIcon, - onClick: onSettingsOpen, - }, - { - key: "Webhook history dropdownItem", - label: t("WebhookHistory"), - icon: HistoryIcon, - onClick: redirectToHistory, - }, - { - key: "Separator dropdownItem", - isSeparator: true, - }, - { - key: "Delete webhook dropdownItem", - label: t("DeleteWebhook"), - icon: DeleteIcon, - onClick: onDeleteOpen, - }, - ]; - - return ( - <> - - - - - ); -}; - -export default inject(({ webhooksStore }) => { - const { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook } = - webhooksStore; - - return { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook }; -})(observer(Row)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js deleted file mode 100644 index 1bdbca8ae2..0000000000 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.js +++ /dev/null @@ -1,78 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -import Text from "@docspace/components/text"; -import { RowContent as ComponentRowContent } from "@docspace/components/row-content"; -import ToggleButton from "@docspace/components/toggle-button"; - -//import StatusBadge from "../../StatusBadge"; - -import { isMobileOnly } from "react-device-detect"; - -const StyledRowContent = styled(ComponentRowContent)` - display: flex; - padding-bottom: 10px; - - .rowMainContainer { - height: 100%; - width: 100%; - } - - .mainIcons { - min-width: 76px; - } -`; - -const ContentWrapper = styled.div` - display: flex; - flex-direction: column; - justify-items: center; -`; - -const ToggleButtonWrapper = styled.div` - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: flex-end; - margin-left: -52px; -`; - -const FlexWrapper = styled.div` - display: flex; -`; - -export const RowContent = ({ - sectionWidth, - webhook, - isChecked, - handleToggleEnabled, -}) => { - return ( - - - - - {webhook.name} - - {/* */} - - - {!isMobileOnly && ( - - {webhook.uri} - - )} - - - - - - - ); -}; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js deleted file mode 100644 index 253f7e761f..0000000000 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useEffect } from "react"; -import styled from "styled-components"; -import { inject, observer } from "mobx-react"; - -import { isMobile } from "react-device-detect"; - -import RowContainer from "@docspace/components/row-container"; - -import Row from "./Row"; - -const StyledRowContainer = styled(RowContainer)` - margin-top: 16px; -`; - -const RowView = (props) => { - const { - webhooks, - sectionWidth, - viewAs, - setViewAs, - openSettingsModal, - openDeleteModal, - } = props; - - useEffect(() => { - if (viewAs !== "table" && viewAs !== "row") return; - - if (sectionWidth < 1025 || isMobile) { - viewAs !== "row" && setViewAs("row"); - } else { - viewAs !== "table" && setViewAs("table"); - } - }, [sectionWidth]); - - return ( - - {webhooks.map((webhook) => ( - - ))} - - ); -}; - -export default inject(({ webhooksStore, setup }) => { - const { webhooks } = webhooksStore; - - const { viewAs, setViewAs } = setup; - - return { - webhooks, - viewAs, - setViewAs, - }; -})(observer(RowView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js similarity index 79% rename from packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js rename to packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js index 9786e9e223..11b223df74 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableHeader.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js @@ -1,11 +1,11 @@ import React, { useState } from "react"; -import { TableHeader as Header } from "@docspace/components/table-container/TableHeader"; +import TableHeader from "@docspace/components/table-container/TableHeader"; import { useTranslation } from "react-i18next"; import { inject, observer } from "mobx-react"; -const TABLE_VERSION = "5"; -const TABLE_COLUMNS = `webhooksConfigColumns_ver-${TABLE_VERSION}`; +const TABLE_VERSION = "1"; +const TABLE_COLUMNS = `oauthConfigColumns_ver-${TABLE_VERSION}`; const getColumns = (defaultColumns, userId) => { const storageColumns = localStorage.getItem(`${TABLE_COLUMNS}=${userId}`); @@ -26,7 +26,7 @@ const getColumns = (defaultColumns, userId) => { } }; -const TableHeader = (props) => { +const Header = (props) => { const { userId, sectionWidth, @@ -38,6 +38,15 @@ const TableHeader = (props) => { const { t } = useTranslation(["Webhooks", "Common"]); const defaultColumns = [ + { + key: "Logo", + title: "Logo", + enable: true, + active: true, + resizable: false, + defaultSize: 64, + onChange: onColumnChange, + }, { key: "Name", title: t("Common:Name"), @@ -49,17 +58,19 @@ const TableHeader = (props) => { onChange: onColumnChange, }, { - key: "URL", - title: t("URL"), - enable: true, + key: "Description", + title: "Description", resizable: true, + enable: true, + minWidth: 150, onChange: onColumnChange, }, { - key: "State", - title: t("State"), + key: "Enable", + title: "Enable", enable: true, - resizable: true, + resizable: false, + defaultSize: 64, onChange: onColumnChange, }, ]; @@ -82,7 +93,7 @@ const TableHeader = (props) => { } return ( -
{ return { userId: auth.userStore.user.id, }; -})(observer(TableHeader)); +})(observer(Header)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js similarity index 67% rename from packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js rename to packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js index 2191a85e1e..ff0d4bfddd 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableRow.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js @@ -1,6 +1,6 @@ import React, { useState } from "react"; import styled from "styled-components"; -import { TableRow as Row } from "@docspace/components/table-container/TableRow"; +import TableRow from "@docspace/components/table-container/TableRow"; import TableCell from "@docspace/components/table-container/TableCell"; import Text from "@docspace/components/text"; @@ -8,6 +8,7 @@ import ToggleButton from "@docspace/components/toggle-button"; import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url"; import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; +import LinuxIcon from "PUBLIC_DIR/images/linux.react.svg?url"; //import StatusBadge from "../../StatusBadge"; import { useNavigate } from "react-router-dom"; @@ -19,7 +20,7 @@ const StyledWrapper = styled.div` display: contents; `; -const StyledTableRow = styled(Row)` +const StyledTableRow = styled(TableRow)` .table-container_cell { padding-right: 30px; text-overflow: ellipsis; @@ -28,30 +29,35 @@ const StyledTableRow = styled(Row)` .mr-8 { margin-right: 8px; } + .textOverflow { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + + .toggleButton { + display: contents; + } `; -const TableRow = (props) => { +const Row = (props) => { const { - webhook, - toggleEnabled, + item, + setEnabled, openSettingsModal, openDeleteModal, - setCurrentWebhook, + setCurrentProject, hideColumns, } = props; const navigate = useNavigate(); const { t } = useTranslation(["Webhooks", "Common"]); - const [isChecked, setIsChecked] = useState(webhook.enabled); + const [isChecked, setIsChecked] = useState(item.token.enable); const redirectToHistory = () => { - navigate(window.location.pathname + `/${webhook.id}`); + navigate(window.location.pathname + `/${item.id}`); }; const handleRowClick = (e) => { @@ -69,39 +75,33 @@ const TableRow = (props) => { redirectToHistory(); }; const handleToggleEnabled = () => { - toggleEnabled(webhook); + setEnabled(item.id); setIsChecked((prevIsChecked) => !prevIsChecked); }; const onSettingsOpen = () => { - setCurrentWebhook(webhook); - openSettingsModal(); + setCurrentProject(item); + //openSettingsModal(); }; const onDeleteOpen = () => { - setCurrentWebhook(webhook); - openDeleteModal(); + setCurrentProject(item); + //openDeleteModal(); }; const contextOptions = [ { - key: "Settings dropdownItem", + key: "settings", label: t("Common:Settings"), icon: SettingsIcon, onClick: onSettingsOpen, }, - { - key: "Webhook history dropdownItem", - label: t("WebhookHistory"), - icon: HistoryIcon, - onClick: redirectToHistory, - }, { key: "Separator dropdownItem", isSeparator: true, }, { - key: "Delete webhook dropdownItem", - label: t("DeleteWebhook"), + key: "delete", + label: t("Common:Delete"), icon: DeleteIcon, onClick: onDeleteOpen, }, @@ -115,26 +115,21 @@ const TableRow = (props) => { hideColumns={hideColumns} > - - {webhook.name}{" "} - - {/* */} + - - {webhook.uri} + + {item.general.name} + + + + + {item.general.description} @@ -145,11 +140,8 @@ const TableRow = (props) => { ); }; -export default inject(({ webhooksStore }) => { - const { toggleEnabled, setCurrentWebhook } = webhooksStore; +export default inject(({ oauthStore }) => { + const { setCurrentProject, setEnabled } = oauthStore; - return { - toggleEnabled, - setCurrentWebhook, - }; -})(observer(TableRow)); + return { setEnabled, setCurrentProject }; +})(observer(Row)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js index d0367f0a46..caba6b2627 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js @@ -7,8 +7,8 @@ import styled from "styled-components"; import TableContainer from "@docspace/components/table-container/TableContainer"; import TableBody from "@docspace/components/table-container/TableBody"; -import TableRow from "./TableRow"; -import TableHeader from "./TableHeader"; +import Row from "./Row"; +import Header from "./Header"; import { Base } from "@docspace/components/themes"; @@ -35,14 +35,14 @@ const TableWrapper = styled(TableContainer)` TableWrapper.defaultProps = { theme: Base }; -const TABLE_VERSION = "5"; -const COLUMNS_SIZE = `webhooksConfigColumnsSize_ver-${TABLE_VERSION}`; -const INFO_PANEL_COLUMNS_SIZE = `infoPanelWebhooksConfigColumnsSize_ver-${TABLE_VERSION}`; +const TABLE_VERSION = "1"; +const COLUMNS_SIZE = `oauthConfigColumnsSize_ver-${TABLE_VERSION}`; +const INFO_PANEL_COLUMNS_SIZE = `infoPanelOauthConfigColumnsSize_ver-${TABLE_VERSION}`; const TableView = (props) => { const { - webhooks, - loadWebhooks, + items, + getProjects, sectionWidth, viewAs, setViewAs, @@ -68,7 +68,7 @@ const TableView = (props) => { return ( - { infoPanelVisible={false} columnStorageName={columnStorageName} columnInfoPanelStorageName={columnInfoPanelStorageName} - filesLength={webhooks.length} - fetchMoreFiles={loadWebhooks} + filesLength={items.length} + fetchMoreFiles={getProjects} hasMoreFiles={false} - itemCount={webhooks.length} + itemCount={items.length} > - {webhooks.map((webhook, index) => ( - ( + { ); }; -export default inject(({ webhooksStore, setup, auth }) => { - const { webhooks, loadWebhooks } = webhooksStore; +export default inject(({ oauthStore, setup, auth }) => { + const { getProjects } = oauthStore; const { viewAs, setViewAs } = setup; const { id: userId } = auth.userStore.user; return { - webhooks, viewAs, setViewAs, - loadWebhooks, + getProjects, userId, }; })(observer(TableView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js index 17f9245c77..cc16c8aa1c 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js @@ -4,35 +4,27 @@ import { inject, observer } from "mobx-react"; import { Consumer } from "@docspace/components/utils/context"; import TableView from "./TableView"; -import RowView from "./RowView"; - -const List = (props) => { - const { viewAs, openSettingsModal, openDeleteModal } = props; +const List = ({ viewAs, openSettingsModal, openDeleteModal, projects }) => { return ( - {(context) => - viewAs === "table" ? ( - - ) : ( - - ) - } + {(context) => ( + + )} ); }; -export default inject(({ setup }) => { +export default inject(({ setup, oauthStore }) => { const { viewAs } = setup; + const { projects } = oauthStore; return { viewAs, + projects, }; })(observer(List)); diff --git a/packages/client/src/store/OAuthStore.js b/packages/client/src/store/OAuthStore.js new file mode 100644 index 0000000000..24d2aad2e4 --- /dev/null +++ b/packages/client/src/store/OAuthStore.js @@ -0,0 +1,80 @@ +import { makeAutoObservable, runInAction } from "mobx"; + +const projects = [...Array(10)].map((value, index) => { + return { + id: index, + general: { + name: `Project ${index}`, + description: `Description ${index}`, + }, + credentials: { + client_id: "random_client_id", + client_secret: "random_client_secret", + }, + token: { + enable: true, + bearer_only: true, + public_client: false, + }, + scopes: { + files: { + read: true, + write: true, + }, + workspaces: { + read: false, + write: false, + }, + users: { + read: false, + write: false, + }, + }, + links: { + installation_url: "https://example.com/install", + redirect_url: "https://example.com/redirect", + allowed_origins: "https://example.com", + }, + }; +}); + +class OAuthStore { + projects = projects; + currentProject = {}; + + constructor() { + makeAutoObservable(this); + } + + getProjects = () => { + this.projects = projects; + }; + + setCurrentProject = (project) => { + this.currentProject = project; + }; + + addProject = (project) => { + this.projects = [...this.projects, project]; + }; + + setEnabled = (id) => { + const index = this.projects.findIndex((proj) => proj.id === id); + + this.projects[index].token.enable = !this.projects[index].token.enable; + }; + + deleteProject = (id) => { + this.projects = this.projects.filter((proj) => proj.id !== id); + }; + + editProject = (project) => { + const index = this.projects.findIndex((proj) => proj.id === project.id); + + runInAction(() => { + this.projects[index] = project; + }); + }; +} + +export default OAuthStore; diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js index f7babf72d5..b70767edbe 100644 --- a/packages/client/src/store/index.js +++ b/packages/client/src/store/index.js @@ -37,6 +37,7 @@ import CreateEditRoomStore from "./CreateEditRoomStore"; import WebhooksStore from "./WebhooksStore"; import ClientLoadingStore from "./ClientLoadingStore"; +import OAuthStore from "./OAuthStore"; const oformsStore = new OformsStore(authStore); @@ -172,6 +173,8 @@ const createEditRoomStore = new CreateEditRoomStore( const webhooksStore = new WebhooksStore(); +const oauthStore = new OAuthStore(); + const store = { auth: authStore, payments: paymentStore, @@ -210,6 +213,7 @@ const store = { webhooksStore, clientLoadingStore, + oauthStore, }; export default store; From e173c5932db498c5c1d1eda6fd3ec4f0ac9433cb Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Tue, 27 Jun 2023 17:51:01 +0300 Subject: [PATCH 006/362] Web: Client: OAuth: Added view page --- .../OAuth/OAuthDetails/index.js | 89 +++++++++++++++++-- .../categories/developer-tools/OAuth/index.js | 34 +++++-- .../OAuth/sub-components/DeleteDialog.js | 71 +++++++++++++++ .../sub-components/List/TableView/Header.js | 4 +- .../sub-components/List/TableView/Row.js | 45 +++++----- .../sub-components/List/TableView/index.js | 8 +- .../OAuth/sub-components/List/index.js | 8 +- packages/client/src/store/OAuthStore.js | 85 ++++++++---------- 8 files changed, 250 insertions(+), 94 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/DeleteDialog.js diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js index 296c3669bb..8ee1ac9293 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js @@ -18,28 +18,103 @@ const Container = styled.div` margin-top: 5px; `; +const Property = styled.div` + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 16px; +`; + const OAuthDetails = (props) => { - const { t, setDocumentTitle } = props; + const { t, setDocumentTitle, currentClient } = props; setDocumentTitle("OAuth"); return ( <> - {isMobile ? ( - - ) : ( - Test - )} + + + + + + + + + + + + + + + + + + ); }; -export default inject(({ setup, auth }) => { +export default inject(({ setup, auth, oauthStore }) => { const { settingsStore, setDocumentTitle } = auth; const { theme } = settingsStore; + const { currentClient } = oauthStore; return { theme, setDocumentTitle, + currentClient, }; })(withTranslation(["Common"])(observer(OAuthDetails))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js index 03c7918736..1743bbc51d 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js @@ -13,29 +13,49 @@ import { inject, observer } from "mobx-react"; import { isMobile } from "react-device-detect"; import BreakpointWarning from "SRC_DIR/components/BreakpointWarning"; import List from "./sub-components/List"; +import DeleteDialog from "./sub-components/DeleteDialog"; const OAuth = (props) => { - const { t, setDocumentTitle } = props; + const { + t, + setDocumentTitle, + getClients, + deleteClient, + currentClient, + } = props; + + const [isDeleteOpened, setIsDeleteOpened] = useState(false); + + const closeDeleteModal = () => setIsDeleteOpened(false); + const openDeleteModal = () => setIsDeleteOpened(true); + + useEffect(() => getClients(), []); setDocumentTitle("OAuth"); return ( <> - {isMobile ? ( - - ) : ( - {}} openDeleteModal={() => {}} /> - )} + + ); }; -export default inject(({ setup, auth }) => { +export default inject(({ setup, auth, oauthStore }) => { const { settingsStore, setDocumentTitle } = auth; + const { getClients, deleteClient, currentClient } = oauthStore; const { theme } = settingsStore; return { theme, setDocumentTitle, + getClients, + deleteClient, + currentClient, }; })(withTranslation(["Common"])(observer(OAuth))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/DeleteDialog.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/DeleteDialog.js new file mode 100644 index 0000000000..822afbfcb8 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/DeleteDialog.js @@ -0,0 +1,71 @@ +import React, { useEffect } from "react"; +import ModalDialog from "@docspace/components/modal-dialog"; +import Button from "@docspace/components/button"; +import styled from "styled-components"; +import { useTranslation } from "react-i18next"; + +const StyledBodyText = styled.div` + line-height: 20px; +`; + +const Footer = styled.div` + width: 100%; + display: flex; + + button { + width: 100%; + } + button:first-of-type { + margin-right: 10px; + } +`; + +const DeleteDialog = ({ + visible, + onClose, + header, + handleSubmit, + currentClient, +}) => { + const onKeyPress = (e) => + (e.key === "Esc" || e.key === "Escape") && onClose(); + + const { t } = useTranslation(["Common", "EmptyTrashDialog"]); + + useEffect(() => { + window.addEventListener("keyup", onKeyPress); + return () => window.removeEventListener("keyup", onKeyPress); + }); + + const handleDeleteClick = () => { + handleSubmit(currentClient.id); + onClose(); + }; + + return ( + + {`Delete profile`} + + {`Do you want to delete profile: ${currentClient.name}`} + + + +
+
+
+
+ ); +}; + +export default DeleteDialog; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js index 11b223df74..efaff96bd2 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.js @@ -84,11 +84,11 @@ const Header = (props) => { setColumns((prevColumns) => prevColumns.map((item, index) => - index === columnIndex ? { ...item, enable: !item.enable } : item + index === columnIndex ? { ...item, enabled: !item.enabled } : item ) ); - const tableColumns = columns.map((c) => c.enable && c.key); + const tableColumns = columns.map((c) => c.enabled && c.key); localStorage.setItem(`${TABLE_COLUMNS}=${userId}`, tableColumns); } diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js index ff0d4bfddd..0565cfb206 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.js @@ -45,21 +45,35 @@ const Row = (props) => { const { item, setEnabled, - openSettingsModal, openDeleteModal, - setCurrentProject, + setCurrentClient, hideColumns, } = props; const navigate = useNavigate(); const { t } = useTranslation(["Webhooks", "Common"]); - const [isChecked, setIsChecked] = useState(item.token.enable); + const [isChecked, setIsChecked] = useState(item.enabled); - const redirectToHistory = () => { + const openClientSettings = () => { navigate(window.location.pathname + `/${item.id}`); }; + const handleToggleEnabled = () => { + setEnabled(item.id); + setIsChecked((prevIsChecked) => !prevIsChecked); + }; + + const onSettingsOpen = () => { + setCurrentClient(item); + openClientSettings(); + }; + + const onDeleteOpen = () => { + setCurrentClient(item); + openDeleteModal(); + }; + const handleRowClick = (e) => { if ( e.target.closest(".checkbox") || @@ -72,20 +86,7 @@ const Row = (props) => { return; } - redirectToHistory(); - }; - const handleToggleEnabled = () => { - setEnabled(item.id); - setIsChecked((prevIsChecked) => !prevIsChecked); - }; - - const onSettingsOpen = () => { - setCurrentProject(item); - //openSettingsModal(); - }; - const onDeleteOpen = () => { - setCurrentProject(item); - //openDeleteModal(); + onSettingsOpen(); }; const contextOptions = [ @@ -119,12 +120,12 @@ const Row = (props) => {
- {item.general.name} + {item.name} - {item.general.description} + {item.description} @@ -141,7 +142,7 @@ const Row = (props) => { }; export default inject(({ oauthStore }) => { - const { setCurrentProject, setEnabled } = oauthStore; + const { setCurrentClient, setEnabled } = oauthStore; - return { setEnabled, setCurrentProject }; + return { setEnabled, setCurrentClient }; })(observer(Row)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js index caba6b2627..7284a941b0 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.js @@ -42,7 +42,7 @@ const INFO_PANEL_COLUMNS_SIZE = `infoPanelOauthConfigColumnsSize_ver-${TABLE_VER const TableView = (props) => { const { items, - getProjects, + getClients, sectionWidth, viewAs, setViewAs, @@ -82,7 +82,7 @@ const TableView = (props) => { columnStorageName={columnStorageName} columnInfoPanelStorageName={columnInfoPanelStorageName} filesLength={items.length} - fetchMoreFiles={getProjects} + fetchMoreFiles={getClients} hasMoreFiles={false} itemCount={items.length} > @@ -102,7 +102,7 @@ const TableView = (props) => { }; export default inject(({ oauthStore, setup, auth }) => { - const { getProjects } = oauthStore; + const { getClients } = oauthStore; const { viewAs, setViewAs } = setup; const { id: userId } = auth.userStore.user; @@ -110,7 +110,7 @@ export default inject(({ oauthStore, setup, auth }) => { return { viewAs, setViewAs, - getProjects, + getClients, userId, }; })(observer(TableView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js index cc16c8aa1c..6663d3bc2e 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.js @@ -5,12 +5,12 @@ import { Consumer } from "@docspace/components/utils/context"; import TableView from "./TableView"; -const List = ({ viewAs, openSettingsModal, openDeleteModal, projects }) => { +const List = ({ viewAs, openSettingsModal, openDeleteModal, clients }) => { return ( {(context) => ( { }; export default inject(({ setup, oauthStore }) => { const { viewAs } = setup; - const { projects } = oauthStore; + const { clients } = oauthStore; return { viewAs, - projects, + clients, }; })(observer(List)); diff --git a/packages/client/src/store/OAuthStore.js b/packages/client/src/store/OAuthStore.js index 24d2aad2e4..8642f4ac20 100644 --- a/packages/client/src/store/OAuthStore.js +++ b/packages/client/src/store/OAuthStore.js @@ -1,78 +1,67 @@ import { makeAutoObservable, runInAction } from "mobx"; -const projects = [...Array(10)].map((value, index) => { +const clients = [...Array(5)].map((value, index) => { return { id: index, - general: { - name: `Project ${index}`, - description: `Description ${index}`, - }, - credentials: { - client_id: "random_client_id", - client_secret: "random_client_secret", - }, - token: { - enable: true, - bearer_only: true, - public_client: false, - }, - scopes: { - files: { - read: true, - write: true, - }, - workspaces: { - read: false, - write: false, - }, - users: { - read: false, - write: false, - }, - }, - links: { - installation_url: "https://example.com/install", - redirect_url: "https://example.com/redirect", - allowed_origins: "https://example.com", - }, + name: `46192a5a-e19c-${index}`, + description: "Demo description", + client_id: "46192a5a-e19c-453c-aec3-50617290edbe", + client_secret: "e5ff57e4-4ce2-4dac-a265-88bc7e726684", + root_url: "https://google.com", + redirect_uris: ["https://openidconnect.net/callback"], + allowed_origins: [ + "https://google.com", + "https://openidconnect.net/callback", + ], + scopes: [ + "files:write", + "accounts:write", + "files:read", + "account.self:write", + "rooms:read", + "accounts:read", + "account.self:read", + "rooms:write", + ], + enabled: true, }; }); class OAuthStore { - projects = projects; - currentProject = {}; + clients = []; + currentClient = clients[0]; constructor() { makeAutoObservable(this); } - getProjects = () => { - this.projects = projects; + getClients = () => { + this.clients = clients; }; - setCurrentProject = (project) => { - this.currentProject = project; + setCurrentClient = (client) => { + this.currentClient = client; }; - addProject = (project) => { - this.projects = [...this.projects, project]; + addClient = (client) => { + this.clients = [...this.clients, client]; }; setEnabled = (id) => { - const index = this.projects.findIndex((proj) => proj.id === id); + const index = this.clients.findIndex((proj) => proj.id === id); - this.projects[index].token.enable = !this.projects[index].token.enable; + this.clients[index].enabled = !this.clients[index].enabled; }; - deleteProject = (id) => { - this.projects = this.projects.filter((proj) => proj.id !== id); + deleteClient = (id) => { + this.clients = this.clients.filter((proj) => proj.id !== id); }; - editProject = (project) => { - const index = this.projects.findIndex((proj) => proj.id === project.id); + editClient = (client) => { + const index = this.clients.findIndex((proj) => proj.id === client.id); runInAction(() => { - this.projects[index] = project; + this.clients[index] = client; }); }; } From a4d69eebe8b67b0096de63c6f13a03dd8f493693 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Thu, 29 Jun 2023 17:41:53 +0300 Subject: [PATCH 007/362] Web: Client: OAuth: Fixed DTO and client view styles --- .../OAuth/OAuthDetails/index.js | 196 +++++++++--------- .../developer-tools/OAuth/StyledOAuth.js | 28 +++ .../OAuth/sub-components/Category.js | 59 ++++++ packages/client/src/store/OAuthStore.js | 32 +-- 4 files changed, 207 insertions(+), 108 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/Category.js diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js index 8ee1ac9293..2d2e04d67e 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuthDetails/index.js @@ -1,109 +1,115 @@ import React, { useState, useEffect } from "react"; import { withTranslation } from "react-i18next"; -import styled from "styled-components"; -import Box from "@docspace/components/box"; import TextInput from "@docspace/components/text-input"; -import Textarea from "@docspace/components/textarea"; import Label from "@docspace/components/label"; -import Checkbox from "@docspace/components/checkbox"; -import Button from "@docspace/components/button"; -import ComboBox from "@docspace/components/combobox"; -import Heading from "@docspace/components/heading"; import { inject, observer } from "mobx-react"; -import { isMobile } from "react-device-detect"; -import BreakpointWarning from "SRC_DIR/components/BreakpointWarning"; - -const Container = styled.div` - width: 100%; - margin-top: 5px; -`; - -const Property = styled.div` - display: flex; - align-items: center; - gap: 16px; - margin-bottom: 16px; -`; +import StyledSettingsSeparator from "SRC_DIR/pages/PortalSettings/StyledSettingsSeparator"; +import Category from "../sub-components/Category"; +import { Container, Property } from "../StyledOAuth"; const OAuthDetails = (props) => { - const { t, setDocumentTitle, currentClient } = props; + const { t, setDocumentTitle, currentClient, theme } = props; setDocumentTitle("OAuth"); return ( - <> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js new file mode 100644 index 0000000000..0668400969 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/StyledOAuth.js @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export const Container = styled.div` + width: 100%; + margin-top: 5px; +`; + +export const Property = styled.div` + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 16px; + width: 500px; +`; + +export const StyledCategory = styled.div` + display: flex; + flex-direction: row; + gap: 4px; + margin-bottom: 16px; + align-items: center; +`; + +export const StyledTooltip = styled.div` + .subtitle { + margin-bottom: 10px; + } +`; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/Category.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/Category.js new file mode 100644 index 0000000000..2a0bf69f4f --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/Category.js @@ -0,0 +1,59 @@ +import InfoReactSvgUrl from "PUBLIC_DIR/images/info.react.svg?url"; +import React from "react"; +import Text from "@docspace/components/text"; +import HelpButton from "@docspace/components/help-button"; +import Link from "@docspace/components/link"; +import { Base } from "@docspace/components/themes"; +import { StyledCategory, StyledTooltip } from "../StyledOAuth"; + +const Category = (props) => { + const { + t, + title, + tooltipTitle, + tooltipUrl, + theme, + currentColorScheme, + } = props; + + const tooltip = () => ( + + + {tooltipTitle} + + {tooltipUrl && ( + + {t("Common:LearnMore")} + + )} + + ); + + return ( + + + {title} + + + + ); +}; + +Category.defaultProps = { + theme: Base, +}; + +export default Category; diff --git a/packages/client/src/store/OAuthStore.js b/packages/client/src/store/OAuthStore.js index 8642f4ac20..207fa4431b 100644 --- a/packages/client/src/store/OAuthStore.js +++ b/packages/client/src/store/OAuthStore.js @@ -2,9 +2,10 @@ import { makeAutoObservable, runInAction } from "mobx"; const clients = [...Array(5)].map((value, index) => { return { + enabled: true, id: index, - name: `46192a5a-e19c-${index}`, - description: "Demo description", + name: `7383bc80-b0ad-4fad-8850-${index}`, + description: "Application description", client_id: "46192a5a-e19c-453c-aec3-50617290edbe", client_secret: "e5ff57e4-4ce2-4dac-a265-88bc7e726684", root_url: "https://google.com", @@ -13,20 +14,25 @@ const clients = [...Array(5)].map((value, index) => { "https://google.com", "https://openidconnect.net/callback", ], - scopes: [ - "files:write", - "accounts:write", - "files:read", - "account.self:write", - "rooms:read", - "accounts:read", - "account.self:read", - "rooms:write", - ], - enabled: true, + scopes: ["accounts:write", "accounts:read"], + logo_uri: "https://logo2.example", + policy_uri: "https://policy2.example", + terms_uri: "https://terms2.example", + state: "draft", }; }); +const scopes = [ + "files:read", + "files:write", + "rooms:read", + "rooms:write", + "account.self:read", + "account.self:write", + "accounts:read", + "accounts:write", +]; + class OAuthStore { clients = []; currentClient = clients[0]; From 2a36d19707345b5b7b1b48146771361f32f1427f Mon Sep 17 00:00:00 2001 From: Dmitrii Vershinin Date: Wed, 13 Sep 2023 16:10:28 +0500 Subject: [PATCH 008/362] feat: authorization server --- web/ASC.OAuth/.gitignore | 40 ++ .../api/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../api/.mvn/wrapper/maven-wrapper.properties | 2 + web/ASC.OAuth/api/Dockerfile | 10 + web/ASC.OAuth/api/HELP.md | 29 ++ web/ASC.OAuth/api/Makefile | 19 + web/ASC.OAuth/api/artillery.yml | 80 ++++ web/ASC.OAuth/api/mvnw | 308 ++++++++++++++++ web/ASC.OAuth/api/mvnw.cmd | 205 ++++++++++ web/ASC.OAuth/api/pom.xml | 148 ++++++++ .../authorization/api/ApplicationAPI.java | 15 + .../ApplicationConfiguration.java | 39 ++ .../SocketCommandLineRunner.java | 18 + .../configuration/WebSocketConfiguration.java | 22 ++ .../AuthorizationQueueConfiguration.java | 75 ++++ .../messaging/ClientQueueConfiguration.java | 73 ++++ .../messaging/ConsentQueueConfiguration.java | 75 ++++ .../messaging/GenericQueueConfiguration.java | 24 ++ .../messaging/RabbitMQConfiguration.java | 88 +++++ .../WebSocketQueueConfiguration.java | 43 +++ .../api/controllers/ClientController.java | 287 ++++++++++++++ .../api/controllers/ScopeController.java | 66 ++++ .../api/controllers/WebSocketController.java | 37 ++ .../ClientNotFoundExceptionHandler.java | 25 ++ .../EntityAlreadyExistsExceptionHandler.java | 25 ++ .../advice/ExecutionExceptionHandler.java | 26 ++ .../advice/RateLimiterExceptionHandler.java | 26 ++ .../advice/TimeLimiterExceptionHandler.java | 27 ++ .../api/crypto/AesGcmCipher.java | 103 ++++++ .../authorization/api/crypto/Cipher.java | 6 + .../authorization/api/dto/ClientDTO.java | 42 +++ .../authorization/api/dto/ErrorDTO.java | 12 + .../authorization/api/dto/PaginationDTO.java | 22 ++ .../authorization/api/dto/RegenerateDTO.java | 17 + .../authorization/api/dto/ScopeDTO.java | 17 + .../api/entities/Authorization.java | 72 ++++ .../authorization/api/entities/Client.java | 55 +++ .../authorization/api/entities/Consent.java | 53 +++ .../authorization/api/entities/Tenant.java | 29 ++ .../exceptions/ClientNotFoundException.java | 22 ++ .../EntityAlreadyExistsException.java | 22 ++ .../exceptions/ScopeNotFoundException.java | 22 ++ .../api/mappers/AuthorizationMapper.java | 19 + .../api/mappers/ClientMapper.java | 54 +++ .../api/mappers/ConsentMapper.java | 19 + .../listeners/AuthorizationListener.java | 79 ++++ .../messaging/listeners/ClientListener.java | 86 +++++ .../messaging/listeners/ConsentListener.java | 76 ++++ .../listeners/SocketNotificationListener.java | 31 ++ .../messages/AuthorizationMessage.java | 38 ++ .../messaging/messages/ConsentMessage.java | 19 + .../messages/NotificationMessage.java | 15 + .../messages/wrappers/MessageWrapper.java | 19 + .../repositories/AuthorizationRepository.java | 8 + .../api/repositories/ClientRepository.java | 32 ++ .../api/repositories/ConsentRepository.java | 8 + .../api/repositories/ReadOnlyRepository.java | 13 + .../api/repositories/TenantRepository.java | 6 + .../api/services/AuthorizationService.java | 67 ++++ .../api/services/ClientService.java | 119 ++++++ .../api/services/ConsentService.java | 61 +++ .../api/src/main/resources/application.yml | 141 +++++++ .../main/resources/migration/V1_1__init.sql | 114 ++++++ web/ASC.OAuth/api/src/test/application.yml | 124 +++++++ .../api/ApplicationAPITests.java | 13 + .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 62547 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + web/ASC.OAuth/authorization/Dockerfile | 10 + web/ASC.OAuth/authorization/HELP.md | 30 ++ web/ASC.OAuth/authorization/mvnw | 308 ++++++++++++++++ web/ASC.OAuth/authorization/mvnw.cmd | 205 ++++++++++ web/ASC.OAuth/authorization/pom.xml | 142 +++++++ .../AuthorizationApplication.java | 13 + .../caching/AuthorizationCache.java | 40 ++ .../ApplicationConfiguration.java | 88 +++++ .../AuthorizationServerConfiguration.java | 116 ++++++ .../configuration/DocspaceConfiguration.java | 14 + .../RegisteredClientConfiguration.java | 16 + .../caching/CacheConfiguration.java | 109 ++++++ .../CacheAuthorizationMapConfig.java | 46 +++ .../messaging/GenericQueueConfiguration.java | 24 ++ .../messaging/RabbitMQConfiguration.java | 79 ++++ .../AuthorizationConsentController.java | 75 ++++ .../controllers/LoginController.java | 27 ++ .../dto/UsernamePasswordCredentials.java | 14 + .../dto/messages/AuthorizationMessage.java | 38 ++ .../dto/messages/ConsentMessage.java | 19 + .../dto/messages/wrappers/MessageWrapper.java | 19 + .../authorization/entities/Authorization.java | 73 ++++ .../authorization/entities/Client.java | 44 +++ .../authorization/entities/Consent.java | 55 +++ ...AuthenticationMethodNotFoundException.java | 22 ++ .../exceptions/ClientNotFoundException.java | 23 ++ .../ReadOnlyOperationException.java | 22 ++ .../extensions/filters/CookieCsrfFilter.java | 26 ++ .../extensions/filters/SimpleCORSFilter.java | 31 ++ .../extensions/jwks/ECGenerator.java | 64 ++++ .../extensions/jwks/JwksKeyPairGenerator.java | 14 + .../extensions/jwks/RSAGenerator.java | 34 ++ .../DocspaceAuthenticationProvider.java | 60 +++ .../DocspaceRegisteredClientRepository.java | 114 ++++++ ...paceOAuth2AuthorizationConsentService.java | 90 +++++ .../DocspaceOAuth2AuthorizationService.java | 349 ++++++++++++++++++ .../repositories/AuthorizationRepository.java | 22 ++ .../repositories/ClientRepository.java | 11 + .../repositories/ConsentRepository.java | 10 + .../src/main/resources/application.yml | 82 ++++ .../main/resources/templates/authorized.html | 10 + .../src/main/resources/templates/error.html | 10 + .../AuthorizationApplicationTests.java | 13 + web/ASC.OAuth/client/.gitignore | 23 ++ web/ASC.OAuth/client/README.md | 70 ++++ web/ASC.OAuth/client/package.json | 41 ++ web/ASC.OAuth/client/public/favicon.ico | Bin 0 -> 3870 bytes web/ASC.OAuth/client/public/index.html | 22 ++ web/ASC.OAuth/client/src/App.jsx | 38 ++ web/ASC.OAuth/client/src/Consent.jsx | 144 ++++++++ web/ASC.OAuth/client/src/Error.jsx | 7 + web/ASC.OAuth/client/src/Login.jsx | 86 +++++ web/ASC.OAuth/client/src/index.css | 10 + web/ASC.OAuth/client/src/index.jsx | 17 + web/ASC.OAuth/client/src/reportWebVitals.js | 13 + web/ASC.OAuth/docker-compose.yml | 45 +++ web/ASC.OAuth/pom.xml | 121 ++++++ 124 files changed, 6737 insertions(+) create mode 100644 web/ASC.OAuth/.gitignore create mode 100644 web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.jar create mode 100644 web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.properties create mode 100644 web/ASC.OAuth/api/Dockerfile create mode 100644 web/ASC.OAuth/api/HELP.md create mode 100644 web/ASC.OAuth/api/Makefile create mode 100644 web/ASC.OAuth/api/artillery.yml create mode 100755 web/ASC.OAuth/api/mvnw create mode 100644 web/ASC.OAuth/api/mvnw.cmd create mode 100644 web/ASC.OAuth/api/pom.xml create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/ApplicationAPI.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/ApplicationConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/SocketCommandLineRunner.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/WebSocketConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/AuthorizationQueueConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ClientQueueConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ConsentQueueConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/GenericQueueConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/RabbitMQConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/WebSocketQueueConfiguration.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ClientController.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ScopeController.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/WebSocketController.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ClientNotFoundExceptionHandler.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/EntityAlreadyExistsExceptionHandler.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ExecutionExceptionHandler.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/RateLimiterExceptionHandler.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/TimeLimiterExceptionHandler.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/AesGcmCipher.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/Cipher.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ClientDTO.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ErrorDTO.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/PaginationDTO.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/RegenerateDTO.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ScopeDTO.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Authorization.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Client.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Consent.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Tenant.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ClientNotFoundException.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/EntityAlreadyExistsException.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ScopeNotFoundException.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/AuthorizationMapper.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ClientMapper.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ConsentMapper.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/AuthorizationListener.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ClientListener.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ConsentListener.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/SocketNotificationListener.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/AuthorizationMessage.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/ConsentMessage.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/NotificationMessage.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/wrappers/MessageWrapper.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/AuthorizationRepository.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ClientRepository.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ConsentRepository.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ReadOnlyRepository.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/TenantRepository.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/AuthorizationService.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ClientService.java create mode 100644 web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ConsentService.java create mode 100644 web/ASC.OAuth/api/src/main/resources/application.yml create mode 100644 web/ASC.OAuth/api/src/main/resources/migration/V1_1__init.sql create mode 100644 web/ASC.OAuth/api/src/test/application.yml create mode 100644 web/ASC.OAuth/api/src/test/java/com/onlyoffice/authorization/api/ApplicationAPITests.java create mode 100644 web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.jar create mode 100644 web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.properties create mode 100644 web/ASC.OAuth/authorization/Dockerfile create mode 100644 web/ASC.OAuth/authorization/HELP.md create mode 100755 web/ASC.OAuth/authorization/mvnw create mode 100644 web/ASC.OAuth/authorization/mvnw.cmd create mode 100644 web/ASC.OAuth/authorization/pom.xml create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/AuthorizationApplication.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/caching/AuthorizationCache.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/DocspaceConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/RegisteredClientConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/CacheConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/authorization/CacheAuthorizationMapConfig.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/GenericQueueConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/RabbitMQConfiguration.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/UsernamePasswordCredentials.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/AuthorizationMessage.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/ConsentMessage.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/wrappers/MessageWrapper.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Authorization.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Client.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Consent.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/AuthenticationMethodNotFoundException.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ClientNotFoundException.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ReadOnlyOperationException.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/CookieCsrfFilter.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/SimpleCORSFilter.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/ECGenerator.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/JwksKeyPairGenerator.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/RSAGenerator.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/providers/DocspaceAuthenticationProvider.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/repositories/DocspaceRegisteredClientRepository.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationConsentService.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationService.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/AuthorizationRepository.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ClientRepository.java create mode 100644 web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ConsentRepository.java create mode 100644 web/ASC.OAuth/authorization/src/main/resources/application.yml create mode 100644 web/ASC.OAuth/authorization/src/main/resources/templates/authorized.html create mode 100644 web/ASC.OAuth/authorization/src/main/resources/templates/error.html create mode 100644 web/ASC.OAuth/authorization/src/test/java/com/onlyoffice/authorization/AuthorizationApplicationTests.java create mode 100644 web/ASC.OAuth/client/.gitignore create mode 100644 web/ASC.OAuth/client/README.md create mode 100644 web/ASC.OAuth/client/package.json create mode 100644 web/ASC.OAuth/client/public/favicon.ico create mode 100644 web/ASC.OAuth/client/public/index.html create mode 100644 web/ASC.OAuth/client/src/App.jsx create mode 100644 web/ASC.OAuth/client/src/Consent.jsx create mode 100644 web/ASC.OAuth/client/src/Error.jsx create mode 100644 web/ASC.OAuth/client/src/Login.jsx create mode 100644 web/ASC.OAuth/client/src/index.css create mode 100644 web/ASC.OAuth/client/src/index.jsx create mode 100644 web/ASC.OAuth/client/src/reportWebVitals.js create mode 100644 web/ASC.OAuth/docker-compose.yml create mode 100644 web/ASC.OAuth/pom.xml diff --git a/web/ASC.OAuth/.gitignore b/web/ASC.OAuth/.gitignore new file mode 100644 index 0000000000..be121f1320 --- /dev/null +++ b/web/ASC.OAuth/.gitignore @@ -0,0 +1,40 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +node_modules +.env + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store diff --git a/web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.jar b/web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 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 A?*IS* literal 0 HcmV?d00001 diff --git a/web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.properties b/web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..462686e25d --- /dev/null +++ b/web/ASC.OAuth/api/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/web/ASC.OAuth/api/Dockerfile b/web/ASC.OAuth/api/Dockerfile new file mode 100644 index 0000000000..0211dba939 --- /dev/null +++ b/web/ASC.OAuth/api/Dockerfile @@ -0,0 +1,10 @@ +FROM maven:3.8.3-openjdk-17 AS MAVEN_BUILD +WORKDIR /build/ +COPY . . +WORKDIR /build/api +RUN mvn clean package -DskipTests=true + +FROM openjdk:17 +WORKDIR /app +COPY --from=MAVEN_BUILD /build/api/target/api-0.0.1.jar /app/ +ENTRYPOINT ["java", "-jar", "api-0.0.1.jar"] \ No newline at end of file diff --git a/web/ASC.OAuth/api/HELP.md b/web/ASC.OAuth/api/HELP.md new file mode 100644 index 0000000000..1d09d703f4 --- /dev/null +++ b/web/ASC.OAuth/api/HELP.md @@ -0,0 +1,29 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.2/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.2/maven-plugin/reference/html/#build-image) +* [Spring Reactive Web](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsinge/index.html#web.reactive) +* [Spring Data R2DBC](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsinge/index.html#data.sql.r2dbc) +* [Spring HATEOAS](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsinge/index.html#web.spring-hateoas) +* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsinge/index.html#data.sql.jpa-and-spring-data) + +### Guides +The following guides illustrate how to use some features concretely: + +* [Building a Reactive RESTful Web Service](https://spring.io/guides/gs/reactive-rest-service/) +* [Accessing data with R2DBC](https://spring.io/guides/gs/accessing-data-r2dbc/) +* [Building a Hypermedia-Driven RESTful Web Service](https://spring.io/guides/gs/rest-hateoas/) +* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) + +### Additional Links +These additional references should also help you: + +* [R2DBC Homepage](https://r2dbc.io) + +## Missing R2DBC Driver + +Make sure to include a [R2DBC Driver](https://r2dbc.io/drivers/) to connect to your database. diff --git a/web/ASC.OAuth/api/Makefile b/web/ASC.OAuth/api/Makefile new file mode 100644 index 0000000000..50e6baa59d --- /dev/null +++ b/web/ASC.OAuth/api/Makefile @@ -0,0 +1,19 @@ +.DEFAULT_GOAL := help + +.PHONY: help +help: + @grep -E "^[a-z-]+: #" $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ": # "}; {printf "%s: %s\n", $$1, $$2}' + +.PHONY: dev +dev: # Start Spring Boot server + ./mvnw spring-boot:run + +.PHONY: lint +lint: # Lint the source code for style and check for types. + @flake8 + @mypy . + +.PHONY: load-dev +load-dev: # Development load testing + @artillery run -e development ./artillery.yml \ No newline at end of file diff --git a/web/ASC.OAuth/api/artillery.yml b/web/ASC.OAuth/api/artillery.yml new file mode 100644 index 0000000000..9e5cb45cf7 --- /dev/null +++ b/web/ASC.OAuth/api/artillery.yml @@ -0,0 +1,80 @@ +config: + target: http://authorization.io + environments: + staging: + target: "http://127.0.0.1:9090" + phases: + - duration: 120 + arrivalRate: 1 + rampTo: 10 + name: Warm up phase + - duration: 180 + arrivalRate: 10 + rampTo: 50 + name: Ramp up load + - duration: 60 + arrivalRate: 50 + rampTo: 100 + name: Spike phase + development: + target: "http://127.0.0.1:9090" + phases: + - duration: 120 + arrivalRate: 1 + rampTo: 10 + name: Warm up phase + - duration: 180 + arrivalRate: 10 + rampTo: 50 + name: Ramp up load + - duration: 60 + arrivalRate: 50 + rampTo: 100 + name: Spike phase + defaults: + headers: + X-API-Version: 1 + plugins: + ensure: + thresholds: + - "http.response_time.p99": 2500 + - "http.response_time.p95": 1500 + metrics-by-endpoint: + useOnlyRequestNames: true + metricsNamespace: "latency_metrics" + apdex: {} +scenarios: + - name: "GET requests" + flow: + - loop: + - get: + url: "/api/clients" + headers: + X-Tenant: 1 + qs: + page: 0 + limit: 25 + - get: + url: "/api/scopes" + qs: + page: 0 + limit: 25 + count: 1000 +# - name: "POST requests" +# flow: +# - loop: +# - post: +# url: "/api/clients" +# headers: +# X-Tenant: 1 +# json: +# name: "Artillery App" +# description: "Artillery App Description" +# terms_url: "http://127.0.0.1:9090/terms" +# policy_url: "http://127.0.0.1:9090/policy" +# logo_url: "http://127.0.0.1:9090/logo" +# authenticationMethod: "client_secret_post" +# redirect_uri: "http://127.0.0.1:9090/authorized" +# logout_redirect_uri: "http://127.0.0.1:9090/logout" +# scopes: [ "accounts:read", "accounts:write" ] +# count: 100 \ No newline at end of file diff --git a/web/ASC.OAuth/api/mvnw b/web/ASC.OAuth/api/mvnw new file mode 100755 index 0000000000..66df285428 --- /dev/null +++ b/web/ASC.OAuth/api/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/web/ASC.OAuth/api/mvnw.cmd b/web/ASC.OAuth/api/mvnw.cmd new file mode 100644 index 0000000000..95ba6f54ac --- /dev/null +++ b/web/ASC.OAuth/api/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/web/ASC.OAuth/api/pom.xml b/web/ASC.OAuth/api/pom.xml new file mode 100644 index 0000000000..b1cb398477 --- /dev/null +++ b/web/ASC.OAuth/api/pom.xml @@ -0,0 +1,148 @@ + + + 4.0.0 + + com.onlyoffice + base + 0.0.1 + + + com.onlyoffice + api + 0.0.1 + api + Docspace Authorization Server API + + 1.70 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-starter-batch + + + org.springframework.hateoas + spring-hateoas + 2.1.2 + + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + ${mysql.connector.version} + + + com.h2database + h2 + ${h2.connector.version} + test + + + org.flywaydb + flyway-core + + + org.flywaydb + flyway-mysql + + + + + + + + org.springframework.security + spring-security-crypto + 6.1.2 + + + + + + + + org.springframework.boot + spring-boot-starter-amqp + + + com.corundumstudio.socketio + netty-socketio + 1.7.17 + + + + + + + + io.github.resilience4j + resilience4j-spring-boot3 + 2.1.0 + + + + + + + + org.bouncycastle + bcprov-jdk15on + ${bouncycastle.version} + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/ApplicationAPI.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/ApplicationAPI.java new file mode 100644 index 0000000000..eadc5976ed --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/ApplicationAPI.java @@ -0,0 +1,15 @@ +package com.onlyoffice.authorization.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@EnableTransactionManagement +@SpringBootApplication +public class ApplicationAPI { + + public static void main(String[] args) { + SpringApplication.run(ApplicationAPI.class, args); + } + +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/ApplicationConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/ApplicationConfiguration.java new file mode 100644 index 0000000000..44b73c8f5c --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/ApplicationConfiguration.java @@ -0,0 +1,39 @@ +package com.onlyoffice.authorization.api.configuration; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.List; + +@Configuration +@ConfigurationProperties(prefix = "application") +@Getter +@Setter +@NoArgsConstructor +@EnableScheduling +public class ApplicationConfiguration { + private SecurityConfiguration security; + private List scopes; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public class SecurityConfiguration { + private String cipherSecret = "secret"; + } + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class ScopeConfiguration { + private String name; + private String description; + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/SocketCommandLineRunner.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/SocketCommandLineRunner.java new file mode 100644 index 0000000000..f2f0953f2e --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/SocketCommandLineRunner.java @@ -0,0 +1,18 @@ +package com.onlyoffice.authorization.api.configuration; + +import com.corundumstudio.socketio.SocketIOServer; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class SocketCommandLineRunner implements CommandLineRunner { + private final SocketIOServer server; + @Override + public void run(String... args) throws Exception { + server.start(); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/WebSocketConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/WebSocketConfiguration.java new file mode 100644 index 0000000000..c10e5321a1 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/WebSocketConfiguration.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.api.configuration; + +import com.corundumstudio.socketio.SocketIOServer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class WebSocketConfiguration { + @Value("${socket-server.host}") + private String host; + @Value("${socket-server.port}") + private Integer port; + + @Bean + public SocketIOServer socketIOServer() { + com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration(); + config.setHostname(host); + config.setPort(port); + return new SocketIOServer(config); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/AuthorizationQueueConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/AuthorizationQueueConfiguration.java new file mode 100644 index 0000000000..97bff25d3f --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/AuthorizationQueueConfiguration.java @@ -0,0 +1,75 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.core.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@RequiredArgsConstructor +@Configuration +@Slf4j +public class AuthorizationQueueConfiguration { + private final RabbitMQConfiguration configuration; + + @Bean + public Queue authorizationDeadQueue() { + log.info("Building an authorization dead queue {} with bytes limit of {}", configuration + .getAuthorization().getDeadQueue(), configuration.getAuthorization().getDeadMaxBytes()); + return QueueBuilder.durable(configuration.getAuthorization().getDeadQueue()) + .withArgument("x-max-length-bytes", configuration.getAuthorization().getDeadMaxBytes()) + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public Queue authorizationQueue() { + log.info("Building an authorization queue {} with dead exchange {}, max bytes {} delivery limit {} and ttl {}", + configuration.getAuthorization().getQueue(), configuration.getAuthorization().getDeadExchange(), + configuration.getAuthorization().getMaxBytes(), configuration.getAuthorization().getDeliveryLimit(), + configuration.getAuthorization().getMessageTTL()); + return QueueBuilder.durable(configuration.getAuthorization().getQueue()) + .withArgument("x-dead-letter-exchange", configuration.getAuthorization().getDeadExchange()) + .withArgument("x-dead-letter-routing-key", configuration.getAuthorization().getDeadRouting()) + .withArgument("x-delivery-limit", configuration.getAuthorization().getDeliveryLimit()) + .withArgument("x-max-length-bytes", configuration.getAuthorization().getMaxBytes()) + .withArgument("x-message-ttl", configuration.getAuthorization().getMessageTTL()) + .withArgument("x-overflow", "reject-publish") + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public TopicExchange authorizationExchange() { + log.info("Building an authorization exchange {}", configuration.getAuthorization().getExchange()); + return new TopicExchange(configuration.getAuthorization().getExchange()); + } + + @Bean + public TopicExchange authorizationDeadExchange() { + log.info("Building an authorization dead exchange {}", configuration.getAuthorization().getDeadExchange()); + return new TopicExchange(configuration.getAuthorization().getDeadExchange()); + } + + @Bean + public Binding authorizationBinding() { + log.info("Building an authorization binding with {}", configuration.getAuthorization().getRouting()); + return BindingBuilder.bind(authorizationQueue()) + .to(authorizationExchange()) + .with(configuration.getAuthorization().getRouting()); + } + + @Bean + public Binding authorizationDeadBinding() { + log.info("Building an authorization dead binding with {}", configuration.getAuthorization().getDeadRouting()); + return BindingBuilder.bind(authorizationDeadQueue()) + .to(authorizationDeadExchange()) + .with(configuration.getAuthorization().getDeadRouting()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ClientQueueConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ClientQueueConfiguration.java new file mode 100644 index 0000000000..76ca455107 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ClientQueueConfiguration.java @@ -0,0 +1,73 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@RequiredArgsConstructor +@Configuration +@Slf4j +public class ClientQueueConfiguration { + private final RabbitMQConfiguration configuration; + + @Bean + public Queue clientDeadQueue() { + log.info("Building a client dead queue {} with bytes limit of {}", configuration + .getClient().getDeadQueue(), configuration.getClient().getDeadMaxBytes()); + return QueueBuilder.durable(configuration.getClient().getDeadQueue()) + .withArgument("x-max-length-bytes", configuration.getClient().getDeadMaxBytes()) + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public Queue clientQueue() { + log.info("Building a client queue {} with dead exchange {}, max bytes {} delivery limit {} and ttl {}", + configuration.getClient().getQueue(), configuration.getClient().getDeadExchange(), + configuration.getClient().getMaxBytes(), configuration.getClient().getDeliveryLimit(), + configuration.getClient().getMessageTTL()); + return QueueBuilder.durable(configuration.getClient().getQueue()) + .withArgument("x-dead-letter-exchange", configuration.getClient().getDeadExchange()) + .withArgument("x-dead-letter-routing-key", configuration.getClient().getDeadRouting()) + .withArgument("x-delivery-limit", configuration.getClient().getDeliveryLimit()) + .withArgument("x-max-length-bytes", configuration.getClient().getMaxBytes()) + .withArgument("x-message-ttl", configuration.getClient().getMessageTTL()) + .withArgument("x-overflow", "reject-publish") + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public TopicExchange clientExchange() { + log.info("Building a client exchange {}", configuration.getClient().getExchange()); + return new TopicExchange(configuration.getClient().getExchange()); + } + + @Bean + public TopicExchange clientDeadExchange() { + log.info("Building a client dead exchange {}", configuration.getClient().getDeadExchange()); + return new TopicExchange(configuration.getClient().getDeadExchange()); + } + + @Bean + public Binding clientBinding() { + log.info("Building a client binding with {}", configuration.getClient().getRouting()); + return BindingBuilder.bind(clientQueue()) + .to(clientExchange()) + .with(configuration.getClient().getRouting()); + } + + @Bean + public Binding clientDeadBinding() { + log.info("Building a client dead binding with {}", configuration.getClient().getDeadRouting()); + return BindingBuilder.bind(clientDeadQueue()) + .to(clientDeadExchange()) + .with(configuration.getClient().getDeadRouting()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ConsentQueueConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ConsentQueueConfiguration.java new file mode 100644 index 0000000000..6fb1c8b208 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/ConsentQueueConfiguration.java @@ -0,0 +1,75 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@RequiredArgsConstructor +@Configuration +@ConfigurationProperties(prefix = "messaging.consent") +@Slf4j +public class ConsentQueueConfiguration { + private final RabbitMQConfiguration configuration; + + @Bean + public Queue consentDeadQueue() { + log.info("Building a consent dead queue {} with bytes limit of {}", configuration + .getConsent().getDeadQueue(), configuration.getConsent().getDeadMaxBytes()); + return QueueBuilder.durable(configuration.getConsent().getDeadQueue()) + .withArgument("x-max-length-bytes", configuration.getConsent().getDeadMaxBytes()) + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public Queue consentQueue() { + log.info("Building a consent queue {} with dead exchange {}, max bytes {} delivery limit {} and ttl {}", + configuration.getConsent().getQueue(), configuration.getConsent().getDeadExchange(), + configuration.getConsent().getMaxBytes(), configuration.getConsent().getDeliveryLimit(), + configuration.getConsent().getMessageTTL()); + return QueueBuilder.durable(configuration.getConsent().getQueue()) + .withArgument("x-dead-letter-exchange", configuration.getConsent().getDeadExchange()) + .withArgument("x-dead-letter-routing-key", configuration.getConsent().getDeadRouting()) + .withArgument("x-delivery-limit", configuration.getConsent().getDeliveryLimit()) + .withArgument("x-max-length-bytes", configuration.getConsent().getMaxBytes()) + .withArgument("x-message-ttl", configuration.getConsent().getMessageTTL()) + .withArgument("x-overflow", "reject-publish") + .withArgument("x-queue-type", "quorum") + .build(); + } + + @Bean + public TopicExchange consentExchange() { + log.info("Building a consent exchange {}", configuration.getConsent().getExchange()); + return new TopicExchange(configuration.getConsent().getExchange()); + } + + @Bean + public TopicExchange consentDeadExchange() { + log.info("Building a consent dead exchange {}", configuration.getConsent().getDeadExchange()); + return new TopicExchange(configuration.getConsent().getDeadExchange()); + } + + @Bean + public Binding consentBinding() { + log.info("Building a consent binding with {}", configuration.getConsent().getRouting()); + return BindingBuilder.bind(consentQueue()) + .to(consentExchange()) + .with(configuration.getConsent().getRouting()); + } + + @Bean + public Binding consentDeadBinding() { + log.info("Building a consent dead binding with {}", configuration.getConsent().getDeadRouting()); + return BindingBuilder.bind(consentDeadQueue()) + .to(consentDeadExchange()) + .with(configuration.getConsent().getDeadRouting()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/GenericQueueConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/GenericQueueConfiguration.java new file mode 100644 index 0000000000..618969d1bf --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/GenericQueueConfiguration.java @@ -0,0 +1,24 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class GenericQueueConfiguration { + private String exchange; + private String queue; + private String routing; + + private String deadQueue; + private String deadExchange; + private String deadRouting; + + private int deadMaxBytes = 15000000; + + private int maxBytes = 20000000; + private int deliveryLimit = 3; + private int messageTTL = 100000; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/RabbitMQConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/RabbitMQConfiguration.java new file mode 100644 index 0000000000..a4ee20dc9b --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/RabbitMQConfiguration.java @@ -0,0 +1,88 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import com.onlyoffice.authorization.api.messaging.messages.AuthorizationMessage; +import com.onlyoffice.authorization.api.messaging.messages.ConsentMessage; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AcknowledgeMode; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper; +import org.springframework.amqp.support.converter.Jackson2JavaTypeMapper; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +@Configuration +@ConfigurationProperties(prefix = "messaging.rabbitmq.configuration") +@Getter +@Setter +@Slf4j +public class RabbitMQConfiguration { + private GenericQueueConfiguration authorization; + private GenericQueueConfiguration client; + private GenericQueueConfiguration consent; + private GenericQueueConfiguration socket; + private int prefetch = 500; + + @Bean + public MessageConverter jsonMessageConverter() { + log.info("Building a json message converter"); + Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); + DefaultJackson2JavaTypeMapper classMapper = new DefaultJackson2JavaTypeMapper(); + classMapper.setTrustedPackages("*"); + classMapper.setIdClassMapping(Map.of( + "authorization", AuthorizationMessage.class, + "consent", ConsentMessage.class + )); + messageConverter.setClassMapper(classMapper); + messageConverter.setTypePrecedence(Jackson2JavaTypeMapper.TypePrecedence.TYPE_ID); + return messageConverter; + } + + + @Bean("rabbitListenerContainerFactory") + public RabbitListenerContainerFactory rabbitFactory( + ConnectionFactory connectionFactory, + MessageConverter converter + ) { + log.info("Building a default rabbit listener container factory"); + var factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory); + factory.setMessageConverter(converter); + return factory; + } + + @Bean("prefetchRabbitListenerContainerFactory") + public RabbitListenerContainerFactory prefetchRabbitListenerContainerFactory( + ConnectionFactory rabbitConnectionFactory, + MessageConverter converter + ) { + log.info("Building a prefetch {} rabbit listener container factory with manual ack", prefetch); + var factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(rabbitConnectionFactory); + factory.setMessageConverter(converter); + factory.setPrefetchCount(prefetch); + factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); + return factory; + } + + public AmqpTemplate rabbitTemplate( + ConnectionFactory connectionFactory, + MessageConverter converter + ) { + log.info("Building an amqp template"); + final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(converter); + return rabbitTemplate; + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/WebSocketQueueConfiguration.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/WebSocketQueueConfiguration.java new file mode 100644 index 0000000000..3870663260 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/configuration/messaging/WebSocketQueueConfiguration.java @@ -0,0 +1,43 @@ +package com.onlyoffice.authorization.api.configuration.messaging; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@RequiredArgsConstructor +@Configuration +@ConfigurationProperties(prefix = "messaging.socket") +@Slf4j +public class WebSocketQueueConfiguration { + private final RabbitMQConfiguration configuration; + + @Bean + public Queue socketQueue() { + return QueueBuilder.nonDurable(configuration.getSocket().getQueue()) + .autoDelete() + .withArgument("x-max-length-bytes", configuration.getSocket().getMaxBytes()) + .withArgument("x-message-ttl", configuration.getSocket().getMessageTTL()) + .withArgument("x-overflow", "reject-publish") + .build(); + } + + @Bean + public FanoutExchange socketExchange() { + log.info("Building a socket exchange {}", configuration.getSocket().getExchange()); + return new FanoutExchange(configuration.getSocket().getExchange()); + } + + @Bean + public Binding socketBinding() { + log.info("Building a consent binding with {}", configuration.getSocket().getRouting()); + return BindingBuilder.bind(socketQueue()) + .to(socketExchange()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ClientController.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ClientController.java new file mode 100644 index 0000000000..7a2585bec7 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ClientController.java @@ -0,0 +1,287 @@ +package com.onlyoffice.authorization.api.controllers; + +import com.onlyoffice.authorization.api.configuration.ApplicationConfiguration; +import com.onlyoffice.authorization.api.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.api.dto.ClientDTO; +import com.onlyoffice.authorization.api.dto.PaginationDTO; +import com.onlyoffice.authorization.api.dto.RegenerateDTO; +import com.onlyoffice.authorization.api.services.ClientService; +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; + +@RestController +@RequestMapping(value = "/api/clients", headers = {"X-API-Version=1"}) +@RequiredArgsConstructor +@Slf4j +public class ClientController { + private final int MAX_LIMIT_PER_PAGE = 20; + private List allowedScopes = new ArrayList<>(); + + private final ApplicationConfiguration applicationConfiguration; + private final RabbitMQConfiguration configuration; + private final ClientService clientService; + private final AmqpTemplate amqpTemplate; + + @PostConstruct + public void init() { + this.allowedScopes = applicationConfiguration.getScopes().stream().map(s -> s.getName()) + .collect(Collectors.toList()); + } + + @GetMapping + @RateLimiter(name = "getRateLimiter") + public ResponseEntity> getClients( + HttpServletResponse response, + @RequestHeader(value = "X-Tenant") int tenant, + @RequestParam(value = "page") int page, + @RequestParam(value = "limit") int limit + ) { + if (limit > MAX_LIMIT_PER_PAGE) + limit = MAX_LIMIT_PER_PAGE; + + log.debug("Received a new get clients request for tenant {} with page {} and limit", tenant, page, limit); + + PaginationDTO pagination = clientService.getTenantClients(tenant, page, limit); + for (final ClientDTO client : pagination.getData()) { + client.add(linkTo(methodOn(ClientController.class) + .getClient(null, tenant, client.getClientId())) + .withRel(HttpMethod.GET.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("get_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .updateClient(response, tenant, client.getClientId(), null)) + .withRel(HttpMethod.PUT.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("update_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .deleteClient(response, client.getClientId(), tenant)) + .withRel(HttpMethod.DELETE.name()) + .withTitle("delete_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .regenerateSecret(response, tenant, client.getClientId())) + .withRel(HttpMethod.PATCH.name()) + .withTitle("regenerate_secret") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + } + + pagination.add(linkTo(methodOn(ClientController.class) + .postClient(response,null)).withRel(HttpMethod.POST.name()) + .withTitle("create_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + + return ResponseEntity.ok(pagination); + } + + @GetMapping("/{clientId}") + @RateLimiter(name = "getRateLimiter") + public ResponseEntity getClient( + HttpServletResponse response, + @RequestHeader(value = "X-Tenant") int tenant, + @PathVariable String clientId + ) { + log.debug("Received a new get client {} request for tenant {}", clientId, tenant); + + var client = clientService.getClient(clientId, tenant); + + client.add(linkTo(methodOn(ClientController.class) + .updateClient(response, tenant, clientId, null)) + .withRel(HttpMethod.PUT.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("update_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .deleteClient(response, clientId, tenant)) + .withRel(HttpMethod.DELETE.name()) + .withTitle("delete_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .regenerateSecret(response, tenant, client.getClientId())) + .withRel(HttpMethod.PATCH.name()) + .withTitle("regenerate_secret") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .postClient(response,null)) + .withRel(HttpMethod.POST.name()) + .withTitle("create_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + + return ResponseEntity.ok(client); + } + + @PostMapping + @RateLimiter(name = "batchRateLimiter") + public ResponseEntity postClient( + HttpServletResponse response, + @RequestBody ClientDTO client + ) { + log.debug("Received a new create client request"); + if (!client.getScopes().stream() + .allMatch(s -> allowedScopes.contains(s))) { + log.error("Could not create a new client with the scopes specified"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + log.debug("Generating a new client's credentials"); + + client.setClientId(UUID.randomUUID().toString()); + client.setClientSecret(UUID.randomUUID().toString()); + + this.amqpTemplate.convertAndSend( + configuration.getClient().getExchange(), + configuration.getClient().getRouting(), + client + ); + + log.debug("Successfully submitted a new client broker message"); + + client.add(linkTo(methodOn(ClientController.class) + .getClient(response, client.getTenant(), client.getClientId())) + .withRel(HttpMethod.GET.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("get_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", client.getTenant()))); + client.add(linkTo(methodOn(ClientController.class) + .updateClient(response, client.getTenant(), client.getClientId(),null)) + .withRel(HttpMethod.PUT.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("update_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", client.getTenant()))); + client.add(linkTo(methodOn(ClientController.class) + .deleteClient(response, client.getClientId(), client.getTenant())) + .withRel(HttpMethod.DELETE.name()) + .withTitle("delete_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", client.getTenant()))); + client.add(linkTo(methodOn(ClientController.class) + .regenerateSecret(response, client.getTenant(), client.getClientId())) + .withRel(HttpMethod.PATCH.name()) + .withTitle("regenerate_secret") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", client.getTenant()))); + + return ResponseEntity.status(HttpStatus.CREATED).body(client); + } + + @PutMapping("/{clientId}") + @RateLimiter(name = "batchRateLimiter") + public ResponseEntity updateClient( + HttpServletResponse response, + @RequestHeader(value = "X-Tenant") int tenant, + @PathVariable String clientId, + @RequestBody ClientDTO clientDTO + ) { + log.debug("Received a new update client {} request", clientId); + if (!clientDTO.getScopes().stream() + .allMatch(s -> allowedScopes.contains(s))) { + log.error("Could not update client {} with the scopes specified", clientId); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + clientDTO.setClientId(clientId); + var client = clientService.updateClient(clientDTO, tenant); + + client.add(linkTo(methodOn(ClientController.class) + .getClient(response, tenant, client.getClientId())) + .withRel(HttpMethod.GET.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("get_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .deleteClient(response, client.getClientId(), tenant)) + .withRel(HttpMethod.DELETE.name()) + .withTitle("delete_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .regenerateSecret(response, tenant, client.getClientId())) + .withRel(HttpMethod.PATCH.name()) + .withTitle("regenerate_secret") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + client.add(linkTo(methodOn(ClientController.class) + .postClient(response,null)) + .withRel(HttpMethod.POST.name()) + .withTitle("create_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + + return ResponseEntity.ok(client); + } + + @PatchMapping("/{clientId}") + @RateLimiter(name = "regenerateSecretRateLimiter") + public ResponseEntity regenerateSecret( + HttpServletResponse response, + @RequestHeader(value = "X-Tenant") int tenant, + @PathVariable String clientId + ) { + log.debug("Received a new regenerate client's {} secret request", clientId); + var regenerate = clientService.regenerateSecret(clientId, tenant); + + regenerate.add(linkTo(methodOn(ClientController.class) + .getClient(response, tenant, clientId)) + .withRel(HttpMethod.GET.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("get_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + regenerate.add(linkTo(methodOn(ClientController.class) + .updateClient(response, tenant, clientId, null)) + .withRel(HttpMethod.PUT.name()) + .withMedia(MediaType.APPLICATION_JSON_VALUE) + .withTitle("update_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + regenerate.add(linkTo(methodOn(ClientController.class) + .deleteClient(response, clientId, tenant)) + .withRel(HttpMethod.DELETE.name()) + .withTitle("delete_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + regenerate.add(linkTo(methodOn(ClientController.class) + .postClient(response,null)).withRel(HttpMethod.POST.name()) + .withTitle("create_client") + .withProfile(String.format("X-API-Version=1;X-Tenant=%d", tenant))); + + return ResponseEntity.ok(regenerate); + } + + @DeleteMapping("/{clientId}") + @RateLimiter(name = "batchRateLimiter") + public ResponseEntity deleteClient( + HttpServletResponse response, + @PathVariable String clientId, + @RequestHeader(value = "X-Tenant") int tenant + ) { + log.debug("Received a new delete client {} request for tenant {}", clientId, tenant); + + this.amqpTemplate.convertAndSend( + configuration.getClient().getExchange(), + configuration.getClient().getRouting(), + ClientDTO + .builder() + .tenant(tenant) + .clientId(clientId) + .clientSecret(UUID.randomUUID().toString()) + .scopes(Set.of("***")) + .redirectUri("***") + .invalidated(true) + .build() + ); + + return ResponseEntity.status(HttpStatus.OK).build(); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ScopeController.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ScopeController.java new file mode 100644 index 0000000000..989d05a591 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/ScopeController.java @@ -0,0 +1,66 @@ +package com.onlyoffice.authorization.api.controllers; + +import com.onlyoffice.authorization.api.configuration.ApplicationConfiguration; +import com.onlyoffice.authorization.api.dto.ScopeDTO; +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Set; +import java.util.stream.Collectors; + +@RestController +@RequestMapping(value = "/api/scopes", headers = {"X-API-Version=1"}) +@RequiredArgsConstructor +@Slf4j +public class ScopeController { + private final ApplicationConfiguration configuration; + private Set scopes; + + @PostConstruct + public void init() { + this.scopes = configuration.getScopes() + .stream() + .map(s -> ScopeDTO + .builder() + .name(s.getName()) + .description(s.getDescription()) + .build() + ) + .collect(Collectors.toSet()); + } + + @GetMapping + @RateLimiter(name = "getRateLimiter") + @SneakyThrows + public ResponseEntity> getScopes() { + log.debug("Received a request to list scopes"); + return ResponseEntity.ok(this.scopes); + } + + @GetMapping("/{name}") + @RateLimiter(name = "getRateLimiter") + @SneakyThrows + public ResponseEntity getScope(@PathVariable String name) { + log.debug("Received a get {} scope", name); + var scope = this.scopes.stream() + .filter(s -> s.getName().equals(name)) + .findFirst(); + + if (scope.isEmpty()) { + log.error("Scope {} does not exist", name); + return ResponseEntity.badRequest().build(); + } + + return ResponseEntity.ok(scope.get()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/WebSocketController.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/WebSocketController.java new file mode 100644 index 0000000000..2416866db3 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/WebSocketController.java @@ -0,0 +1,37 @@ +package com.onlyoffice.authorization.api.controllers; + +import com.corundumstudio.socketio.SocketIOServer; +import com.corundumstudio.socketio.listener.ConnectListener; +import com.corundumstudio.socketio.listener.DisconnectListener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class WebSocketController { + private final SocketIOServer server; + + public WebSocketController(SocketIOServer server) { + this.server = server; + server.addConnectListener(onConnected()); + server.addDisconnectListener(onDisconnected()); + } + + private ConnectListener onConnected() { + return (client) -> { + String tenant = client.getHandshakeData().getSingleUrlParam("tenant"); + if (tenant == null || tenant.isBlank()) { + client.disconnect(); + return; + } + client.joinRoom(tenant); + log.debug("Client[{}] - Connected to socket", client.getSessionId().toString()); + }; + } + + private DisconnectListener onDisconnected() { + return client -> { + log.debug("Client[{}] - Disconnected from socket", client.getSessionId().toString()); + }; + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ClientNotFoundExceptionHandler.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ClientNotFoundExceptionHandler.java new file mode 100644 index 0000000000..38a5dae7bd --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ClientNotFoundExceptionHandler.java @@ -0,0 +1,25 @@ +package com.onlyoffice.authorization.api.controllers.advice; + +import com.onlyoffice.authorization.api.dto.ErrorDTO; +import com.onlyoffice.authorization.api.exceptions.ClientNotFoundException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +@Slf4j +public class ClientNotFoundExceptionHandler { + @ExceptionHandler(ClientNotFoundException.class) + public ResponseEntity handleClientNotFound(ClientNotFoundException ex, HttpServletRequest request) { + log.error("Exception has occurred: {}", ex.getMessage()); + return new ResponseEntity<>(ErrorDTO + .builder() + .reason(ex.getMessage()) + .build(), + HttpStatus.BAD_REQUEST + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/EntityAlreadyExistsExceptionHandler.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/EntityAlreadyExistsExceptionHandler.java new file mode 100644 index 0000000000..419702189a --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/EntityAlreadyExistsExceptionHandler.java @@ -0,0 +1,25 @@ +package com.onlyoffice.authorization.api.controllers.advice; + +import com.onlyoffice.authorization.api.dto.ErrorDTO; +import com.onlyoffice.authorization.api.exceptions.EntityAlreadyExistsException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +@Slf4j +public class EntityAlreadyExistsExceptionHandler { + @ExceptionHandler(EntityAlreadyExistsException.class) + public ResponseEntity handleEntityAlreadyExists(EntityAlreadyExistsException ex, HttpServletRequest request) { + log.error("Exception has occurred: {}", ex.getMessage()); + return new ResponseEntity<>(ErrorDTO + .builder() + .reason(ex.getMessage()) + .build(), + HttpStatus.CONFLICT + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ExecutionExceptionHandler.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ExecutionExceptionHandler.java new file mode 100644 index 0000000000..1d536fb1a2 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/ExecutionExceptionHandler.java @@ -0,0 +1,26 @@ +package com.onlyoffice.authorization.api.controllers.advice; + +import com.onlyoffice.authorization.api.dto.ErrorDTO; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import java.util.concurrent.ExecutionException; + +@ControllerAdvice +@Slf4j +public class ExecutionExceptionHandler { + @ExceptionHandler(ExecutionException.class) + public ResponseEntity handleExecutionException(ExecutionException ex, HttpServletRequest request) { + log.error("Exception has occurred: {}", ex.getMessage()); + return new ResponseEntity(ErrorDTO + .builder() + .reason("could not perform operation") + .build(), + HttpStatus.BAD_REQUEST + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/RateLimiterExceptionHandler.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/RateLimiterExceptionHandler.java new file mode 100644 index 0000000000..e87cc017d6 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/RateLimiterExceptionHandler.java @@ -0,0 +1,26 @@ +package com.onlyoffice.authorization.api.controllers.advice; + +import com.onlyoffice.authorization.api.dto.ErrorDTO; +import io.github.resilience4j.ratelimiter.RequestNotPermitted; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +@Slf4j +public class RateLimiterExceptionHandler { + @ExceptionHandler(RequestNotPermitted.class) + public ResponseEntity handleRequestNotPermitted(RequestNotPermitted ex, HttpServletRequest request) { + log.warn("Request to path '{}' is blocked due to rate-limiting. {}", + request.getRequestURI(), ex.getMessage()); + return new ResponseEntity(ErrorDTO + .builder() + .reason("too many requests") + .build(), + HttpStatus.TOO_MANY_REQUESTS + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/TimeLimiterExceptionHandler.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/TimeLimiterExceptionHandler.java new file mode 100644 index 0000000000..088d4dc30a --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/controllers/advice/TimeLimiterExceptionHandler.java @@ -0,0 +1,27 @@ +package com.onlyoffice.authorization.api.controllers.advice; + +import com.onlyoffice.authorization.api.dto.ErrorDTO; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import java.util.concurrent.TimeoutException; + +@ControllerAdvice +@Slf4j +public class TimeLimiterExceptionHandler { + @ExceptionHandler(TimeoutException.class) + public ResponseEntity handleTimeoutException(TimeoutException ex, HttpServletRequest request) { + log.warn("Request to path '{}' is blocked due to time-limiting. {}", + request.getRequestURI(), ex.getMessage()); + return new ResponseEntity(ErrorDTO + .builder() + .reason("request timeout") + .build(), + HttpStatus.REQUEST_TIMEOUT + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/AesGcmCipher.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/AesGcmCipher.java new file mode 100644 index 0000000000..4f4953083e --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/AesGcmCipher.java @@ -0,0 +1,103 @@ +package com.onlyoffice.authorization.api.crypto; + +import com.onlyoffice.authorization.api.configuration.ApplicationConfiguration; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; + +@Component +@Qualifier("gcm") +@RequiredArgsConstructor +@Slf4j +public class AesGcmCipher implements com.onlyoffice.authorization.api.crypto.Cipher { + private static final String ALGORITHM = "AES/GCM/NoPadding"; + private static final String FACTORY_INSTANCE = "PBKDF2WithHmacSHA256"; + private static final int TAG_LENGTH_BIT = 128; + private static final int IV_LENGTH_BYTE = 12; + private static final int SALT_LENGTH_BYTE = 16; + private static final String ALGORITHM_TYPE = "AES"; + private static final int KEY_LENGTH = 128; + private static final int ITERATION_COUNT = 1500; // Min 1000 + private static final Charset UTF_8 = StandardCharsets.UTF_8; + private final ApplicationConfiguration configuration; + + private byte[] getRandomNonce(int length) { + byte[] nonce = new byte[length]; + new SecureRandom().nextBytes(nonce); + return nonce; + } + + private SecretKey getSecretKey(String password, byte[] salt) + throws NoSuchAlgorithmException, InvalidKeySpecException { + KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH); + + SecretKeyFactory factory = SecretKeyFactory.getInstance(FACTORY_INSTANCE); + return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), ALGORITHM_TYPE); + } + + private Cipher initCipher(int mode, SecretKey secretKey, byte[] iv) + throws InvalidKeyException, InvalidAlgorithmParameterException, + NoSuchPaddingException, NoSuchAlgorithmException { + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(mode, secretKey, new GCMParameterSpec(TAG_LENGTH_BIT, iv)); + return cipher; + } + + public String encrypt(String plainMessage) throws Exception { + log.debug("Trying to encrypt '{}' message", plainMessage); + byte[] salt = getRandomNonce(SALT_LENGTH_BYTE); + SecretKey secretKey = getSecretKey(configuration.getSecurity().getCipherSecret(), salt); + + byte[] iv = getRandomNonce(IV_LENGTH_BYTE); + Cipher cipher = initCipher(Cipher.ENCRYPT_MODE, secretKey, iv); + + byte[] encryptedMessageByte = cipher.doFinal(plainMessage.getBytes(UTF_8)); + + byte[] cipherByte = ByteBuffer.allocate(iv.length + salt.length + encryptedMessageByte.length) + .put(iv) + .put(salt) + .put(encryptedMessageByte) + .array(); + return Base64.getEncoder().encodeToString(cipherByte); + } + + public String decrypt(String cipherMessage) throws Exception { + log.debug("Trying to decrypt '{}' message", cipherMessage); + byte[] decodedCipherByte = Base64.getDecoder().decode(cipherMessage.getBytes(UTF_8)); + ByteBuffer byteBuffer = ByteBuffer.wrap(decodedCipherByte); + + byte[] iv = new byte[IV_LENGTH_BYTE]; + byteBuffer.get(iv); + + byte[] salt = new byte[SALT_LENGTH_BYTE]; + byteBuffer.get(salt); + + byte[] encryptedByte = new byte[byteBuffer.remaining()]; + byteBuffer.get(encryptedByte); + + SecretKey secretKey = getSecretKey(configuration.getSecurity().getCipherSecret(), salt); + Cipher cipher = initCipher(Cipher.DECRYPT_MODE, secretKey, iv); + + byte[] decryptedMessageByte = cipher.doFinal(encryptedByte); + return new String(decryptedMessageByte, UTF_8); + } +} \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/Cipher.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/Cipher.java new file mode 100644 index 0000000000..8f418c28b6 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/crypto/Cipher.java @@ -0,0 +1,6 @@ +package com.onlyoffice.authorization.api.crypto; + +public interface Cipher { + String encrypt(String plainMessage) throws Exception; + String decrypt(String cipherMessage) throws Exception; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ClientDTO.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ClientDTO.java new file mode 100644 index 0000000000..d931b2a639 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ClientDTO.java @@ -0,0 +1,42 @@ +package com.onlyoffice.authorization.api.dto; + + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.springframework.hateoas.RepresentationModel; + +import java.io.Serializable; +import java.util.Set; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class ClientDTO extends RepresentationModel implements Serializable { + private String name; + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonProperty("client_id") + private String clientId; + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonProperty("client_secret") + private String clientSecret; + private String description; + @JsonProperty("terms_url") + private String termsUrl; + @JsonProperty("policy_url") + private String policyUrl; + @JsonProperty("logo_url") + private String logoUrl; + @JsonProperty("authentication_method") + @JsonInclude(JsonInclude.Include.NON_NULL) + private String authenticationMethod; + @JsonProperty("redirect_uri") + private String redirectUri; + @JsonProperty("logout_redirect_uri") + private String logoutRedirectUri; + private Set scopes; + private int tenant; + private boolean invalidated; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ErrorDTO.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ErrorDTO.java new file mode 100644 index 0000000000..808f311bb1 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ErrorDTO.java @@ -0,0 +1,12 @@ +package com.onlyoffice.authorization.api.dto; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class ErrorDTO { + private String reason; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/PaginationDTO.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/PaginationDTO.java new file mode 100644 index 0000000000..800e5ea247 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/PaginationDTO.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.api.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; +import org.springframework.hateoas.RepresentationModel; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class PaginationDTO extends RepresentationModel> implements Serializable { + int page; + int limit; + @JsonInclude(JsonInclude.Include.NON_NULL) + Integer previous; + @JsonInclude(JsonInclude.Include.NON_NULL) + Integer next; + Iterable data; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/RegenerateDTO.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/RegenerateDTO.java new file mode 100644 index 0000000000..dfefaa4c28 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/RegenerateDTO.java @@ -0,0 +1,17 @@ +package com.onlyoffice.authorization.api.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.springframework.hateoas.RepresentationModel; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class RegenerateDTO extends RepresentationModel implements Serializable { + @JsonProperty("client_secret") + private String clientSecret; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ScopeDTO.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ScopeDTO.java new file mode 100644 index 0000000000..f1158941b8 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/dto/ScopeDTO.java @@ -0,0 +1,17 @@ +package com.onlyoffice.authorization.api.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class ScopeDTO implements Serializable { + @JsonInclude(JsonInclude.Include.NON_NULL) + private String name; + private String description; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Authorization.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Authorization.java new file mode 100644 index 0000000000..653c1ead2b --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Authorization.java @@ -0,0 +1,72 @@ +package com.onlyoffice.authorization.api.entities; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; +import java.util.Date; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "identity_authorizations") +public class Authorization { + @Id + @Column + private String id; + @Column(name = "registered_client_id") + private String registeredClientId; + @Column(name = "principal_name") + private String principalName; + @Column(name = "authorization_grant_type") + private String authorizationGrantType; + @Column(name = "authorized_scopes", length = 1000) + private String authorizedScopes; + @Lob + @Column(name = "attributes", length = 4000) + private String attributes; + @Column(name = "state", length = 500) + private String state; + @Lob + @Column(name = "authorization_code_value", length = 4000) + private String authorizationCodeValue; + @Column(name = "authorization_code_issued_at") + private Date authorizationCodeIssuedAt; + @Column(name = "authorization_code_expires_at") + private Date authorizationCodeExpiresAt; + @Column(name = "authorization_code_metadata") + private String authorizationCodeMetadata; + @Lob + @Column(name = "access_token_value", length = 4000) + private String accessTokenValue; + @Column(name = "access_token_issued_at") + private Date accessTokenIssuedAt; + @Column(name = "access_token_expires_at") + private Date accessTokenExpiresAt; + @Lob + @Column(name = "access_token_metadata", length = 2000) + private String accessTokenMetadata; + @Column(name = "access_token_type") + private String accessTokenType; + @Column(name = "access_token_scopes", length = 1000) + private String accessTokenScopes; + @Lob + @Column(name = "refresh_token_value", length = 4000) + private String refreshTokenValue; + @Column(name = "refresh_token_issued_at") + private Date refreshTokenIssuedAt; + @Column(name = "refresh_token_expires_at") + private Date refreshTokenExpiresAt; + @Lob + @Column(name = "refresh_token_metadata", length = 2000) + private String refreshTokenMetadata; + @Column(name = "modified_at") + private Timestamp modifiedAt; + @Column(name = "invalidated") + private Boolean invalidated; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Client.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Client.java new file mode 100644 index 0000000000..b084ce35b5 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Client.java @@ -0,0 +1,55 @@ +package com.onlyoffice.authorization.api.entities; + +import jakarta.persistence.*; +import lombok.*; +import org.springframework.data.annotation.CreatedDate; + +import java.sql.Timestamp; +import java.time.Instant; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "identity_clients") +public class Client { + @Id + @Column(name = "client_id", unique = true, length = 36) + private String clientId; + @Column(name = "client_name") + private String name; + private String description; + @Column(name = "client_secret", unique = true, length = 36) + private String clientSecret; + @Column(name = "terms_url") + private String termsUrl; + @Column(name = "policy_url") + private String policyUrl; + @Column(name = "logo_url") + private String logoUrl; + @Column(name = "client_issued_at") + @CreatedDate + private Timestamp clientIssuedAt; + @Column(name = "authentication_method", length = 100) + private String authenticationMethod; + @Column(name = "redirect_uri") + @Lob + private String redirectUri; + @Column(name = "logout_redirect_uri") + @Lob + private String logoutRedirectUri; + @Column(name = "scopes") + @Lob + private String scopes; + @ManyToOne + @JoinColumn(name="tenant_id", nullable=false) + private Tenant tenant; + @Column(name = "invalidated") + private Boolean invalidated; + @PrePersist + public void prePersist() { + this.clientIssuedAt = Timestamp.from(Instant.now()); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Consent.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Consent.java new file mode 100644 index 0000000000..f25baf6cbf --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Consent.java @@ -0,0 +1,53 @@ +package com.onlyoffice.authorization.api.entities; + +import jakarta.persistence.*; +import lombok.*; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Objects; + +@IdClass(Consent.ConsentId.class) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +@Entity +@Table(name = "identity_consents") +public class Consent { + @Id + @Column(name = "registered_client_id") + private String registeredClientId; + @Id + @Column(name = "principal_name") + private String principalName; + @Column(name = "scopes") + @Lob + private String scopes; + @Column(name = "modified_at") + private Timestamp modifiedAt; + @Column(name = "invalidated") + private Boolean invalidated; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class ConsentId implements Serializable { + private static final long serialVersionUID = 1L; + private String registeredClientId; + private String principalName; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConsentId that = (ConsentId) o; + return registeredClientId.equals(that.registeredClientId) && principalName.equals(that.principalName); + } + + public int hashCode() { + return Objects.hash(registeredClientId, principalName); + } + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Tenant.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Tenant.java new file mode 100644 index 0000000000..2d2fa91a70 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/entities/Tenant.java @@ -0,0 +1,29 @@ +package com.onlyoffice.authorization.api.entities; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tenants_tenants") +public class Tenant { + @Id + private Integer id; + private String name; + private String alias; + @OneToMany( + mappedBy="tenant", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.LAZY + ) + private Set clients; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ClientNotFoundException.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ClientNotFoundException.java new file mode 100644 index 0000000000..a0320fd4c3 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ClientNotFoundException.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.api.exceptions; + +public class ClientNotFoundException extends RuntimeException { + public ClientNotFoundException() { + } + + public ClientNotFoundException(String message) { + super(message); + } + + public ClientNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ClientNotFoundException(Throwable cause) { + super(cause); + } + + public ClientNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/EntityAlreadyExistsException.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/EntityAlreadyExistsException.java new file mode 100644 index 0000000000..0280464541 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/EntityAlreadyExistsException.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.api.exceptions; + +public class EntityAlreadyExistsException extends RuntimeException { + public EntityAlreadyExistsException() { + } + + public EntityAlreadyExistsException(String message) { + super(message); + } + + public EntityAlreadyExistsException(String message, Throwable cause) { + super(message, cause); + } + + public EntityAlreadyExistsException(Throwable cause) { + super(cause); + } + + public EntityAlreadyExistsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ScopeNotFoundException.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ScopeNotFoundException.java new file mode 100644 index 0000000000..2f86ded291 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/exceptions/ScopeNotFoundException.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.api.exceptions; + +public class ScopeNotFoundException extends RuntimeException { + public ScopeNotFoundException() { + } + + public ScopeNotFoundException(String message) { + super(message); + } + + public ScopeNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ScopeNotFoundException(Throwable cause) { + super(cause); + } + + public ScopeNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/AuthorizationMapper.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/AuthorizationMapper.java new file mode 100644 index 0000000000..ed9bbbfd94 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/AuthorizationMapper.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.api.mappers; + +import com.onlyoffice.authorization.api.messaging.messages.AuthorizationMessage; +import com.onlyoffice.authorization.api.entities.Authorization; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.factory.Mappers; + +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface AuthorizationMapper { + AuthorizationMapper INSTANCE = Mappers.getMapper(AuthorizationMapper.class); + + AuthorizationMessage toDTO(Authorization authorization); + + Authorization toEntity(AuthorizationMessage scopeDTO); + + void update(@MappingTarget Authorization entity, AuthorizationMessage dto); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ClientMapper.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ClientMapper.java new file mode 100644 index 0000000000..8e07031878 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ClientMapper.java @@ -0,0 +1,54 @@ +package com.onlyoffice.authorization.api.mappers; + +import com.onlyoffice.authorization.api.dto.ClientDTO; +import com.onlyoffice.authorization.api.entities.Client; +import org.bouncycastle.util.Strings; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface ClientMapper { + ClientMapper INSTANCE = Mappers.getMapper(ClientMapper.class); + + default Set map(String value) { + return Arrays.stream(Strings.split(value, ',')).collect(Collectors.toSet()); + } + + default String map(Set value) { + return String.join(",", value); + } + + @Mappings({ + @Mapping(source = "tenant.id", target = "tenant"), + @Mapping(source = "invalidated", target = "invalidated") + }) + ClientDTO toDTO(Client client); + + @Mappings({ + @Mapping( + source = "authenticationMethod", + target = "authenticationMethod", + defaultValue = "client_secret_post" + ), + @Mapping( + source = "tenant", + target = "tenant.id" + ), + @Mapping( + source = "invalidated", + target = "invalidated" + ) + }) + Client toEntity(ClientDTO clientDTO); + + @Mappings({ + @Mapping(target = "clientId", ignore = true), + @Mapping(target = "clientSecret", ignore = true), + @Mapping(target = "tenant", ignore = true) + }) + void update(@MappingTarget Client entity, ClientDTO clientDTO); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ConsentMapper.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ConsentMapper.java new file mode 100644 index 0000000000..8466e0e211 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/mappers/ConsentMapper.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.api.mappers; + +import com.onlyoffice.authorization.api.entities.Consent; +import com.onlyoffice.authorization.api.messaging.messages.ConsentMessage; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.factory.Mappers; + +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface ConsentMapper { + ConsentMapper INSTANCE = Mappers.getMapper(ConsentMapper.class); + + ConsentMessage toDTO(Consent consent); + + Consent toEntity(ConsentMessage consentMessage); + + void update(@MappingTarget Consent entity, ConsentMessage message); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/AuthorizationListener.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/AuthorizationListener.java new file mode 100644 index 0000000000..f8eaebccfc --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/AuthorizationListener.java @@ -0,0 +1,79 @@ +package com.onlyoffice.authorization.api.messaging.listeners; + +import com.onlyoffice.authorization.api.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.api.messaging.messages.AuthorizationMessage; +import com.onlyoffice.authorization.api.messaging.messages.wrappers.MessageWrapper; +import com.onlyoffice.authorization.api.services.AuthorizationService; +import com.rabbitmq.client.Channel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@RabbitListener( + queues = "${messaging.rabbitmq.configuration.authorization.queue}", + containerFactory = "prefetchRabbitListenerContainerFactory" +) +@Slf4j +public class AuthorizationListener { + private final RabbitMQConfiguration configuration; + private final AuthorizationService authorizationService; + private LinkedBlockingQueue> messages = new LinkedBlockingQueue<>(); + @RabbitHandler + public void receiveMessage( + @Payload AuthorizationMessage message, + Channel channel, + @Header(AmqpHeaders.DELIVERY_TAG) long tag + ) { + if (messages.size() > configuration.getPrefetch()) { + log.warn("Authorization message queue is full"); + return; + } + + log.debug("Adding an authorization message to the queue"); + + messages.add(MessageWrapper. + builder() + .tag(tag) + .channel(channel) + .data(message) + .build()); + } + + @Scheduled(fixedDelay = 1000) + private void persistAuthorizations() { + if (messages.size() > 0) { + log.debug("Persisting authorization messages (count {})", messages.size()); + + var ids = authorizationService.saveAuthorizations(messages + .stream().map(s -> s.getData()) + .collect(Collectors.toSet()) + ); + + messages.removeIf(m -> { + var tag = m.getTag(); + var channel = m.getChannel(); + + try { + if (!ids.contains(m.getData().getId())) + channel.basicAck(tag, true); + else + channel.basicNack(tag, false, true); + } catch (IOException e) {} finally { + return true; + } + }); + } + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ClientListener.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ClientListener.java new file mode 100644 index 0000000000..246c6d9c2c --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ClientListener.java @@ -0,0 +1,86 @@ +package com.onlyoffice.authorization.api.messaging.listeners; + +import com.onlyoffice.authorization.api.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.api.dto.ClientDTO; +import com.onlyoffice.authorization.api.messaging.messages.NotificationMessage; +import com.onlyoffice.authorization.api.messaging.messages.wrappers.MessageWrapper; +import com.onlyoffice.authorization.api.services.ClientService; +import com.rabbitmq.client.Channel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@Slf4j +public class ClientListener { + private final RabbitMQConfiguration configuration; + private final ClientService clientService; + private final AmqpTemplate rabbitClient; + private CopyOnWriteArrayList> messages = new CopyOnWriteArrayList<>(); + + @RabbitListener( + queues = "${messaging.rabbitmq.configuration.client.queue}", + containerFactory = "prefetchRabbitListenerContainerFactory" + ) + public void receiveMessage( + ClientDTO clientDTO, + Channel channel, + @Header(AmqpHeaders.DELIVERY_TAG) long tag + ) { + if (messages.size() == configuration.getPrefetch()) { + log.warn("Client message queue is full"); + return; + } + + log.debug("Adding a client message to the queue"); + + messages.add(MessageWrapper. + builder(). + tag(tag). + channel(channel). + data(clientDTO). + build()); + } + + @Scheduled(fixedDelay = 1000) + private void persistClients() { + if (messages.size() > 0) { + log.debug("Persisting client messages (count {})", messages.size()); + + var ids = clientService.createClients(messages.stream().map(s -> s.getData()) + .collect(Collectors.toList())); + + messages.removeIf(w -> { + var tag = w.getTag(); + var channel = w.getChannel(); + + try { + if (!ids.contains(w.getData().getClientId())) { + channel.basicAck(tag, true); + rabbitClient.convertAndSend( + configuration.getSocket().getExchange(), + "", + NotificationMessage.builder() + .tenant(w.getData().getTenant()) + .clientId(w.getData().getClientId()) + .build() + ); + } else + channel.basicNack(tag, false, true); + } catch (IOException e) {} finally { + return true; + } + }); + } + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ConsentListener.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ConsentListener.java new file mode 100644 index 0000000000..25c75857ec --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/ConsentListener.java @@ -0,0 +1,76 @@ +package com.onlyoffice.authorization.api.messaging.listeners; + +import com.onlyoffice.authorization.api.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.api.messaging.messages.ConsentMessage; +import com.onlyoffice.authorization.api.messaging.messages.wrappers.MessageWrapper; +import com.onlyoffice.authorization.api.services.ConsentService; +import com.rabbitmq.client.Channel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@RabbitListener( + queues = "${messaging.rabbitmq.configuration.consent.queue}", + containerFactory = "prefetchRabbitListenerContainerFactory" +) +@Slf4j +public class ConsentListener { + private final RabbitMQConfiguration configuration; + private final ConsentService consentService; + private LinkedBlockingQueue> messages = new LinkedBlockingQueue<>(); + @RabbitHandler + public void receiveSave( + @Payload ConsentMessage message, + Channel channel, + @Header(AmqpHeaders.DELIVERY_TAG) long tag + ) { + if (messages.size() > configuration.getPrefetch()) { + log.warn("Consent message queue is full"); + return; + } + + log.debug("Adding a consent message to the queue"); + + messages.add(MessageWrapper + .builder() + .tag(tag) + .channel(channel) + .data(message) + .build()); + } + + @Scheduled(fixedDelay = 1000) + private void persistConsents() { + if (messages.size() > 0) { + log.debug("Persisting consent messages (count {})", messages.size()); + + consentService.saveConsents(messages + .stream().map(s -> s.getData()) + .collect(Collectors.toSet()) + ); + + messages.removeIf(m -> { + var tag = m.getTag(); + var channel = m.getChannel(); + + try { + channel.basicAck(tag, true); + } catch (IOException e) {} finally { + return true; + } + }); + } + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/SocketNotificationListener.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/SocketNotificationListener.java new file mode 100644 index 0000000000..859837ff38 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/listeners/SocketNotificationListener.java @@ -0,0 +1,31 @@ +package com.onlyoffice.authorization.api.messaging.listeners; + +import com.corundumstudio.socketio.SocketIOServer; +import com.onlyoffice.authorization.api.messaging.messages.NotificationMessage; +import com.rabbitmq.client.Channel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@RabbitListener(queues = "#{rabbitMQConfiguration.getSocket().getQueue()}") +@Slf4j +public class SocketNotificationListener { + private final SocketIOServer server; + @RabbitHandler + public void receiveConfirmation( + @Payload NotificationMessage message, + Channel channel, + @Header(AmqpHeaders.DELIVERY_TAG) long tag + ) { + server.getRoomOperations(String.valueOf(message.getTenant())).getClients().forEach(c -> { + c.sendEvent("client_created", message.getClientId()); + }); + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/AuthorizationMessage.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/AuthorizationMessage.java new file mode 100644 index 0000000000..9a46f1bdb0 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/AuthorizationMessage.java @@ -0,0 +1,38 @@ +package com.onlyoffice.authorization.api.messaging.messages; + +import lombok.*; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Date; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class AuthorizationMessage implements Serializable { + private String id; + private String registeredClientId; + private String principalName; + private String authorizationGrantType; + private String authorizedScopes; + private String attributes; + private String state; + private String authorizationCodeValue; + private Date authorizationCodeIssuedAt; + private Date authorizationCodeExpiresAt; + private String authorizationCodeMetadata; + private String accessTokenValue; + private Date accessTokenIssuedAt; + private Date accessTokenExpiresAt; + private String accessTokenMetadata; + private String accessTokenType; + private String accessTokenScopes; + private String refreshTokenValue; + private Date refreshTokenIssuedAt; + private Date refreshTokenExpiresAt; + private String refreshTokenMetadata; + private Timestamp modifiedAt; + private Boolean invalidated; +} \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/ConsentMessage.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/ConsentMessage.java new file mode 100644 index 0000000000..62770f8077 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/ConsentMessage.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.api.messaging.messages; + +import lombok.*; + +import java.io.Serializable; +import java.sql.Timestamp; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class ConsentMessage implements Serializable { + private String registeredClientId; + private String principalName; + private String scopes; + private Timestamp modifiedAt; + private Boolean invalidated; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/NotificationMessage.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/NotificationMessage.java new file mode 100644 index 0000000000..506792b149 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/NotificationMessage.java @@ -0,0 +1,15 @@ +package com.onlyoffice.authorization.api.messaging.messages; + +import lombok.*; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class NotificationMessage implements Serializable { + private String clientId; + private int tenant; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/wrappers/MessageWrapper.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/wrappers/MessageWrapper.java new file mode 100644 index 0000000000..a5b0d30525 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/messaging/messages/wrappers/MessageWrapper.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.api.messaging.messages.wrappers; + +import com.rabbitmq.client.Channel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MessageWrapper implements Serializable { + private long tag; + private Channel channel; + private E data; +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/AuthorizationRepository.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/AuthorizationRepository.java new file mode 100644 index 0000000000..f380a42f81 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/AuthorizationRepository.java @@ -0,0 +1,8 @@ +package com.onlyoffice.authorization.api.repositories; + +import com.onlyoffice.authorization.api.entities.Authorization; +import org.springframework.data.repository.CrudRepository; + +public interface AuthorizationRepository extends CrudRepository { + void deleteById(String id); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ClientRepository.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ClientRepository.java new file mode 100644 index 0000000000..c748cc210c --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ClientRepository.java @@ -0,0 +1,32 @@ +package com.onlyoffice.authorization.api.repositories; + +import com.onlyoffice.authorization.api.entities.Client; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Transactional(rollbackFor = Exception.class) +public interface ClientRepository extends CrudRepository, + PagingAndSortingRepository { + @Query(""" + SELECT c FROM Client c WHERE c.clientId=:id AND c.invalidated=false + """) + Optional findById(@Param("id") String id); + int deleteByClientIdAndTenantId(String id, int tenantId); + @EntityGraph(attributePaths = {"scopes", "tenant"}) + Optional findClientByClientIdAndTenantId(String id, int tenantId); + Page findAllByTenantId(int tenantId, Pageable pageable); + @Query(""" + UPDATE Client c SET c.clientSecret=:secret WHERE c.clientId=:clientId AND c.tenant.id=:tenant + """) + @Modifying + void regenerateClientSecretByClientId(@Param("clientId") String clientId, @Param("tenant") int tenant, @Param("secret") String secret); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ConsentRepository.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ConsentRepository.java new file mode 100644 index 0000000000..0e3fd6267d --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ConsentRepository.java @@ -0,0 +1,8 @@ +package com.onlyoffice.authorization.api.repositories; + +import com.onlyoffice.authorization.api.entities.Consent; +import org.springframework.data.repository.CrudRepository; + +public interface ConsentRepository extends CrudRepository { + void deleteById(Consent.ConsentId id); +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ReadOnlyRepository.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ReadOnlyRepository.java new file mode 100644 index 0000000000..1d5a740e5e --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/ReadOnlyRepository.java @@ -0,0 +1,13 @@ +package com.onlyoffice.authorization.api.repositories; + +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.Repository; + +import java.util.List; +import java.util.Optional; + +@NoRepositoryBean +public interface ReadOnlyRepository extends Repository { + Optional findById(ID id); + List findAll(); +} \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/TenantRepository.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/TenantRepository.java new file mode 100644 index 0000000000..7132b79177 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/repositories/TenantRepository.java @@ -0,0 +1,6 @@ +package com.onlyoffice.authorization.api.repositories; + +import com.onlyoffice.authorization.api.entities.Tenant; + +public interface TenantRepository extends ReadOnlyRepository { +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/AuthorizationService.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/AuthorizationService.java new file mode 100644 index 0000000000..5f24b02ea5 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/AuthorizationService.java @@ -0,0 +1,67 @@ +package com.onlyoffice.authorization.api.services; + +import com.onlyoffice.authorization.api.mappers.AuthorizationMapper; +import com.onlyoffice.authorization.api.messaging.messages.AuthorizationMessage; +import com.onlyoffice.authorization.api.repositories.AuthorizationRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AuthorizationService { + private final AuthorizationRepository authorizationRepository; + + @Transactional + public void saveAuthorization(AuthorizationMessage authorizationMessage) { + log.debug("Saving an authorization with id: {}", authorizationMessage.getId()); + authorizationRepository.save(AuthorizationMapper.INSTANCE.toEntity(authorizationMessage)); + } + + /** + * + * @param authorizations + * @return a list of failed ids + */ + @Transactional + public List saveAuthorizations(Iterable authorizations) { + log.debug("Saving authorizations"); + List ids = new ArrayList<>(); + + for (AuthorizationMessage authorization : authorizations) { + try { + log.debug("Saving an authorization with id: {}", authorization.getId()); + authorizationRepository.save(AuthorizationMapper.INSTANCE.toEntity(authorization)); + } catch (Exception e) { + ids.add(authorization.getId()); + log.error(e.getMessage()); + } + } + + return ids; + } + + @Transactional + public void deleteAuthorization(AuthorizationMessage a) { + log.debug("Deleting authorization with id: {}", a.getId()); + authorizationRepository.deleteById(a.getId()); + } + + @Transactional + public void deleteAuthorizations(Iterable authorizations) { + log.debug("Deleting authorizations"); + for (AuthorizationMessage authorization : authorizations) { + try { + log.debug("Deleting authorization with id: {}", authorization.getId()); + authorizationRepository.deleteById(authorization.getId()); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ClientService.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ClientService.java new file mode 100644 index 0000000000..1018ea8727 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ClientService.java @@ -0,0 +1,119 @@ +package com.onlyoffice.authorization.api.services; + +import com.onlyoffice.authorization.api.crypto.Cipher; +import com.onlyoffice.authorization.api.dto.ClientDTO; +import com.onlyoffice.authorization.api.dto.PaginationDTO; +import com.onlyoffice.authorization.api.dto.RegenerateDTO; +import com.onlyoffice.authorization.api.exceptions.ClientNotFoundException; +import com.onlyoffice.authorization.api.mappers.ClientMapper; +import com.onlyoffice.authorization.api.repositories.ClientRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class ClientService { + private final ClientRepository clientRepository; + private final Cipher cipher; + + @Transactional(readOnly = true, rollbackFor = Exception.class, timeout = 2000) + public ClientDTO getClient(String id, int tenantId) { + log.debug("Trying to get a client with id {} for tenant {}", id, tenantId); + var entity = clientRepository + .findById(id) + .orElseThrow(() -> new ClientNotFoundException(String + .format("could not find client with id %s for %d", id, tenantId))); + return ClientMapper.INSTANCE.toDTO(entity); + } + + // Intentionally do not decipher secrets + @Transactional(readOnly = true, rollbackFor = Exception.class, timeout = 2000) + public PaginationDTO getTenantClients(int tenantId, int page, int limit) { + log.debug("Trying to get tenant {} clients with page {} and limit {}", tenantId, page, limit); + var data = clientRepository + .findAllByTenantId(tenantId, Pageable.ofSize(limit).withPage(page)); + + var builder = PaginationDTO + .builder() + .page(page) + .limit(limit) + .data(data.map(c -> ClientMapper.INSTANCE.toDTO(c))); + + if (data.hasPrevious()) + builder.previous(page - 1); + + if (data.hasNext()) + builder.next(page + 1); + + return builder.build(); + } + + @Transactional(rollbackFor = Exception.class, timeout = 2000) + public ClientDTO createClient(ClientDTO clientDTO) { + log.debug("Trying to create a new client"); + clientDTO.setClientId(UUID.randomUUID().toString()); + clientDTO.setClientSecret(UUID.randomUUID().toString()); + log.debug("A new client's client id is {}", clientDTO.getClientId()); + return ClientMapper.INSTANCE.toDTO(clientRepository.save(ClientMapper.INSTANCE.toEntity(clientDTO))); + } + + /** + * + * @param clientDTO + * @return a list of failed ids + */ + @Transactional + public List createClients(Iterable clientDTO) { + log.debug("Trying to save new clients"); + List ids = new ArrayList<>(); + + for (ClientDTO dto : clientDTO) { + try { + clientRepository.save(ClientMapper.INSTANCE.toEntity(dto)); + } catch (RuntimeException e) { + ids.add(dto.getClientId()); + log.debug("could not create client {}: ", dto.getClientId(), e.getMessage()); + } + } + + return ids; + } + + @Transactional(rollbackFor = Exception.class, timeout = 2000) + public ClientDTO updateClient(ClientDTO clientDTO, int tenant) { + log.debug("Trying to update a client with id {} for tenant {}", clientDTO.getClientId(), tenant); + var c = clientRepository.findClientByClientIdAndTenantId(clientDTO.getClientId(), tenant) + .orElseThrow(() -> new ClientNotFoundException(String + .format("could not find client with client id %s for %d", clientDTO.getClientId(), tenant))); + ClientMapper.INSTANCE.update(c, clientDTO); + return ClientMapper.INSTANCE.toDTO(c); + } + + @Transactional(rollbackFor = Exception.class, timeout = 2000) + public RegenerateDTO regenerateSecret(String id, int tenant) { + log.debug("Regenerating client's secret for tenant {} by client id {}", tenant, id); + String secret = UUID.randomUUID().toString(); + clientRepository.regenerateClientSecretByClientId(id, tenant, secret); + return RegenerateDTO.builder().clientSecret(secret).build(); + } + + @Transactional(rollbackFor = Exception.class, timeout = 2000) + public Boolean deleteClient(String id, int tenantId) { + log.debug("Deleting a client with id {} for tenant {}", id, tenantId); + if (clientRepository.deleteByClientIdAndTenantId(id, tenantId) < 1) + throw new ClientNotFoundException(String + .format("could not find client with client id %s for %d", id, tenantId)); + return true; + } +} diff --git a/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ConsentService.java b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ConsentService.java new file mode 100644 index 0000000000..e2706f1888 --- /dev/null +++ b/web/ASC.OAuth/api/src/main/java/com/onlyoffice/authorization/api/services/ConsentService.java @@ -0,0 +1,61 @@ +package com.onlyoffice.authorization.api.services; + +import com.onlyoffice.authorization.api.entities.Consent; +import com.onlyoffice.authorization.api.mappers.ConsentMapper; +import com.onlyoffice.authorization.api.messaging.messages.ConsentMessage; +import com.onlyoffice.authorization.api.repositories.ConsentRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ConsentService { + private final ConsentRepository consentRepository; + + @Transactional + public void saveConsent(ConsentMessage consentMessage) { + log.debug("Trying to save a new consent for {} and {}", + consentMessage.getPrincipalName(), consentMessage.getRegisteredClientId()); + consentRepository.save(ConsentMapper.INSTANCE.toEntity(consentMessage)); + } + + @Transactional + public void saveConsents(Iterable consents) { + log.debug("Trying to save consents"); + for (ConsentMessage consent : consents) { + try { + log.debug("Saving a new consent for {} and {}", + consent.getPrincipalName(), consent.getRegisteredClientId()); + consentRepository.save(ConsentMapper.INSTANCE.toEntity(consent)); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + } + + @Transactional + public void deleteConsent(ConsentMessage consentMessage) { + log.debug("Deleting a consent for {} and {}", + consentMessage.getPrincipalName(), consentMessage.getRegisteredClientId()); + consentRepository.deleteById(new Consent.ConsentId( + consentMessage.getRegisteredClientId(), + consentMessage.getPrincipalName() + )); + } + + @Transactional + public void deleteConsents(Iterable consents) { + log.debug("Trying to delete all consents"); + consentRepository.deleteAll(StreamSupport + .stream(consents.spliterator(), false) + .map(c -> ConsentMapper.INSTANCE.toEntity(c)) + .collect(Collectors.toList()) + ); + } +} diff --git a/web/ASC.OAuth/api/src/main/resources/application.yml b/web/ASC.OAuth/api/src/main/resources/application.yml new file mode 100644 index 0000000000..ffc7a8535c --- /dev/null +++ b/web/ASC.OAuth/api/src/main/resources/application.yml @@ -0,0 +1,141 @@ +server: + port: 9090 + +socket-server: + host: 127.0.0.1 + port: 8585 + +application: + security: + cipherSecret: ${CIPHER_SECRET:secret} + scopes: + - + name: accounts:read + description: read accounts + - + name: accounts:write + description: write accounts + +messaging: + rabbitmq: + configuration: + authorization: + exchange: authorization.exchange + queue: authorization.queue + routing: authorization.routing + deadExchange: authorization.dead.exchange + deadQueue: authorization.dead.queue + deadRouting: authorization.dead.routing + client: + exchange: client.exchange + queue: client.queue + routing: client.routing + deadExchange: client.dead.exchange + deadQueue: client.dead.queue + deadRouting: client.dead.routing + consent: + exchange: consent.exchange + queue: consent.queue + routing: consent.routing + deadExchange: consent.dead.exchange + deadQueue: consent.dead.queue + deadRouting: consent.dead.routing + socket: + exchange: socket.exchange + queue: ${random.uuid} + routing: socket.routing + deadExchange: socket.dead.exchange + deadQueue: socket.dead.queue + deadRouting: socket.dead.routing + +spring: + flyway: + enabled: true + baselineOnMigrate: true + url: jdbc:mysql://${JDBC_URL:onlyoffice-mysql-server}/${JDBC_DATABASE:docspace} + user: ${JDBC_USER_NAME:root} + password: ${JDBC_PASSWORD:my-secret-pw} + schemas: ${JDBC_DATABSE:docspace} + sql-migration-prefix: V + repeatable-sql-migration-prefix: R + sql-migration-separator: __ + sql-migration-suffixes: .sql + locations: classpath:migration + application: + name: authorization + profiles: + active: ${PROFILE:dev} + jpa: + show-sql: false + hibernate: + ddl-auto: none + properties: + hibernate: + generate_statistics: false + jdbc: + batch_size: 100 + order_inserts: true + dialect: org.hibernate.dialect.MySQLDialect + datasource: + url: jdbc:mysql://${JDBC_URL:onlyoffice-mysql-server}/${JDBC_DATABASE:docspace} + username: ${JDBC_USER_NAME:root} + password: ${JDBC_PASSWORD:my-secret-pw} + driver-class-name: com.mysql.cj.jdbc.Driver + rabbitmq: + host: ${RABBIT_HOST:onlyoffice-rabbitmq} + port: ${RABBIT_PORT:5671} + username: ${RABBIT_USER_NAME:guest} + password: ${RABBIT_PASSWORD:guest} + listener: + simple: + retry: + enabled: true + initial-interval: 1000 + max-attempts: 3 + max-interval: 3000 + multiplier: 3.0 + +resilience4j: + ratelimiter: + configs: + default: + limitRefreshPeriod: 1s + limitForPeriod: 1000 + timeoutDuration: 500ms + registerHealthIndicator: true + eventConsumerBufferSize: 100 + instances: + getRateLimiter: + baseConfig: default + batchRateLimiter: + baseConfig: default + limitForPeriod: 1500 + regenerateSecretRateLimiter: + baseConfig: default + limitForPeriod: 15 + updateClientRateLimiter: + baseConfig: default + limitForPeriod: 15 + deleteClientRateLimiter: + baseConfig: default + limitForPeriod: 15 + timelimiter: + instances: + mutateTimeLimiter: + timeoutDuration: 2s + readTimeLimiter: + timeoutDuration: 1s + +management: + endpoints: + web: + exposure: + include: "*" + +logging: + level: + root: INFO + org: + hibernate: + stat: DEBUG + SQL: DEBUG \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/main/resources/migration/V1_1__init.sql b/web/ASC.OAuth/api/src/main/resources/migration/V1_1__init.sql new file mode 100644 index 0000000000..7dcf0f4eed --- /dev/null +++ b/web/ASC.OAuth/api/src/main/resources/migration/V1_1__init.sql @@ -0,0 +1,114 @@ +CREATE TABLE identity_authorizations ( + id varchar(255) not null, + access_token_expires_at datetime(6), + access_token_issued_at datetime(6), + access_token_metadata text, + access_token_scopes varchar(1000), + access_token_type varchar(255), + access_token_value text, + attributes text, + authorization_code_expires_at datetime(6), + authorization_code_issued_at datetime(6), + authorization_code_metadata varchar(255), + authorization_code_value text, + authorization_grant_type varchar(255), + authorized_scopes varchar(1000), + invalidated bit, + modified_at datetime(6), + principal_name varchar(255), + refresh_token_expires_at datetime(6), + refresh_token_issued_at datetime(6), + refresh_token_metadata text, + refresh_token_value text, + registered_client_id varchar(255), + state varchar(500), + primary key (id) +) engine=InnoDB; + +CREATE TABLE identity_clients ( + authentication_method varchar(100), + client_id varchar(36) not null, + client_issued_at datetime(6), + client_secret varchar(36) not null, + description varchar(255), + logo_url varchar(255), + logout_redirect_uri tinytext, + client_name varchar(255), + policy_url varchar(255), + redirect_uri tinytext not null, + scopes tinytext not null, + terms_url varchar(255), + tenant_id integer not null, + invalidated bit, + primary key (client_id) +) engine=InnoDB; + +CREATE TABLE identity_consents ( + principal_name varchar(255) not null, + registered_client_id varchar(255) not null, + invalidated bit, + modified_at datetime(6), + scopes tinytext, + primary key (principal_name, registered_client_id) +) engine=InnoDB; + +ALTER TABLE identity_clients + ADD CONSTRAINT UK_client_id + UNIQUE (client_id); + +ALTER TABLE identity_clients + ADD CONSTRAINT UK_client_secret + UNIQUE (client_secret); + +ALTER TABLE identity_clients + ADD CONSTRAINT FK_tenant_id__id + FOREIGN KEY (tenant_id) + REFERENCES tenants_tenants (id); + +DROP EVENT IF EXISTS delete_invalidated_consents; +DROP EVENT IF EXISTS delete_invalidated_authorization; +DROP EVENT IF EXISTS delete_invalidated_clients; + +CREATE EVENT delete_invalidated_consents +ON schedule at current_timestamp + interval 1 hour + DO + DELETE FROM identity_consents ic WHERE ic.invalidated = 1; + +CREATE EVENT delete_invalidated_authorization +ON schedule at current_timestamp + interval 1 hour + DO + DELETE FROM identity_authorizations ia WHERE ia.invalidated = 1; + +CREATE EVENT delete_invalidated_clients +ON schedule at current_timestamp + interval 1 hour + DO + DELETE FROM identity_clients ic WHERE ic.invalidated = 1; + +DROP TRIGGER IF EXISTS update_entry_authorizations; +DROP TRIGGER IF EXISTS update_entry_consents; + +DELIMITER $$ +CREATE TRIGGER update_entry_authorizations +BEFORE UPDATE ON identity_authorizations +FOR EACH ROW +BEGIN + IF new.modified_at <= old.modified_at + THEN + SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Warning: updated date can not be before than existing date!'; + END IF; + +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE TRIGGER update_entry_consents +BEFORE UPDATE ON identity_consents +FOR EACH ROW +BEGIN + IF new.modified_at <= old.modified_at + THEN + SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Warning: updated date can not be before than existing date!'; + END IF; + +END$$ +DELIMITER ; \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/test/application.yml b/web/ASC.OAuth/api/src/test/application.yml new file mode 100644 index 0000000000..9df9d1707a --- /dev/null +++ b/web/ASC.OAuth/api/src/test/application.yml @@ -0,0 +1,124 @@ +server: + port: 9090 + +socket-server: + host: 127.0.0.1 + port: 8585 + +application: + security: + cipherSecret: ${CIPHER_SECRET:secret} + scopes: + - + name: accounts:read + description: read accounts + - + name: accounts:write + description: write accounts + +messaging: + rabbitmq: + configuration: + authorization: + exchange: authorization.exchange + queue: authorization.queue + routing: authorization.routing + deadExchange: authorization.dead.exchange + deadQueue: authorization.dead.queue + deadRouting: authorization.dead.routing + client: + exchange: client.exchange + queue: client.queue + routing: client.routing + deadExchange: client.dead.exchange + deadQueue: client.dead.queue + deadRouting: client.dead.routing + socket: + exchange: socket.exchange + queue: ${random.uuid} + routing: socket.routing + deadExchange: socket.dead.exchange + deadQueue: socket.dead.queue + deadRouting: socket.dead.routing + +spring: + flyway: + enabled: true + baselineOnMigrate: true + url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:33060}/${MYSQL_DATABASE:docspace} + user: ${MYSQL_USER_NAME:keycloak} + password: ${MYSQL_PASSWORD:keycloak} + schemas: ${MYSQL_DATABSE:docspace} + sql-migration-prefix: V + repeatable-sql-migration-prefix: R + sql-migration-separator: __ + sql-migration-suffixes: .sql + locations: classpath:migration + application: + name: authorization + profiles: + active: ${PROFILE:dev} + jpa: + show-sql: false + hibernate: + ddl-auto: none + properties: + hibernate: + generate_statistics: false + jdbc: + batch_size: 100 + order_inserts: true + datasource: + url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:${MYSQL_PORT:33060}/${MYSQL_DATABASE:docspace} + username: ${MYSQL_USER_NAME:keycloak} + password: ${MYSQL_PASSWORD:keycloak} + rabbitmq: + host: ${RABBIT_HOST:onlyoffice-rabbitmq} + port: ${RABBIT_PORT:5671} + username: ${RABBIT_USER_NAME:guest} + password: ${RABBIT_PASSWORD:guest} + listener: + simple: + retry: + enabled: true + initial-interval: 1000 + max-attempts: 3 + max-interval: 3000 + multiplier: 3.0 + +resilience4j: + ratelimiter: + configs: + default: + limitRefreshPeriod: 1s + limitForPeriod: 1000 + timeoutDuration: 500ms + registerHealthIndicator: true + eventConsumerBufferSize: 100 + instances: + getRateLimiter: + baseConfig: default + batchRateLimiter: + baseConfig: default + limitForPeriod: 1500 + regenerateSecretRateLimiter: + baseConfig: default + limitForPeriod: 15 + updateClientRateLimiter: + baseConfig: default + limitForPeriod: 15 + deleteClientRateLimiter: + baseConfig: default + limitForPeriod: 15 + timelimiter: + instances: + mutateTimeLimiter: + timeoutDuration: 2s + readTimeLimiter: + timeoutDuration: 1s + +management: + endpoints: + web: + exposure: + include: "*" \ No newline at end of file diff --git a/web/ASC.OAuth/api/src/test/java/com/onlyoffice/authorization/api/ApplicationAPITests.java b/web/ASC.OAuth/api/src/test/java/com/onlyoffice/authorization/api/ApplicationAPITests.java new file mode 100644 index 0000000000..3ac70c46d2 --- /dev/null +++ b/web/ASC.OAuth/api/src/test/java/com/onlyoffice/authorization/api/ApplicationAPITests.java @@ -0,0 +1,13 @@ +package com.onlyoffice.authorization.api; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationAPITests { + + @Test + void contextLoads() { + } + +} diff --git a/web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.jar b/web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..cb28b0e37c7d206feb564310fdeec0927af4123a GIT binary patch literal 62547 zcmb5V1CS=sk~Z9!wr$(CZEL#U=Co~N+O}=mwr$(Cds^S@-Tij=#=rmlVk@E|Dyp8$ z$UKz?`Q$l@GN3=8fq)=^fVx`E)Pern1@-q?PE1vZPD);!LGdpP^)C$aAFx&{CzjH` zpQV9;fd0PyFPNN=yp*_@iYmRFcvOrKbU!1a*o)t$0ex(~3z5?bw11HQYW_uDngyer za60w&wz^`W&Z!0XSH^cLNR&k>%)Vr|$}(wfBzmSbuK^)dy#xr@_NZVszJASn12dw; z-KbI5yz=2awY0>OUF)&crfPu&tVl|!>g*#ur@K=$@8N05<_Mldg}X`N6O<~3|Dpk3 zRWb!e7z<{Mr96 z^C{%ROigEIapRGbFA5g4XoQAe_Y1ii3Ci!KV`?$ zZ2Hy1VP#hVp>OOqe~m|lo@^276Ik<~*6eRSOe;$wn_0@St#cJy}qI#RP= zHVMXyFYYX%T_k3MNbtOX{<*_6Htq*o|7~MkS|A|A|8AqKl!%zTirAJGz;R<3&F7_N z)uC9$9K1M-)g0#}tnM(lO2k~W&4xT7gshgZ1-y2Yo-q9Li7%zguh7W#kGfnjo7Cl6 z!^wTtP392HU0aVB!$cPHjdK}yi7xNMp+KVZy3_u}+lBCloJ&C?#NE@y$_{Uv83*iV zhDOcv`=|CiyQ5)C4fghUmxmwBP0fvuR>aV`bZ3{Q4&6-(M@5sHt0M(}WetqItGB1C zCU-)_n-VD;(6T1%0(@6%U`UgUwgJCCdXvI#f%79Elbg4^yucgfW1^ zNF!|C39SaXsqU9kIimX0vZ`U29)>O|Kfs*hXBXC;Cs9_Zos3%8lu)JGm~c19+j8Va z)~kFfHouwMbfRHJ``%9mLj_bCx!<)O9XNq&uH(>(Q0V7-gom7$kxSpjpPiYGG{IT8 zKdjoDkkMTL9-|vXDuUL=B-K)nVaSFd5TsX0v1C$ETE1Ajnhe9ept?d;xVCWMc$MbR zL{-oP*vjp_3%f0b8h!Qija6rzq~E!#7X~8^ZUb#@rnF~sG0hx^Ok?G9dwmit494OT z_WQzm_sR_#%|I`jx5(6aJYTLv;3U#e@*^jms9#~U`eHOZZEB~yn=4UA(=_U#pYn5e zeeaDmq-$-)&)5Y}h1zDbftv>|?GjQ=)qUw*^CkcAG#o%I8i186AbS@;qrezPCQYWHe=q-5zF>xO*Kk|VTZD;t={XqrKfR|{itr~k71VS?cBc=9zgeFbpeQf*Wad-tAW7(o ze6RbNeu31Uebi}b0>|=7ZjH*J+zSj8fy|+T)+X{N8Vv^d+USG3arWZ?pz)WD)VW}P z0!D>}01W#e@VWTL8w1m|h`D(EnHc*C5#1WK4G|C5ViXO$YzKfJkda# z2c2*qXI-StLW*7_c-%Dws+D#Kkv^gL!_=GMn?Y^0J7*3le!!fTzSux%=1T$O8oy8j z%)PQ9!O+>+y+Dw*r`*}y4SpUa21pWJ$gEDXCZg8L+B!pYWd8X;jRBQkN_b=#tb6Nx zVodM4k?gF&R&P=s`B3d@M5Qvr;1;i_w1AI=*rH(G1kVRMC`_nohm~Ie5^YWYqZMV2<`J* z`i)p799U_mcUjKYn!^T&hu7`Lw$PkddV&W(ni)y|9f}rGr|i-7nnfH6nyB$Q{(*Nv zZz@~rzWM#V@sjT3ewv9c`pP@xM6D!StnV@qCdO${loe(4Gy00NDF5&@Ku;h2P+Vh7 z(X6De$cX5@V}DHXG?K^6mV>XiT768Ee^ye&Cs=2yefVcFn|G zBz$~J(ld&1j@%`sBK^^0Gs$I$q9{R}!HhVu|B@Bhb29PF(%U6#P|T|{ughrfjB@s- zZ)nWbT=6f6aVyk86h(0{NqFg#_d-&q^A@E2l0Iu0(C1@^s6Y-G0r32qll>aW3cHP# zyH`KWu&2?XrIGVB6LOgb+$1zrsW>c2!a(2Y!TnGSAg(|akb#ROpk$~$h}jiY&nWEz zmMxk4&H$8yk(6GKOLQCx$Ji-5H%$Oo4l7~@gbHzNj;iC%_g-+`hCf=YA>Z&F)I1sI z%?Mm27>#i5b5x*U%#QE0wgsN|L73Qf%Mq)QW@O+)a;#mQN?b8e#X%wHbZyA_F+`P%-1SZVnTPPMermk1Rpm#(;z^tMJqwt zDMHw=^c9%?#BcjyPGZFlGOC12RN(i`QAez>VM4#BK&Tm~MZ_!#U8PR->|l+38rIqk zap{3_ei_txm=KL<4p_ukI`9GAEZ+--)Z%)I+9LYO!c|rF=Da5DE@8%g-Zb*O-z8Tv zzbvTzeUcYFgy{b)8Q6+BPl*C}p~DiX%RHMlZf;NmCH;xy=D6Ii;tGU~ zM?k;9X_E?)-wP|VRChb4LrAL*?XD6R2L(MxRFolr6GJ$C>Ihr*nv#lBU>Yklt`-bQ zr;5c(o}R!m4PRz=CnYcQv}m?O=CA(PWBW0?)UY)5d4Kf;8-HU@=xMnA#uw{g`hK{U zB-EQG%T-7FMuUQ;r2xgBi1w69b-Jk8Kujr>`C#&kw-kx_R_GLRC}oum#c{je^h&x9 zoEe)8uUX|SahpME4SEog-5X^wQE0^I!YEHlwawJ|l^^0kD)z{o4^I$Eha$5tzD*A8 zR<*lss4U5N*JCYl;sxBaQkB3M8VT|gXibxFR-NH4Hsmw|{={*Xk)%!$IeqpW&($DQ zuf$~fL+;QIaK?EUfKSX;Gpbm8{<=v#$SrH~P-it--v1kL>3SbJS@>hAE2x_k1-iK# zRN~My-v@dGN3E#c!V1(nOH>vJ{rcOVCx$5s7B?7EKe%B`bbx(8}km#t2a z1A~COG(S4C7~h~k+3;NkxdA4gbB7bRVbm%$DXK0TSBI=Ph6f+PA@$t){_NrRLb`jp zn1u=O0C8%&`rdQgO3kEi#QqiBQcBcbG3wqPrJ8+0r<`L0Co-n8y-NbWbx;}DTq@FD z1b)B$b>Nwx^2;+oIcgW(4I`5DeLE$mWYYc7#tishbd;Y!oQLxI>?6_zq7Ej)92xAZ z!D0mfl|v4EC<3(06V8m+BS)Vx90b=xBSTwTznptIbt5u5KD54$vwl|kp#RpZuJ*k) z>jw52JS&x)9&g3RDXGV zElux37>A=`#5(UuRx&d4qxrV<38_w?#plbw03l9>Nz$Y zZS;fNq6>cGvoASa2y(D&qR9_{@tVrnvduek+riBR#VCG|4Ne^w@mf2Y;-k90%V zpA6dVw|naH;pM~VAwLcQZ|pyTEr;_S2GpkB?7)+?cW{0yE$G43`viTn+^}IPNlDo3 zmE`*)*tFe^=p+a{a5xR;H0r=&!u9y)kYUv@;NUKZ)`u-KFTv0S&FTEQc;D3d|KEKSxirI9TtAWe#hvOXV z>807~TWI~^rL?)WMmi!T!j-vjsw@f11?#jNTu^cmjp!+A1f__Dw!7oqF>&r$V7gc< z?6D92h~Y?faUD+I8V!w~8Z%ws5S{20(AkaTZc>=z`ZK=>ik1td7Op#vAnD;8S zh<>2tmEZiSm-nEjuaWVE)aUXp$BumSS;qw#Xy7-yeq)(<{2G#ap8z)+lTi( ziMb-iig6!==yk zb6{;1hs`#qO5OJQlcJ|62g!?fbI^6v-(`tAQ%Drjcm!`-$%Q#@yw3pf`mXjN>=BSH z(Nftnf50zUUTK;htPt0ONKJq1_d0!a^g>DeNCNpoyZhsnch+s|jXg1!NnEv%li2yw zL}Y=P3u`S%Fj)lhWv0vF4}R;rh4&}2YB8B!|7^}a{#Oac|%oFdMToRrWxEIEN<0CG@_j#R4%R4i0$*6xzzr}^`rI!#y9Xkr{+Rt9G$*@ zQ}XJ+_dl^9@(QYdlXLIMI_Q2uSl>N9g*YXMjddFvVouadTFwyNOT0uG$p!rGF5*`1 z&xsKPj&;t10m&pdPv+LpZd$pyI_v1IJnMD%kWn{vY=O3k1sJRYwPoDV1S4OfVz4FB z$^ygjgHCW=ySKSsoSA&wSlq83JB+O-)s>>e@a{_FjB{@=AlrX7wq>JE=n@}@fba(;n4EG| zge1i)?NE@M@DC5eEv4; z#R~0aNssmFHANL@-eDq2_jFn=MXE9y>1FZH4&v<}vEdB6Kz^l)X%%X@E#4)ahB(KY zx8RH+1*6b|o1$_lRqi^)qoLs;eV5zkKSN;HDwJIx#ceKS!A$ZJ-BpJSc*zl+D~EM2 zm@Kpq2M*kX`;gES_Dd1Y#UH`i!#1HdehqP^{DA-AW^dV(UPu|O@Hvr>?X3^~=1iaRa~AVXbj z-yGL<(5}*)su2Tj#oIt+c6Gh}$0|sUYGGDzNMX+$Oi$e&UJt3&kwu)HX+XP{es(S3 z%9C9y({_fu>^BKjI7k;mZ4DKrdqxw`IM#8{Sh?X(6WE4S6-9M}U0&e32fV$2w{`19 zd=9JfCaYm@J$;nSG3(|byYDqh>c%`JW)W*Y0&K~g6)W?AvVP&DsF_6!fG3i%j^Q>R zR_j5@NguaZB{&XjXF+~6m|utO*pxq$8?0GjW0J-e6Lnf0c@}hvom8KOnirhjOM7!n zP#Iv^0_BqJI?hR5+Dl}p!7X}^NvFOCGvh9y*hgik<&X)3UcEBCdUr$Dt8?0f&LSur ze*n!(V(7umZ%UCS>Hf(g=}39OcvGbf2+D;OZ089m_nUbdCE0PXJfnyrIlLXGh2D!m zK=C#{JmoHY1ws47L0zeWkxxV=A%V8a&E^w%;fBp`PN_ndicD@oN?p?Bu~20>;h;W` ztV=hI*Ts$6JXOwOY?sOk_1xjzNYA#40dD}|js#3V{SLhPEkn5>Ma+cGQi*#`g-*g56Q&@!dg)|1YpLai3Bu8a;l2fnD6&)MZ~hS%&J}k z2p-wG=S|5YGy*Rcnm<9VIVq%~`Q{g(Vq4V)CP257v06=M2W|8AgZO0CC_}HVQ>`VU zy;2LDlG1iwIeMj?l40_`21Qsm?d=1~6f4@_&`lp~pIeXnR)wF0z7FH&wu~L~mfmMr zY4_w6tc{ZP&sa&Ui@UxZ*!UovRT})(p!GtQh~+AMZ6wcqMXM*4r@EaUdt>;Qs2Nt8 zDCJi#^Rwx|T|j_kZi6K!X>Ir%%UxaH>m6I9Yp;Sr;DKJ@{)dz4hpG>jX?>iiXzVQ0 zR$IzL8q11KPvIWIT{hU`TrFyI0YQh`#>J4XE*3;v^07C004~FC7TlRVVC}<}LC4h_ zZjZ)2*#)JyXPHcwte!}{y%i_!{^KwF9qzIRst@oUu~4m;1J_qR;Pz1KSI{rXY5_I_ z%gWC*%bNsb;v?>+TbM$qT`_U8{-g@egY=7+SN#(?RE<2nfrWrOn2OXK!ek7v`aDrH zxCoFHyA&@^@m+#Y(*cohQ4B76me;)(t}{#7?E$_u#1fv)vUE5K;jmlgYI0$Mo!*EA zf?dx$4L(?nyFbv|AF1kB!$P_q)wk1*@L0>mSC(A8f4Rgmv1HG;QDWFj<(1oz)JHr+cP|EPET zSD~QW&W(W?1PF-iZ()b|UrnB(#wG^NR!*X}t~OS-21dpXq)h)YcdA(1A`2nzVFax9rx~WuN=SVt`OIR=eE@$^9&Gx_HCfN= zI(V`)Jn+tJPF~mS?ED7#InwS&6OfH;qDzI_8@t>In6nl zo}q{Ds*cTG*w3CH{Mw9*Zs|iDH^KqmhlLp_+wfwIS24G z{c@fdgqy^Y)RNpI7va^nYr9;18t|j=AYDMpj)j1oNE;8+QQ)ap8O??lv%jbrb*a;} z?OvnGXbtE9zt;TOyWc|$9BeSGQbfNZR`o_C!kMr|mzFvN+5;g2TgFo8DzgS2kkuw@ z=`Gq?xbAPzyf3MQ^ZXp>Gx4GwPD))qv<1EreWT!S@H-IpO{TPP1se8Yv8f@Xw>B}Y z@#;egDL_+0WDA)AuP5@5Dyefuu&0g;P>ro9Qr>@2-VDrb(-whYxmWgkRGE(KC2LwS z;ya>ASBlDMtcZCCD8h+Awq1%A|Hbx)rpn`REck#(J^SbjiHXe-jBp!?>~DC7Wb?mC z_AN+^nOt;3tPnaRZBEpB6s|hCcFouWlA{3QJHP!EPBq1``CIsgMCYD#80(bsKpvwO)0#)1{ zos6v&9c=%W0G-T@9sfSLxeGZvnHk$SnHw57+5X4!u1dvH0YwOvuZ7M^2YOKra0dqR zD`K@MTs(k@h>VeI5UYI%n7#3L_WXVnpu$Vr-g}gEE>Y8ZQQsj_wbl&t6nj{;ga4q8SN#Z6cBZepMoyv7MF-tnnZp*(8jq848yZ zsG_fP$Y-rtCAPPI7QC^nzQjlk;p3tk88!1dJuEFZ!BoB;c!T>L>xSD<#+4X%*;_IB z0bZ%-SLOi5DV7uo{z}YLKHsOHfFIYlu8h(?gRs9@bbzk&dkvw*CWnV;GTAKOZfbY9 z(nKOTQ?fRRs(pr@KsUDq@*P`YUk4j=m?FIoIr)pHUCSE84|Qcf6GucZBRt;6oq_8Z zP^R{LRMo?8>5oaye)Jgg9?H}q?%m@2bBI!XOOP1B0s$%htwA&XuR`=chDc2)ebgna zFWvevD|V882V)@vt|>eeB+@<-L0^6NN%B5BREi8K=GwHVh6X>kCN+R3l{%oJw5g>F zrj$rp$9 zhepggNYDlBLM;Q*CB&%w zW+aY{Mj{=;Rc0dkUw~k)SwgT$RVEn+1QV;%<*FZg!1OcfOcLiF@~k$`IG|E8J0?R2 zk?iDGLR*b|9#WhNLtavx0&=Nx2NII{!@1T78VEA*I#65C`b5)8cGclxKQoVFM$P({ zLwJKo9!9xN4Q8a2F`xL&_>KZfN zOK?5jP%CT{^m4_jZahnn4DrqgTr%(e_({|z2`C2NrR6=v9 z*|55wrjpExm3M&wQ^P?rQPmkI9Z9jlcB~4IfYuLaBV95OGm#E|YwBvj5Z}L~f`&wc zrFo!zLX*C{d2}OGE{YCxyPDNV(%RZ7;;6oM*5a>5LmLy~_NIuhXTy-*>*^oo1L;`o zlY#igc#sXmsfGHA{Vu$lCq$&Ok|9~pSl5Q3csNqZc-!a;O@R$G28a@Sg#&gnrYFsk z&OjZtfIdsr%RV)bh>{>f883aoWuYCPDP{_)%yQhVdYh;6(EOO=;ztX1>n-LcOvCIr zKPLkb`WG2;>r)LTp!~AlXjf-Oe3k`Chvw$l7SB2bA=x3s$;;VTFL0QcHliysKd^*n zg-SNbtPnMAIBX7uiwi&vS)`dunX$}x)f=iwHH;OS6jZ9dYJ^wQ=F#j9U{wJ9eGH^#vzm$HIm->xSO>WQ~nwLYQ8FS|?l!vWL<%j1~P<+07ZMKkTqE0F*Oy1FchM z2(Nx-db%$WC~|loN~e!U`A4)V4@A|gPZh`TA18`yO1{ z(?VA_M6SYp-A#%JEppNHsV~kgW+*Ez=?H?GV!<$F^nOd+SZX(f0IoC#@A=TDv4B2M z%G-laS}yqR0f+qnYW_e7E;5$Q!eO-%XWZML++hz$Xaq@c%2&ognqB2%k;Cs!WA6vl z{6s3fwj*0Q_odHNXd(8234^=Asmc0#8ChzaSyIeCkO(wxqC=R`cZY1|TSK)EYx{W9 z!YXa8GER#Hx<^$eY>{d;u8*+0ocvY0f#D-}KO!`zyDD$%z1*2KI>T+Xmp)%%7c$P< zvTF;ea#Zfzz51>&s<=tS74(t=Hm0dIncn~&zaxiohmQn>6x`R+%vT%~Dhc%RQ=Cj^ z&%gxxQo!zAsu6Z+Ud#P!%3is<%*dJXe!*wZ-yidw|zw|C`cR z`fiF^(yZt?p{ZX|8Ita)UC$=fg6wOve?w+8ww|^7OQ0d zN(3dmJ@mV8>74I$kQl8NM%aC+2l?ZQ2pqkMs{&q(|4hwNM z^xYnjj)q6uAK@m|H$g2ARS2($e9aqGYlEED9sT?~{isH3Sk}kjmZ05Atkgh^M6VNP zX7@!i@k$yRsDK8RA1iqi0}#Phs7y(bKYAQbO9y=~10?8cXtIC4@gF#xZS;y3mAI`h zZ^VmqwJ%W>kisQ!J6R?Zjcgar;Il%$jI*@y)B+fn^53jQd0`)=C~w%Lo?qw!q3fVi{~2arObUM{s=q)hgBn64~)W0tyi?(vlFb z>tCE=B1cbfyY=V38fUGN(#vmn1aY!@v_c70}pa(Lrle-(-SH8Nd!emQF zf3kz0cE~KzB%37B24|e=l4)L}g1AF@v%J*A;5F7li!>I0`lfO9TR+ak`xyqWnj5iwJ$>t_vp(bet2p(jRD;5Q9x2*`|FA4#5cfo8SF@cW zeO{H7C0_YJ*P@_BEvm2dB}pUDYXq@G1^Ee#NY9Q`l`$BUXb01#lmQk^{g3?aaP~(* zD;INgi#8TDZ&*@ZKhx$jA^H-H1Lp`%`O{Y{@_o!+7ST}{Ng^P;X>~Bci{|Qdf1{}p z_kK+zL;>D30r6~R?|h!5NKYOi6X&I5)|ME+NG>d9^`hxKpU^)KBOpZiU^ z;|SzGWtbaclC-%9(zR-|q}kB8H&($nsB1LPAkgcm+Qs@cAov{IXxo5PHrH(8DuEMb z3_R#>7^jjGeS7$!`}m8!8$z|)I~{dhd)SvoH9oR9#LjO{{8O&r7w{d9V1z^syn&E6 z{DG0vlQF_Yb3*|>RzVop^{$mWp|%NDYj@4{d*-@O^<(=L=DMFIQHEp-dtz@1Rumd; zadt^4B#(uUyM6aeUJkGl0GfaULpR!2Ql&q$nEV^+SiDptdPbuJ=VJ)`czZ@&HPUuj zc5dSRB&xk)dI~;6N?wkzI}}4K3i%I=EnlKGpPJ9hu?mNzH7|H0j(mN3(ubdaps3GM z1i+9gk=!$mH=L#LRDf4!mXw0;uxSUIXhl|#h*uK+fQPilJc8RCK9GNPt=X^8`*;3$ zBBo77gkGB5F8a8)*OR10nK&~8CEMPVQyhY>i`PS{L^-*WAz$ljtU%zlG1lm%%U4Zw zms0oZR8b|`>4U1X*9JLQQ>m9MF5%ppoafz^;`7DbmmIENrc$hucekkE4I83WhT%(9 zMaE;f7`g4B#vl(#tNP8$3q{$&oY*oa0HLX6D?xTW3M6f<^{%CK4OE1Pmfue`M6Dh= z&Z-zrq$^xhP%|hU&)(+2KSSpeHgX^0?gRZ5wA8@%%9~@|*Ylux1M{WQ4ekG(T+_b` zb6I)QRGp%fRF)^T?i^j&JDBhfNU9?>Sl6WVMM%S?7< ze|4gaDbPooB=F4Y=>~_+y~Q1{Ox@%q>v+_ZIOfnz5y+qy zhi+^!CE*Lv-}>g^%G=bGLqD(aTN;yHDBH#tOC=X02}QU~Xdme``Wn>N>6{VwgU~Z>g+0 zxv0`>>iSfu$baHMw8(^FL6QWe;}(U>@;8j)t)yHAOj?SdeH;evFx-kpU@nT>lsrUt zqhV}2pD^5bC4786guG1`5|fK@pE6xcT#ns)vR|^?A08G62teHaE&p`ZrCBj_Swt*~dVt=5*RK6Y{% zABqK$X59BnrK3r3u=wxklRnA1uh+q`?T0kE1YhvDWF4OY#<(+V|R@R%tdkq2huF(!Ip+EpZF3zr*|9pmKHPo)Cu z;H+^s&`Ql}u=Jt~ZWj`bAw|i-3#7(2WuRU3DU{BW8`?!O?YO1M$*MMTsaEM!5Jyp~ z!gp6yR4$O%wQ8%dyz43ZPeoJwy;o;yg=S0^Y}%|)to>=N^`!3VMf1~}OZ`Dl$q&|w z9$!i3!i1uAgPTuKSWdBrDr*N$g=E#mdqfj*h;Z}OG`{n245+g;IKfdn!&gF2OtHaD zyGDzj@@d2!P(_Ux)3v;1ABTj__{w*kaRF-1YVU`})Acgk?(T*1YqEve3=5)8bkZK* z!Tus*e$h@^u z>#zV0771Bix~r&h2FJ9)%N{>s>?2tk1$bId)1#G;OKgn-U8jUo^AK;Hu)hQEi}swD(264kAS-SBCD$R(Ro0rh8~Le zzRwxbz_JHDbD+hTX15AWmVw!#rC)-zeZahQQmo6FG1)ah3uuyIuTMof}RO!`Y3^Fxn_-G$23RDOh(@NU?r6`*S?#E50)w zpcsgDZ-iO{;EesgDQq9;p*C#QH(sp~2w^zAJWaUL%@yo)iIL6y8;e_}=dwQc%k%;H zFt5lenH*`}LWd+fPqi;exJeRZgl&nLR%|a!%1x0RQ54cgyWBYrL>sskcAtPxi&8c( zw_K?sI*3n%S;lKiYpveBN08{rgV&-B1NN5Jiu07~%n#%&f!(R(z1)xsxtRBkg#+Lv zh21zX?aYDd_f}qdA`Os*j!eC<5)iUJ&Twj7?*p%vEOGElGhpRZsccM!<k}DeC;TY;rULQs3e}lZyP#UVb=6 zB$Dkm2FaHWUXr7<{R&46sfZ)&(HXxB_=e`%LZci`s7L6c-L7iF&wdmTJz`*^=jD~* zpOZ@jcq8LezVkE^M6D9^QgZqnX&x*mr1_Cf#R9R3&{i3%v#}V$UZzGC;Or*=Dw5SXBC6NV|sGZp^#%RTimyaj@!ZuyJ z6C+r}O1TsAzV9PAa*Gd!9#FQMl)ZLHzTr99biAqA(dz-m9LeIeKny3YB=*+|#-Gq# zaErUR5Z*Wh^e<+wcm70eW;f-g=YTbMiDX)AznDM6B73)T4r%nq+*hKcKF?)#vbv?K zPMe=sFCuC*ZqsBPh-?g!m*O`}6<}Pfj}Y1n9|Y@cUdD5GX_)6Sx9pPfS7 zxkt?g6ZwJ+50C7qrh6dMFmr7qah`FskT_H=GC92vkVh$WfZa2%5L99_DxyM{$#6HQ zx$VR-Wwt!q9JL2{ybEGJr$^?!V4m_BqDqt!mbs=QjHf340+^a{)waVvP0+98(BA$M ztWr&sM=juyYgvf`(SC}+y@QtYgU>0ghJ6VbU}|kEraR&&W%#;!#KI?le%g`e>ZVPiDrneh#&1(Y?uiMo^f5qo@{JEr(p9>8GhDa+PC9yG;lX+D?hQ^fZB&Sdox219zUj_5;+n<0@Wi3@DK`MU8FM!OFJ z8*_mTA-u!Ab#95FRVWTIqAL#BVQGxE_s?>Ql|@0o9vos&r<_4d!+Q6(_270)6#lu$ zV!j$a?_V0I<(3Z=J7C-K0a^Kc1Go9p&T6yQeAD+)dG-$a&%Fo0AOte~_Z&_m2@ue~ z9cKFf-A41Dz31Ooj9FSR`l?H5UtdP?JS=UU$jF#znE1k@0g%K?KQuwZkfDI3Ai)(q z#x_Yo6WR_Y@#6I_02S&NpcP<%sw!!M_3#*8qa+*4rS@x=i{-2K#*Qr)*Q$-{<_(<| z0730e+rubnT38*m;|$-4!1r6u&Ua2kO_s-(7*NGgDTe##%I>_9uW;X__b_k)xlv$; zW%K2hsmr>5e^Z~`tS-eUgWmSF9}Yg8E}qydSVX0nYZMX_x94QK?tw2>^;raVTqstR zIrNAX2`X~|h->dTOb9IrA!i5INpLV}99ES|i0ldzC`;R$FBY5&7+TIy8%GO8SZ37_ zw=^Swk?z+j-&0-cTE|LU0q@IKRa&C6ZlXbSa2vN5r-)*f<3{wLV*uJUw980AFkWN7 zKh{?97GmVu-0rs9FB6ludy|n`gN5p~?y51aJzBg6#+-=0pWdZ2n4xTiQ=&3As-!-6 zFlb|ssAJEJL#s8(=odfz8^9b#@RrvNE4gjuEITzAd7R4+rq$yEJKXP?6D@yM7xZ&^ z@%jnE3}bteJo{p(l`hu`Yvzg9I#~>(T;>c;ufeLfc!m3D&RaQS=gAtEO-WbI+f_#| zaVpq-<%~=27U8*qlVCuI6z9@j)#R!z3{jc>&I(qT-8IBW57_$z5Qm3gVC1TcWJNc% zDk?H3%QHno@fu9nT%L^K)=#sRiRNg|=%M zR;8BE)QA4#Dsg^EakzttRg9pkfIrF3iVYVM#*_+#3X+~qeZc^WQJvEyVlO@9=0pl!ayNOh|{j0j^a z+zi_$_0QKhwArW)sJ$wji;A`?$ecbr?(4x5%2pLgh#wggbt)#T^2R3a9m+>GcrUxU z*u-WTgHAN*e!0;Wa%1k)J_P(Vdp>vwrROTVae@6Wn04q4JL-)g&bWO6PWGuN2Q*s9 zn47Q2bIn4=!P1k0jN_U#+`Ah59zRD??jY?s;U;k@%q87=dM*_yvLN0->qswJWb zImaj{Ah&`)C$u#E0mfZh;iyyWNyEg;w0v%QS5 zGXqad{`>!XZJ%+nT+DiVm;lahOGmZyeqJ-;D&!S3d%CQS4ZFM zkzq5U^O|vIsU_erz_^^$|D0E3(i*&fF-fN}8!k3ugsUmW1{&dgnk!|>z2At?h^^T@ zWN_|`?#UM!FwqmSAgD6Hw%VM|fEAlhIA~^S@d@o<`-sxtE(|<><#76_5^l)Xr|l}Q zd@7Fa8Bj1ICqcy2fKl1rD4TYd84)PG5Ee2W4Nt@NNmpJWvc3q@@*c;~%^Vasf2H`y z+~U-19wtFT?@yIFc4SE_ab?s@wEUfSkOED}+qVjjy>=eac2^S^+|_3%cjH%EUTJ&r znp9q?RbStJcT*Vi{3KDa^jr4>{5x+?!1)8c2SqiCEzE$TQ+`3KPQQnG8_Qk<^)y_o zt1Q^f{#yCUt!1e(3;E6y?>p+7sGAYLp`lA3c~Y`re9q&`c6>0?c0E2Ap5seFv92#X z1Vldj!7A8@8tWr&?%;EBQ_Fwd)8A3!wIx`V!~~h(!$pCy7=&*+*uIzG@*d%*{qG#4 zX0^}}sRN^N=p{w(+yjv%xwb!%lnVTE7l1l6gJwQmq_G83J&Y98$S!r*L8}IiIa2E= zE!0tbOuEDb*No0-KB{zjo1k#_4FHtr{!)>o+Y@bll}Sa6D^xktI0H&l{jKAK)A(iz zB-N00F?~Z}Y7tG+vp)-q*v71(C}65$-=uXx^|R$xx9zZip-V>Hqeyfd(wteM)+!!H z$s+>g4I@+`h2>C|J;PhvtOq)`xm4;CyF}R<)!ma3T{Vf_5|zo;D4YI4ZDBkE(vMeE zb#ZV;n}CgA0w8x!UC2&5Z(K)9bibj#?~>R(72lFx_Am~jS?;7mo~p+05~XGD+(wV4 zEVYnf0N5+-7O+Gc1L!sPGUHv<6=cV8}*m$m`kBs@z zy;goR(?J^JrB7uXXpD00+SD0luk!vK3wwp(N%|X!HmO{xC#OMYQ&a7Yqv-54iEUK4 zVH;)rY6)pUX~ESvQK^w|&}>J{I?YlvOhpMgt-JB}m5Br`Q9X+^8+Xa%S81hO<1t#h zbS+MljFP1J0GGNR1}KwE=cfey%;@n&@Kli+Z5d>daJjbvuO3dW{r$1FT0j zR$c9$t~P50P+NhG^krLH%k}wsQ%mm+@#c;-c9>rYy;8#(jZ|KA8RrmnN2~>w0ciU7 zGiLC?Q^{^Ox-9F()RE^>Xq(MAbGaT0^6jc>M5^*&uc@YGt5Iw4i{6_z5}H$oO`arY z4BT(POK%DnxbH>P$A;OWPb@gYS96F7`jTn6JO@hdM za>_p!1mf?ULJZb1w-+HamqN__2CtI%VK`k^(++Ga0%z*z@k0wYJDqT^)~%|4O299; zh1_iRtc7you(kOK8?Q$R7v-@Qk4+i=8GD2_zI0%{Ra`_prF{+UPW^m5MCA&4ZUpZb z2*!)KA8b--Upp~U%f+rsmCmV~!Y>Gzl#yVvZER2h;f&rkdx{r#9mc8DZMJaQXs?SL zCg3#>xR6ve8&YkP*`Z=lng|Ow+h@t*!Ial*XQg3P;VS8@E1C)VS`?L9N+rxlD7bxC z3@Ag)Vu?#ykY`ND+GvRYTUP&-KDMiqly$Z~uFXt^)4Jjk9RIs*&$?-UPM*d7&m${m zm12kaN3mV1J|c6f$>V+{lvHp~XVW3DU0;cBR>7|)4bo{xa1-ts-lYU-Q-b)_fVVl`EP5X}+J9EzT20x8XIv=m7witdu7!3Lh=KE#OyKpT1GWk{YAo^ny|fvZt<+jmsFs=l*%e& zmRkBt5ccv4O7!HAyv2~rsq*(FmMTm?@TX3&1`nu|7C^F{ad%GLuoX}Rl}6`)uHF_xlx^gVca+mGH4T8u8;q{S*x3=j;kelz^atO~)v!Q_BT z4H6%IA}bvfuk0_vweELeEl8N5w-Q1GF!@f{VKnbyYB2?}d&QvI-j}~RI_+9t9$tC2 z94m=3eLi=sQb^S5;fqP?3aaXc&`}`lq z&M8dOXvxx9Y1^u_ZQHhO+qP}nwkvJhwoz$Mp6Qcq^7M#eWm}!3U@s07hop` zW24|J{t$aB`W>uBTssEvYMyi$hkaOqWh+^(RV_1MYnE0XPgW?7sBDk=Cqs(;$qrPEflqa0ZE?A3cBfW%0RPA235Wb6@=R_d>Sez; z`spwa50bq?-zh+id~Q!T`AYn`$GHzs;jxIw(A1_Ql&f|qP}|bon#H;sjKmSDM!nyn z>bU8l%3DB3F+$}|J^da!!pN|DO!Ndc2J)wMk!+Rr1hes#V}5o(?(yQSphn|9_aU<- zn|nsDS{^x&tweP;Ft`2ur>Koo2IdXJDsr6IN)7vB41Yy-^Wbo9*2th2QA@C zE0-0Gk12YOO?d_Guu6b3&(PIL`d zh4{`k54hu9o%v1K3PGuccez-wdC<&2fp)>`qIIaf)R{5un7-vwm=>LD7ibnJ$|KyE zzw`X*tM0S|V(I3vf454PY{yA5lbE+36_<1kd=&0Xy4jfvUKZ0$Jq!AG4KS7DrE9rph;dK^6*#CIU9qu7 z?)6O`TN&MCWGmUVd1@E2ow2`vZ1A#nGo8_n!dmX77DCgAP1va*ILU+!a&$zdm6Pa6 z4#|*&3dM+r_RJb%!0}7X!An&T4a4@ejqNJ;=1YVQ{J6|oURuj8MBZ8i7l=zz%S4-; zL}=M^wU43lZVwNJgN|#xIfo$aZfY#odZ6~z?aNn=oR1@zDb=a(o3w`IGu&j>6lYxL z&MtqINe4Z>bdsHNkVIu$Dbq0wc#X-xev221e~L zbm8kJ(Xzij$gF4Ij0(yuR?H1hShSy@{WXsHyKtAedk4O!IdpR{E32Oqp{1TD{usJi zGG@{3A$x%R*pp8b$RQo4w&eDhN`&b~iZ2m3U>@9p1o5kXoEVmHX7I6Uw4dn((mFw` zilWrqFd=F5sH$&*(eJB52zaLwRe zz`sruIc=Ck75>v5P5kd>B2u=drvGPg6s&k5^W!%CDxtRO)V6_Y_QP{%7B>E~vyMLG zhrfn8kijyK&bX+rZsnSJ26!j$1x+V!Pyn|ph%sXWr9^f&lf|C;+I^Fi_4;`-LJI&F zr;5O@#4jZX=Yaw0`pUyfF4J8A9wE#7_9!X|_s8~YUzWu&#E^%4NxUA3*jK-F5R3LP2|msHBLmiMIzVpPAEX)2 zLKYjm3VI4r#7|nP^}-}rL+Q4?LqlmBnbL+R8P%8VmV{`wP0=~2)LptW_i682*sUR# z+EifOk_cWVKg-iWr^Qf4cs^3&@BFRC6n0vu{HqZzNqW1{m)3K@gi$i}O(hT`f#bT- z8PqCdSj~FncPNmMKl9i9QPH1OMhvd42zLL~qWVup#nIJRg_?7KQ-g3jGTt5ywN;Qx zwmz4dddJYIOsC8VqC2R%NQ>zm=PJH70kS|EsEB>2Otmtf-18`jUGA6kMZL3vEASDN zNX%?0+=vgsUz!dxZ@~)eU17m4pN3xGC0T;#a@b9Iu0g_v*a3|ck^s_DVA^%yH-wt= zm1)7&q6&Rq#)nc9PQ6DKD{NU=&ul10rTiIe!)x^PS~=K(wX9|?k&{Mv&S$iL9@H7= zG0w~UxKXLF003zJ-H%fGA4Db9{~#p&Bl7ki^SWwv2sfoAlrLMvza)uh;7Aa_@FL4b z4G>`j5Mn9e5JrrN#R$wiB(!6@lU@49(tawM&oma6lB$-^!Pmmo;&j57CDmKi)yesg~P;lJPy9D(!;n;^1ql)$5uYf~f z&GywSWx=ABov_%8pCx=g-gww_u26?5st=rdeExu?5dvj^C?ZZxDv@Si^nX~2qA&K= z2jr;{=L(x~9GLXrIGXs>dehU^D}_NMCMegdtNVWyx)8xHT6Qu!R>?%@RvADs9er;NMkweUBFNrBm1F5e0_>^%CwM6ui}K_MpRqLS0*@lAcj zB6TTCBv>w2qh)qU3*kN+6tPmMQx|5Z0A4n67U-nss90Ec_rDF}r)IR4PE{$8;BSt= zT%6|jyD^(w6a*A5>_|TkMqx~e$n@8{`q?|)Q&Y4UWcI!yP-8AwBQ#P`%M&ib;}pli z9KAPU_9txQ3zOM#(x}*lN8q$2(Tq1yT4RN0!t~|&RdQMXfm!81d0ZuyD}aG3r4+g` z8Aevs3E_ssRAMR+&*Q30M!J5&o%^(3$ZJ=PLZ9<@x^0nb>dm17;8EQJE>hLgR(Wc% zn_LXw|5=b$6%X zS~ClDAZ?wdQrtKcV9>_v1_IXqy)?<@cGGq#!H`DNOE1hb4*P_@tGbMy6r@iCN=NiA zL1jLwuMw&N-e9H(v7>HGwqegSgD{GSzZ@sZ?g5Y`fuZ^X2hL=qeFO(;u|QZl1|HmW zYv+kq#fq_Kzr_LaezT zqIkG6R+ve#k6!xy*}@Kz@jcRaG9g|~j5fAYegGOE0k8+qtF?EgI99h*W}Cw z7TP&T0tz4QxiW!r zF4?|!WiNo=$ZCyrom-ep7y}(MVWOWxL+9?AlhX<>p||=VzvX`lUX(EdR^e5m%Rp_q zim6JL6{>S%OKoX(0FS>c1zY|;&!%i-sSE>ybYX3&^>zb`NPj7?N^ydh=s=0fpyyz% zraFILQ17_9<ettJJt~I+sl=&CPHwz zC9dEb#QFQcY?bk11Y=tEl{t+2IG`QFmYS>ECl;kv=N6&_xJLQt>}ZQiFSf+!D*4Ar zGJ~LFB7e_2AQaxg*h{$!eJ6=smO(d2ZNmwzcy3OG@)kNymCWS44|>fP^7QkJHkE9JmLryhcxFASKb4GYkJ|u^Fj=VdF0%6kgKllkt zC|_ov2R4cJ2QjjYjT6jE#J1J<xaNC>Xm;0SX<`LuW*}*{yQ3c9{Zl=<9NP z^2g5rAdO!-b4XfeBrXa4f{M0&VDrq+ps&2C8FYl@S59?edhp~7ee>GR$zQI4r8ONi zP^OA+8zrTAxOMx5ZBS03RS@J_V`3{QsOxznx6Yt*$IuEd3%R|Ki&zZkjNvrxlPD$m z%K+rwM!`E&Z46ogXCu!3 z8use`FJJ?g_xi?~?MxZYXEu=F=XTC8P3{W*CbG3Wk)^31nD~W>*cJ@W4xg%Qqo7rq z`pUu8wL!6Cm~@niI*YmQ+NbldAlQRh?L!)upVZ)|1{2;0gh38FD&8h#V{7tR&&J}I zX1?;dBqK}5XVyv;l(%?@IVMYj3lL4r)Wx9$<99}{B92UthUfHW3DvGth^Q0-=kcJ1 z!*I9xYAc$5N$~rXV>_VzPVv`6CeX(A_j3*ZkeB~lor#8O-k+0OOYzTkri@PVRRpOP zmBV|NKlJT?y4Q82er)@lK&P%CeLbRw8f+ZC9R)twg5ayJ-Va!hbpPlhs?>297lC8 zvD*WtsmSS{t{}hMPS;JjNf)`_WzqoEt~Pd0T;+_0g*?p=dEQ0#Aemzg_czxPUspzI z^H5oelpi$Z{#zG$emQJ#$q#|K%a0_x5`|;7XGMuQ7lQB9zsnh6b75B9@>ZatHR_6c z0(k}`kfHic{V|@;ghTu>UOZ_jFClp>UT#piDniL(5ZNYXWeW0VRfBerxamg4su5<; z(}Ct2AhR@I-ro0}DdZLRtgI@dm+V`cRZjgV-H+aXm5|Mgz`aZX63i<|oHk-E)cABn z0$NR?(>fla7)Ong28FZSi9Yk0LtYl5lZw5wT!K5=fYT$avgkMKJWx~V#i@7~6_{dM zxDDPIW2l{O2Elv#i^cjYg~lGHRj(W*9gD`(FILKY$R`tL2qo&rtU*c;li!V`O$aV{ z!m|n!FAB2>MR_FVN*Ktv5+2dW4rr3YmfEheyD+48%USM#q6)w%#2}~=5yZE1LLcth zF%VtefH&#AcMx7)JNC$P>~OFuG6sK}F7V$D7m!{ixz&inpAVpFXiu^QruAw@Sc7Y2 z_A^V(2W_+KTGRp2aQSMAgyV#b3@{?5q@hPEP6oF3^}|@8GuD6iKbX;!LI!L=P#Za zL$Zuv#=x3fseRMZ()#SQcXv->xW`C|6quwqL1M&KByBj z2V`}(uL4JB-hUs6304@%QL~S6VF^6ZI=e-Nm9Tc^7gWLd*HM-^S&0d1NuObw-Y3e> zqSXR3>u^~aDQx>tHzn9x?XRk}+__h_LvS~3Fa`#+m*MB9qG(g(GY-^;wO|i#x^?CR zVsOitW{)5m7YV{kb&Z!eXmI}pxP_^kI{}#_ zgjaG)(y7RO*u`io)9E{kXo@kDHrbP;mO`v2Hei32u~HxyuS)acL!R(MUiOKsKCRtv z#H4&dEtrDz|MLy<&(dV!`Pr-J2RVuX1OUME@1%*GzLOchqoc94!9QF$QnrTrRzl`K zYz}h+XD4&p|5Pg33fh+ch;6#w*H5`@6xA;;S5)H>i$}ii2d*l_1qHxY`L3g=t? z!-H0J5>kDt$4DQ{@V3$htxCI;N+$d^K^ad8q~&)NCV6wa5(D${P!Y2w(XF!8d0GpJ zRa=xLRQ;=8`J2+A334};LOIhU`HQ*0v4Upn?w|sciL|{AJSrG_(%-(W9EZb%>EAGG zpDY?z1rQLps`nbCtzqJ#@wxU4}(j!ZQ{`g`g*SXlLah*W9 zyuh)UWoRCknQtd~Lk#BT_qjwj&Kw8U)w=owaJ;A5ae}3)y>{neYNS`|VHJdcSEBF# zBJ6a;T)u;^i#L~LVF-X7!E$SggILXMlsEy~v}K*DM2)f@U~g|Q6I-Pss@)`>fgFWx zsq&7pe!|VA-h;@=fBF{(mR1^{1>ukTYUdyF^#A+(|I_&nm{_xaKn3h4&yMyym2k-wMFg(s@ez=DPmuB%`| z6;e@HQKB(|!PU1sW)W6~x|=8m6rL~4dQ9LTk|RzL-_(_77B4I~ZG=q7K%qHiv!FD8 zmt;Vnhb{ymaydv2V;X-5p zTt2ln?kaB9&(dH_X70^@rrCfz)nwfa9LYTHXO(IPcTEf$QiEhTpl??L+`Eetyqof8 zzl=q)?KdYni!C_9b8Z3xm7r5<5ZG-0uA`u^7Dm7k4mAsQ(rkoWy*^DZJa~#y6+hNG zh?7{D9$a9LS`a@SvZ5?C{JUHovWU9KI}z8YV4pWftx21v*Q;MpU{+b@>Or(}pwO^fu0qA3_k_Bo2}lIxvmMhucG-o>O=+R6YxZ zjs!o%K1AA*q#&bs@~%YA@C;}?!7yIml1`%lT3Cvq4)%A)U0o1)7HM;mm4-ZZK2`Lj zLo?!Kq1G1y1lk>$U~_tOW=%XFoyIui^Cdk511&V}x#n4JeB7>bpQkYIkpGQRHxH$L z%tS=WHC~upIXSem>=TTv?BLsQ37AO88(X+L1bI<;Bt>eY!}wjYoBn#2RGEP49&ZH-Z_}R_JK_ z>o*_y!pOI6?Vf*{x-XT;^(_0}2twfk`*)_lLl0H-g|}BC?dm7CU|^-gNJ~rx z($>97WTKf71$?2|V$Ybpf~Aj@ZZOcb3#uRq51%4^ts-#RMrJhgm|K3QpCsPGW=2dZ zAr5-HYX!D*o#Q&2;jL%X?0{}yH}j*(JC4ck;u%=a_D6CrXyBIM&O#7QWgc?@7MCsY zfH6&xgQmG$U6Miu$iF(*6d8Mq3Z+en_Fi`6VFF=i6L8+;Hr6J zmT=k0A2T{9Ghh9@)|G5R-<3A|qe_a#ipsFs6Yd!}Lcdl8k)I22-)F^4O&GP&1ljl~ z!REpRoer@}YTSWM&mueNci|^H?GbJcfC_Y@?Y+e4Yw?Qoy@VLy_8u2d#0W~C6j(pe zyO6SqpGhB-;)%3lwMGseMkWH0EgErnd9a_pLaxbWJug8$meJoY@o-5kNv&A$MJZ=U z^fXPLqV6m3#x%4V*OYD zUPS&WHikdN<{#Yj|EFQ`UojD4`Zh*CZO4Cv`w^&*FfqBi`iXsWg%%a< zk@*c%j1+xib(4q^nHHO^y5d8iNkvczbqZ5;^ZVu%*PJ!O?X-CoNP*&tOU!5%bwUEw zQN?P*a=KKlu{`7GoA}DE=#nDibRgecw>-*da~7&wgow}|DyCJq!-Lp8a~(zR@tO1 zgu(4s4HptPGn(HmN2ayYs@g+yx1n`nU3KM{tQHhMHBw7f#gwru$=C()`aKZAl^dYc ze7fC)8EZEXOryk6AD&-4L+4cJ&M@3;;{R)mi4=`ti7IZByr^|_HNsjcNFu?mIE)jD za2j)FPwRY!R_YR-P?URm0Pti*e#5jmfK)6EvaKCT{h)kbJl{AGr1Ekt}pG?^e z*botRf-RsB8q10BTroj{ZP**)2zkXTF+{9<4@$aNDreO7%tttKkR3z`3ljd?heAJEe<0%4zYK?};Ur*!a>PbGYFFi(OF-%wyzbKeBdbkjv^i9mn@UocSS z4;J%-Q$l`zb&r*Pb`U;3@qkc=8QaPE9KwmlVwAf01sa*uI2*N`9U^3*1lLsM9dJ(4 zZBkU}os|5YT#Z;PD8xVv!yo$-n{-n4JM5ukjnTciniiT`(cZ6sD6~67e5_?8am%!w zeCLUxq~7x-!Xg#PgKV&caC@7mu<86am{WaXo(lAemt4~I$utSp(URWpYNo$RvU*$N z#%iiA+h`(E;BUg;=I!#EaxO89bUK3*v5Nc3GPmURC5TqzC|))DsFNtJICH6oBW6#q z+B(N{ey+^mk_{!@ z)VhAWXG=_0j|0f9iJ;c404PiIFqK)(AD05Xh`Fk`r$^b`v+>*g+_+h@r)e+ELJ45) z?20~u<}HQyQ5AsBz(teF9!!_GLXnm{5Z0e{Ki*@!=&3x4-RcjBn##DDzHJ|KSZ5(E z9=tFZ)p~-}x%9sCY27)2i>(E-^OiYT?_)a;yXAGR$y+E`myMd;xDA#_Q49t*E}&ql#H~|x z2J2R1_#2lt91NnF!uqW%_=HlbF?A{B{n>}9$g5QF!bh_a7LTU~Jyz}7>W5{_LAov{ zy2_dmGy)d)&7^bJyUjEw%3xj{cuG0Eo zwL*XQB*Oi=r&HIIecC1%lbE;Y-*5|cL955S+2@uR18JDL<0;;Uc2Q9JEyo1R!!sz_ z#BqnkGfbLP#oQJk3y}nwMd(3Tt^PVA#zXnYF7D0W1)#+`i?@cm}fBkKD z+Mpcuim53|v7;8Tv(KraEyOK`HvJq^;rlNzOjIbW&HJDFqW>doN&j7)`RDv#v|PQ+ z03WnB4Y4X@Fe-@%3;He*FjY1MFmkyv0>64Cp~FIDKQTwmFP~_CxZOf{8gPy}I<=JC zo%_bmue&$UU0|GG%%99eI!m#5Y1MD3AsJqG#gt3u{%sj5&tQ&xZpP%fcKdYPtr<3$ zAeqgZ=vdjA;Xi##r%!J+yhK)TDP3%C7Y#J|&N^))dRk&qJSU*b;1W%t1;j#2{l~#{ zo8QYEny2AY>N{z4S6|uBzYp>7nP_tqX#!DfgQfeY6CO7ZRJ10&$5Rc+BEPb{ns!Bi z`y;v{>LQheel`}&OniUiNtQv@;EQP5iR&MitbPCYvoZgL76Tqu#lruAI`#g9F#j!= z^FLRVg0?m$=BCaL`u{ZnNKV>N`O$SuDvY`AoyfIzL9~ zo|bs1ADoXMr{tRGL% zA#cLu%kuMrYQXJq8(&qS|UYUxdCla(;SJLYIdQp)1luCxniVg~duy zUTPo9%ev2~W}Vbm-*=!DKv$%TktO$2rF~7-W-{ODp{sL%yQY_tcupR@HlA0f#^1l8 zbi>MV~o zz)zl1a?sGv)E}kP$4v3CQgTjpSJo?s>_$e>s2i+M^D5EfrwjFAo(8E%(^ROV0vz0o z-cg0jIk24n!wxZainfH)+?MGu@kg$XgaMY-^H}z^vG~XC7z2;p2Kv`b^3S#b5ssMOJ7724v>S36dD zeypxJ<=E~sD4f5wX060RIF-AR0#{Z z=&y$r8A-e6q18lIF{@O9Mi%dYSYT6erw!@zrl=uj>o(3=M*Bg4E$#bLhNUPO+Mn}>+IVN-`>5gM7tT7jre|&*_t;Tpk%PJL z%$qScr*q7OJ6?p&;VjEZ&*A;wHv2GdJ+fE;d(Qj#pmf2WL5#s^ZrXYC8x7)>5vq_7 zMCL}T{jNMA5`}6P5#PaMJDB2~TVt;!yEP)WEDAoi9PUt89S2Cj?+E0V(=_sv4Vn6b z_kS6~X!G;PKK>vZF@gWpg8Zuh%YX^2UYPdCg7?EH#^gkdOWpy(%RnXyyrhmJT~UJw zAR;%Zgb6z(mS+o9MT|Sc6O({!i0pzk;s9?Dq)%tTW3*XdM3zhPn*`z45$Bg!P4xfy zD*{>30*JsSk?bQ-DgG62v>Vw-w`SA}{*Za7%N(d-mr@~xq5&OvPa*F2Q3Mqzzf%Oe z4N$`+<=;f5_$9nBd=PhPRU>9_2N8M`tT<-fcvc&!qkoAo4J{e3&;6(YoF8Wd&A+>; z|MSKXb~83~{=byCWHm57tRs{!AI<5papN(zKssb_p_WT@0kL0T0Z5#KLbz%zfk?f7 zR!vXBs36XaNcq5usS7<>skM_*P$e*^8y1ksiuokbsGFQ_{-8BAMfu!Z6G=88;>Fxt z|F-RU{=9i6obkTa0k~L#g;9ot8GCSxjAsyeN~1;^E=o5`m%u7dO1C*nn1gklHCBUw z;R(LgZ}sHld`c%&=S+Vx%;_I1*36P`WYx%&AboA1W@P;BvuFW+ng*wh?^aH4-b7So zG?9kFs_6ma85@wo!Z`L)B#zQAZz{Mc7S%d<*_4cKYaKRSY`#<{w?}4*Z>f2gvK`P1 zfT~v?LkvzaxnV|3^^P5UZa1I@u*4>TdXADYkent$d1q;jzE~%v?@rFYC~jB;IM5n_U0;r>5Xmdu{;2%zCwa&n>vnRC^&+dUZKy zt=@Lfsb$dsMP}Bn;3sb+u76jBKX(|0P-^P!&CUJ!;M?R?z7)$0DXkMG*ccBLj+xI) zYP=jIl88MY5Jyf@wKN--x@We~_^#kM2#Xg$0yD+2Tu^MZ1w%AIpCToT-qQbctHpc_ z>Z97ECB%ak;R<4hEt6bVqgYm(!~^Yx9?6_FUDqQQVk=HETyWpi!O^`EZ_5AoSv@VbUzsqusIZ;yX!4CsMiznO}S{4e>^0`c<)c~mC#*{90@+T@%EQ~>bovc8n_$bvqkOU7CrYe8uI5~{3O7EijeX`js z-$LNz4pJA7_V5~JA_Wl*uSrQYSh9Wm($%@jowv^fSPW<~kK&M*hAleywHd?7v{`;Y zBhL2+-O+7QK_)7XOJAbdTV-S`!I)t~GE8z+fV7y;wp#!wj75drv;R*UdSh(}u$%{VSd0gLeFp;h6FkiVz%g=EY3G#>RU;alRy;vQmk*| z@x-ba0XKE%IyL4OYw6IXzMiS(q^UDk=t(#XgkuF`{P?=k8k3r)rmhkv`vg@kiWd34 z-~t+1aV3SabTbG=nQYs>3~E<}{5@0g**LAWi*~SfRZhGcgP{e5T!0M7CU}`f@r8xI z0bx%sI!?5);-wG+Mx&S=NRfIi>V-wP(n&$X0Bhd)qI^ch%96s6&u7qpiK8ijA=X_R zk&|9f$GXf-;VgnrxV83Cp-Q!!sHH`5O^o~qZu!xny1t?(Au(EAn)D??v<1Uo;#m7-M@ovk|()C(`o>QMTp}F?> zakm3bHBKUjH-MHXDow7#Z|@wea1X9ePH;%YA)fCZ9-MD)p^(p!2E`aU9nmJlm;CXQ zkx~$WQ`Yq{1h5k>E>Ex{Z=P=)N*0b8_O({IeKg?vqQ)hk=JHe z5iqUKm!~mLP0fnRwkCO(xxTV@&p+o8wdSP$jZofYP}yEkvSc z5yD-^>04{zTP7X44q9Af&-wgt7k|XtncO&L@y-wFFR44RsPu57FRvIBaI^Pqy_*DV z@i13CsaR5@X@xH=NT3}T`_vsy!a02n80eQqya=-p7#YW`Jc0z!QglGg`1zeg6uXwI zsB~hlNMo)kFL(V3Q1<%8yoI6X7ncn-&&Uh3rL@S(6@wKAXt6Wr=a2ObI7}8$D-FoI z>AJA>WsBEMi5ba6JhJ%9EAi&ocd(ZsD|MsXwu@X;2h#|(bSWu@2{+c7soC`%uo{sMYq&Vyufb)?OI59ds)O+kyE8@G z@tlpNr0UO~}qd0HQve6njJ zda2+l$gdX7AvvGhxM6OToCuQ|Zw|9!g1)O+7>~{KNvASjp9#Cqce-or+y5xdzWL3gLWt2oa+T(I+{j(&bF1laUsJB{fOgE-B}qslaS>C z)TjzG8XecbS%a+?yT!0QmTex?E478;D|sL*oS4C-g0Tq(YoH|eyxJ#1j088C|U-w5id`%Sz7X_w#l+U9+)$|2no<}5J zRb_9@0esSr?n}HvVGbD5@$p$8k4?qOe-GNOk3-K^Mw>Xg+drCKi5@$GTeijpI;;IG ziD<&go`ptLC&^<0jw^l0aY?_pUUK+xp#0Bk66iQ29vpR)VBE{JOJ&OL^gKsN<&t<| zCMLTYMSDG5Ie9O>6Dl#T{@cscz%)}?tC#?rj>iwQ0!YUk~R z$rB-k=fa9x&631Z9Mfqj_GRoS1MzqSMEdaZ2!isP19Sr>qG8!yL(WWF)_&{F)r>KnJGSciSp!P0fqHr+G=fGO02Q#9gHK zpwz+yhpC4w*<9JO@#(MdkZcWbdCO5B!H`Z|nV?UtcBo96$BgX+7VYMwp@b-%;BrJu zMd*K!{1txv{kHKPDs9?WZrz_^o1Tq2P=+=|E=Oy4#WE{>9}*9(apqhmE`&AeBzQgQ zELFLCmb~q|6y0FCt|B}*uI*ayZ#6=$BpGtF{Jfye#Q>FZ?BPnk)*Qmd?rNG^tvFUU z_b&antYsZnUR6Q9tQUy81r$&ovT#fy;(Db4F&M*C=KxQgHDrRcVR#d+ z0(D|*9#u`w_%2o3faI{?dNd9$#5nj1PROHNq z7HJ(;7B1ThyM>a@Fo^lJb2ls2lD`}ocREH|5pKN;$>gFyM6k)kZG;lA;@kSJIqUhf zX%dhcN(Jtomz4(rNng&1br3Xx33EvCWz%o8s;SpRiKEUFd+KJ+u|gn|J85dZ)Exc&=V|Ns8Xs#P>qv6PX&VAJXJ(ILZO!WJd0 z`+|f5HrEj~isRN7?dBHotcPI7;6W48*%J(9 zftl1Tr`bKH*WNdFx+h;BZ+`p!qKl~|Zt5izh}#pU9FQKE97#$@*pf38Hr8A+`N+50U3$6h%^!4fBN zjh^cl#8qW5OZbvxCfYzKHuyeKLF4z^@~+oqlz9(Hx8vypIiUlt!(vs}_t#4@nh$s; z>FYERg*KD#Xs+W4q-V-IBQK!)M1)Aa+h+V+is)z!_=gEn&^ci7<DEEmYcoSh?WdXUsP7O4)&lQXA(BVM5jI8s6;mO}94AC0gG(`>|T)yuV1l~i-ejCCt zoejDhX0nrZDP|x9u4zp%S2UeDzV`o#pBGu1tZ-$<9TIbN=ALwhQ0=9S{8#}Uu8n-~ z5~xIvUhLSz@c@0|me$CdZCpZl(vQw@a0Y4^{T0w_>pOkwI^x4KkBf3qGmm)nG|Ps5 z_XTY~^b^mL&_*yjl~RRIi&eS(>y?y}O4-)nWyTEPpQAb#Xz8SnnfIL+nAcNL9nqV9 zRL|eyF)RKI5-kJO6}>Q89XmgY@b1&!JI>g3ryZ@jN2v3vm7O`AL!BTWNouJzV+$+Y zYY}u%i>K6=IYU2O$2TAyVjGt?wgF9xCj;?EK(8fWu!!~48`3u^W$eUlCh*91PLxu1 zRY(F7Q3s7h$Q-p&L$ucN}it*-9KR z_<wHu?!dav0$P+PI3{J8?{+l|n&2YMLV2 z+hRta$A5WpCXl1RNbYBsX8IGX{2v>U|8_I-JD56K|GexW>}F_e_g_1r?08v8Kz{V$ zT=6aGMk>ibvRO@Yrc@ezaD0%ydHkXGHrR{7>q~~tO7ChJflwa4-xL|@#YIJejC5VT zInU4CjQ9V0+lClQY=vh^s4MadwQmk7li{54Y;Ht}gkZOIh9(vfK?3kXLoD72!lHD# zwI-Jg|IhT=Y#s|tso1PWp;|aJ2}M?Y{ETyYG<86woO_b+WVRh<9eJu#i5jxKu(s~3 z4mz+@3=aNl^xt{E2_xewFIsHJfCzEkqQ0<7e|{vT>{;WlICA|DW4c@^A*osWudRAP zJut4A^wh@}XW4*&iFq|rOUqg*x%1F+hu3U6Am;CLXMF&({;q0uEWG2w2lZtg)prt` z=5@!oRH~lpncz1yO4+)?>NkO4NEgP4U~VPmfw~CEWo`!#AeTySp3qOE#{oUW>FwHkZ3rBaFeISHfiVSB7%}M) z=10EZ1Ec&l;4 zG98m5sU!pVqojGEFh8P{2|!ReQ&hfDEH2dmTVkrS;$dN~G2v-qnxn^A2VeHqY@;P} zudZD5vHtVvB*loIDF1M7AEEvS&h0;X`u}!1vj6S-NmdbeL=r{*T2J6^VA7F`S`CDd zY|=AA6|9Tu8>ND6fQhfK4;L3vAdJPBA}d6YOyKP&ZVi%z6{lbkE|VyB*p1_julR^k zqBwjkqmFK=u&e8MfArjW-(Ei8{rWso1vt5NhUdN|zpXqK{ylJ8@}wq-nV~L4bIjtt zt$&(1FTIs+aw}{&0SO4*sa0H2h&7g}VN5uYjfed5h7eGp$2Wu*@m9WIr0kxOc}fX9eOWh zFKfV>+SD$@kESKYm{F*J90XQjr$!<~v(J%&RMuQM+6CkmnYZDGlOUdq}%)VA& zl#acS%XE2KuX~7IamK`og@C`21~*cEEc#PZM6HT*Veb_l&Ej~j0zL7p0Eo`mMu(=X zJ$v;&Lya75I4C^saKROgfi(fdP0C$GM3WyZn%mm3yEI>|S&O(u{{S<}ihUp#`X&_z zmQBma;82#`C;dR5Sx09e07FvtJLhZ{9R~|$FCdU6TDNUwTc9kNct?8e@o2MpQDrkg zN?G+aYtTjiUPA=RX5o{4RYu}6;)ET>TcgL^VpfIpluJ|lQR(_)>6k%L^FZmoK-Wm- zR5qy0P)hm8yvqOL>>Z;k4U}!s?%1~7v7K~m+gh=0c9Ip_9UC3nwr$%^I>yU6`;2kV z-uJ%y-afzA7;BC7jc-=XnpHK+Kf*tcOS>f5ab2&J&5hIOfXzs=&cz|Qmrpu6Z);`R z0%3^dioK5x?o7t~SK7u5m{dyUZ#QUPqBHYn@jETeG>VU=ieZuJ;mm^j>dZM7))cw?a`w8R z%3M0R=kdOt^W^$Kq5Z%aJ(a$(*qFpy^W}Ij$h+Jnmc9eaP(vB@{@8t zz=RQ$x4XYC#enS$fxh@;cSZ|D%7ug;0z{C8I8h{KocN-cyv3UG_nk99UNS4ki^OFkYea`q`rs zG@qdMI;4ogcd5Tr`di1JBg4I*6CFvCID_2SN5&)DZG&wXW{|c+BdQ4)G9_{YGA@A* zaf}o^hQFJCFtzt&*ua~%3NylCjLtqWTfmA-@zw;@*?d&RE3O8G&d;AVC|rZrU}jx# zC-9SF`9;CbQ(?07o8Q9E12vi)EP@tOIYKEKnO@-o!ggkC)^#L-c40iZtb4Y-cS>$I zTn~+>rn*Ts>*y*z^b3-fAlne+M-*%ecrI^rmKAVv23cB`aWD?JDJ5NIafRvRr*~~C z)99Afs`BPK!5BFT)b_^8GyH*{22}yDq;be`GnPl=vW+ITnaqzl(uYOHhXi}S!P+QZ z4SwfEPuu&z4t#?6Zaw}bvN{;|80DfxCTuOdz-}iY%AO}SBj1nx1(*F%3A-zdxU0aj z`zzw9-l?C(2H7rtBA*_)*rea>G?SnBgv#L)17oe57KFyDgzE36&tlDunHKKW$?}ta ztJc>6h<^^#x1@iTYrc}__pe0yf1OnQmoTjWaCG`#Cbdb?g5kXaXd-7;tfx?>Y-gI| zt7_K}yT5WM-2?bD-}ym*?~sZ{FgkQ9tXFSF zls=QGy?fZ=+(@M>P3Y>@O{f44yU^fP>zNzIQ0(&O$JCd_!p?2;} zI6E1j@`DxzgJvqcE@zgapQ?tophO14`=14DUZ*#@%rRi``pi0lkNgidSsHGjXK8gO{drQoNqR&tRjM4>^DtW`)fiRFO4LE=Z+nCBS~|B3gZsh`Y?-$g z@8@Z$D7C!L9l=SWoE;(+*YirPLWvBd$5Ztn3J3EaGM+#pW#@{3%yksGqy(2Bt5PVE zf*fICtPp77%}5j#0G8<=v=)LR>-a3dxja8cy3m$=MZ2#$8mbLvxE%NptMd+L?mG`v zF1cANFv17DqP^P5)AYHDQWHk*s~HFq6OaJ3h#BUqUOMkh)~!(ptZ2WP!_$TBV}!@>Ta#eQS_{ffgpfiRbyw1f)X4S z_iU`lNuTy86;%!sF3yh?$5zjW4F?6E9Ts-TnA zDyx5p1h$Z3IsHv7b*Q{5(bkPc{f`2Wfxg*Z#IvQ;W_q9|GqXGj<@abo)FyPtzI~i25&o zC!cJR%0!}lLf^L2eAfZg7Z69wp{J?D6UhXr%vvAn?%)7Ngct4Hrs@LZqD9qFHYAWy z4l=2LI?ER&$He2n`RiG&nsfLv?8$Cl)&d8a-~-N`I|&EPa@Y=v@>0Gl?jlt>AUY;H z`**5bpS#VGhdp4pKbf3iEF*>-eXg_$bqt5Dc%q0+)R50>zd^l7sN5R5Z)Ut+oz-8_ zJ`Z9HE9(=wRTD)T=%GZTEi9K5naPzlfE$|3GYGLRCLsnqLi8Sc6y&iskqA&Z$#7Ng z7Q@C0)6k;J$TlQ+VKZ5)-Ff_BNoIMm+~!@Cv1yAUI-U!R)LHc@+nSUzo$GlRb+8W< zYPG%NFfr;!(RlnvBbN~~EpT6Xj5*^Z&73tdIQ$LZu`vkfzdTKa5|JJtQ_rm4g$9LO zKtgYVdW=b<2WGM3I_j|Rd8gZ3j;)S#AT(aP^d>9wrtQS_+K>pZDX^?mN!Z>f^jP@1 zlJ;i79_MgOAJa`%S9EdVn>ip{d!k6c5%zizdIoB9Nr!n`*X#%6xP1?vHKc6*6+vKx zmEt|f^02)S_u_wlW_<`7uLQU%{wdH0iojOf_=}2=(krE<*!~kn%==#0Zz`?8v@4gP zPB=-O-W=OO3tD19%eX>PZj3YfrCt0sEjgTd#b$buAgBri#)wW14x7QcHf2Cneuizz z368r7`zpf`YltXY9|2V{stf8VCHgKXVGjv$m!hdDf0gi`(Q!(Pyg~FO28Vr#!BYP| zI)qG2?Ho=1Us9dTml}-ZOR?g5Vk)f+r=dbCN*N1=qNfG>UCLeA8pd3Ub-pRx1b3FA zEn`CIMf`2Mt3>>#3RkE19o}aMzi^C`+Z>8iIPHSdTdmjCdJBtNmd9o0^LrJc9|U9c zD~=FUnSyghk7jScMWT|SHkP(&DK$Z=n&lGm+FDTpGxfoIyKV)H6^nY~INQ#=OtIT! zyB*J=(#oHf=S)MNOncW->!c0r0H#=2QzobO&f@x&Y8sYi-)Ld;83zO$9@nPPhD}yt z{P`*fT@Z(?YAmF{1)C;o?G@dfd2$c+=Av*|;P@Yz1KnclB-Z-fJQ-=+T*g>0B7!g# zQH{dHt_%wj=wlmT&m59)TQ~xK)gB6f^EY$=1zcbGf~Q>p_PzDCHR6lndGmqPY2)&w z$Th^K%1v@KeY-5DpLr4zeJcHqB`HqX0A$e)AIm(Y(hNQk5uqovcuch0v=`DU5YC3y z-5i&?5@i$icVgS3@YrU<+aBw+WUaTr5Ya9$)S>!<@Q?5PsQIz560=q4wGE3Ycs*vK z8@ys>cpbG8Ff74#oVzfy)S@LK27V5-0h|;_~=j1TTZ9_1LrbBUHb?)F4fc)&F7hX1v160!vJc!aRI>vp*bYK=CB(Qbtw7 zDr2O^J%%#zHa7M5hGBh#8(2IBAk}zdhAk$`=QYe^0P6Bb+j5X)Grmi$ z6YH?*kx9hX>KCI04iaM_wzSVD+%EWS)@DR&nWsSBc2VIZ>C(jX((ZiV0=cp}rtTO&|GMvbmE4FpBF5Rd z6ZG=>X&>N3?ZN2^11pXEP4L?XUo`qrwxgQm4X~RCttXmZAhnhu4KDK=VkKq?@@Q_Z za`*xyHrsAEsR zV(7)2+|h)%EHHLD3>Qg{>G|ns_%5g5aSzA#z91R zMDKNuIt@|t?PkPsjCxUy&fu^At*yUYdBV!R_KOyVb?DO&z$GLJh9~b|3ELsysL7U6 zp24`RH+;%C(!bWHtX&*bF!l-jEXsR_|K~XL+9c+$`<11IzZ4>se?JZh1Ds60y#7sW zoh+O!Tuqd}w)1VxzL>W?;A=$xf1Os={m;|NbvBxm+JC@H^Fj$J=?t2XqL|2KWl$3+ zz$K+#_-KW(t)MEg6zBSF8XqU$IUhHj+&VwsZqd7) ztjz$#CZrccfmFdi_1$#&wl~A*RisBaBy~)w|txu1QrvR1?)2mb&m2N$C(5MS%hSX)VJnb@ZGXB5^%(<#1L@ zL^>fBd+dEe`&hxXM<0A9tviIs^BDkByJdc~mtTYr!%F7Q1XnK2$%h$Ob30*hSP$Bt zDd#w{2Z%x^Wpv8!)hm>6u01mY!xmPgwZ#Q0148)SxJc3Udt!-&}eRO^LN ze26pQB!Jhg&Z>#FD>`C`sU44><=v>O>tJdLs!HPpV#AM32^J@Za-9J(CQjKxpzXao zQfRkWP%g9P8XV21MmoHfx{DICLSc*t4qVeQL9t}&Pz0rM}YTba@XsD=XMW@FxFM{QYQJHvM(JsUSa3mcTUl9^qcVA zBveO--fqw%{#QGR1vy;x88+qMcgzmcYc#8U`CPPt6bl?uj%w_`b~9JliftnOa|ziW z|6(q&STs_*0{KNa(Z79@{`X&JY1^+;Xa69b|Dd7D&H!hVf6&hh4NZ5v0pt&DEsMpo zMr0ak4U%PP5+e(ja@sKj)2IONU+B`cVR&53WbXAm5=K>~>@0Qh7kK*=iU^KaC~-ir zYFQA7@!SSrZyYEp95i%GCj*1WgtDId*icG=rKu~O#ZtEB2^+&4+s_Tv1;2OIjh~pG zcfHczxNp>;OeocnVoL-HyKU!i!v0vWF_jJs&O1zm%4%40S7_FVNX1;R4h^c1u9V@f z`YzP6l>w>%a#*jk(Y82xQ@`@L(*zD&H>NY`iH(iyEU5R$qwTKC5jm4>BikQGHp^)u z-RQ`UCa70hJaYQeA=HtU1;fyxkcB2oY&q&->r-G9pis)t$`508$?eDDueFdW=n5hJ z08lH$dKN$y#OEE@k{#|<%GYY=_c~fHfC@pD54KSP9{Ek@T47ez$;m$}iwR}3?)hbkwS$@p2iVH0IM$lB*XYA+#}-re|UNzCE)SOYwy z=Y!fkG4&I%3J(_H#UsV#SjHulRIVcpJ`utDTY{k&6?#fzt~@Om=L(vs6cxAJxkIWI z@H7)f2h%9!jl@C!lm+X4uu;TT6o0pd7 zteFQ(ND@djf#o2kTkjcgT=dHs7ukmP0&l8{f;o3JuHGd2Op*?p7?Ct=jA*tIg{MZk z$2Lsc0e8Tdcwrjx|_Ok?9uB3Il|^2FF%X#ck}WoIvrzQXN%kT$9NI{79Wm~gZ3`8I+O`)`n30feZ( zDO-fl6IG3c^8S;Y_M-)+^CmM0tT^g0?H#>H8!oC8W%oU!~3|DJ?)~LT9*&GAQG13zOGq6gs*={cu|(V7{R$y@{-iV*9q@AD(#Ktb}J&3&k|5Djs$)9WM7!6#EaJ_ilvbfUvyh8c?-{n zfuFrC0u6}UJZ7aj@(cNG_(CKgjQQTA-UK@-MVmick zot}6F%@jhq(*}!rVFp5d6?dg|G}M*moyLriI!PQDI;E1L1eOa6>F9E6&mdLD>^0jJ z09l?1PptuV65gm=)VYiv<5?*<+MH~*G|$~9Z3XEy@B1-M(}o&*Fr9Sv6NYAP#`h{p zbwbUE3xeJ;vD}QMqECN)!yvDHRwb7c1s6IRmW!094`?Fm!l~45w)0X`Hg+6Y0-xf# zSMemBdE)Q=e^58HR{kWrL5-H0X6pDu%o{0=#!KxGp0A;6{N5kI+EoY_eTE%2q|rwm zekNeLY-R?htk!YP2|@dbd8TWG4#G)=bXlE{^ZTb^Q$}Er zz)Fp)ul24tBtQFIegdI37`K$VR3tVdi<(fIsu{#QMx=$&CK9M8oN%3Mk;>ZPd-;Q- zn|sSKSnc-S0yrw#TlA$+p{J~u=u98s>IoL@cNLOxH=+1m?;t1bR$vR=M$US&Z8DO3 z_&zhQuId1$wVNsS=X?&s(ecIi#00o{kuPs6kpYkL$jMyGW8U7mlCVaZeEL=HsIxqm zFRLxWin8B>!Dc#9Z#t0RNQiR-@5J+=;tC7|1D*~rxcwHa5iIVD@99cCFE@BukUC-S z^iJdt?dwU)kH2VY9?|zVShMbZctzFRz5Q4tiXa^>@U%jDYq}$rSyc#p2wXr}mc0qq z^lT>$y)N(Qg0dwmEwTopneoU(y)>Mj+f{iHM0o|>ZtCg-itPj4addYz??aE)Rp&hk z_SI)%XeSf=SjZq18h!Cc>Xy&EynnxdHQ){(x@g|ZA%`3LU^KzX02c5N;F#tEk1)7v z(|V9tO3>?^X|kQ*rRBf4>mWW2$-Lx})|M7z125&VHcxsCqB!<$l1F$zCrJ+nm0f3Z z%Hq^=SKpHyV2@Y*Cu2x>fXC0SscnR*($zEB{KOniJcpn@e`PMH*_Q6*0Z^8RNCEvZ z+UU9!927p9YZ&g=bnUvQUZcdisyn;-4;ACXOe-Xor9K8Qbp{ldE17+G@VQT+9ZJQ*9dZoXfU2ue|mMhrrZk2R7&~YjFW4`BTq45UwVc6JORKU)wBCTanITh0GD}s$`C5pb(9{b9 znwee6j%?-UV)_7opOioCf5@C?@w^@g& z&68+oMmV;5JW@TT63&CSDrfYL2$L)pVseDtAwPwleEM3F^-Ufn3PpfxFmx6o zQ`Wq9x#d$e`VKn5LOXNsrqhGao7~|s(u~drPrZ+;aP!C%z4NskZstCbAibD}O%8Ij zb~C(taxco~WzJLxhL1T}3ctXMbV6}_z=IZN9L0|SxLSe`$X`<)BhM`$1&&)e_}fCh z=idVL<+u6Vn{&ksP*ZLlMo$fC`dtzF_?~L?4Rril2G4%v5^7sUa^&8aMtMX&mtapl zD(dW|cisM3fqMaB`8?QbkyiUl2g>hMB5EoS&IB8TdoC~)b$nT=`%GgU`k-)+8}`)F*~I~DXMaTP%kZftx11~?iALs5J+&Rom#p%Y z>dH}-euH4u=_V3hc6^*2WMtL!9%yRTJ93p}@aV0zdY*?xchFI>m+UivV=;aMFp0P~ zwB8P)wvV6D-GL?6hJ#g7Hy7=2i^&Od#S=j!;Rc_yjO!*4aN7{vqzg2t-R|Dav%_NDk z`H_FVlSi==(~f-#65VmQ{EE92x<03lwo5p)s=ZJ^L7PlS>132Whr zR6v~t(#I+(`usYLCoO;Rt8j&b^5g_xgs*98Gp|N}b>-`HtVm)MscD)71y?(K6DRCZV26RsHPHKk)EKKZA%C99t3$t^B0-k5@?E>A-YMbFe?>ms?J?_guHHNU(;id*>xH zTrtam+Aq?n@-y@uY@A?hy?1qX^eLu_RaH4Ave?A8NapgQF=C%XI7wlcCf4<6BRo_% zBXxxc*A6-3CruF?3i8HOdbc%>N=-iiOF+9HX|ht6SCkz;A^am&qi_I&qk1B(x<=(m z>QG)nswCOLl_1{SZ@_eE#m^qb6#6DoMsB*)`17ui+XvF%(}|J4G$z2G*;E!1ERnAH z@q%=#uV6kBddqy4=g>!VTV)9*1=i{wJ}Ep!I*?)uJdA(LwE?(!?;}_u=^M2NShWC_ z*7l4aBJ=!QVU2-iehgb`$vOI8zkm{W%QO~?xOD;NgI;Iqa3#^$^U5D&McReLe&qs# zR<^@QpR4#W~Laz+QBsPt@3L#KF`Yr8}jgHe;5(cfpQ=;Zjtbt;c%y^#-m=hqOT z;KAYakW+$w0&F}>K10&SiPcD9SrDOuczj@U#W})5jGU-_htU`U6Q%wdy((%?J}y+$ z=$4jw1N nJo)qTxG{D(`3*#8tY|67hJRF;)r6F|#I`Ar6I0aafRa=kr-Z0I^}9xf^u;G5iEQCbpv3b#S#%H|HYHsQaHK$! zU#3Fpz8*^pK%RRmX<_09eIVziB0jOgPgFnI-*QcwEBtBiO#v!>{W1cLNXyw3D9M|A z*oGy(u8BkDA1c;MsXmpK^-~pl=We^RYnhZ4bz*)Q)C2G+E3tgx9PzU0T>c|1ilS!T zyE=bz`=wskDiOi!@!l?Y))#%{FM`}7r~X)i1)1*c6_2Q!_1{)fp%cS|YF+Q-CB%d< z=zYus`Vt@Mx*a7V)=mpLS$-5viaKgNB=+zN657qy0qR94!cTtX-Z%KBCg4OKw7b=t zr=`7q5Ox=lJ%!G5WIyNQC1xpqYU0{!I$hyrk!6%De$gp<_*Gc?ES(OwY8U^)Kjgc{ zSlhpXDb|;{+y9`u{EuMz54rlky2~p6xX2>MV6BZ&k`$q%q7v(xYps2wr9e8^4<;CB zc)eAT~B^rjzO6<4BDDH;il6 zFsM8jL+agQ;zazW(uiQjM%fPf2N~_p{cy29XP11_lQFpt`t#9nlk}>fv((FZt-dBa zuMIc4HmPHW04n0TTG9ug9;&OV9euL$Ib|+M7}}L~z4e%%%b|r~6OQj(S2d7XfYn#xp8;KQ55UYu#gY*De5j6Cc z#R%?rqwpy7I1(kpU7B*Pq=etXeYUn04jg%ZPjYqQNa$==yTG=6KX+=;i2Xg+kjV2T*Gc!(ef z`Q4fR*TA=M5-}z+s%YO+!K{k}S**ic&>o4_Tmv$EQTOp7F6TXPCj-UTXy?OQ=%*y62Qajk{rXbR%jMCOFMiVE3KekQa4xR}B%=iPtd8BXo~q$OX_ zSp910{Ew;m|GATsq_XiJ3w@s(jrj^NDtr(Dp!`Ve!Oq?|EJ9=vY2>IfrV{rT%(jiY zi}W@jA2iqd=?q>s;3%?@oi7~Ndo3Ge-2!zX58j(w&zVlPuXm3rcHb7O0RsM|!Ys(b zh(=*&Aywo3vuJoWZnU!u2_4bNkDTc&&bCYc%T zM~~xYxS#3KXFzQ@OXdc%9QDOxqiTd_> zT;(DX9{5dIuC4pO_xy+3{Ov)1I7j!Z)6&nHUvTRP>VU5dm#849icG)cvl0QOPkCIzG^lOp4#UcNr`VhBp(Ha%8@KPlvT*5u!v_$b#b~%sn3K{mu zaxeD%Q~{;Lw03ZAq(Pc-IVj>n*h3l2{sqioCMGatQY0kx zi`1(WWDQ=;gmLSGptEQ%UFC)th@|71<8eiRtX&Mx@#1q#nMF_BMfQdS>!!Qkx2o}= zuqRi?`UOX5P3fP%M+71Q$ctH4Av}bXED#fQ`KR4!b~60nsAv^*M7c-x`|~B}XIuq% zlqIJOf>WvlhQ@Uw$du|14)tZ?; zPNZ|xZSwp1y+d4sut8E4*l2JWR|~o0A9vD-?zC-w zDc@=wE1YKb*OMSi_Kx}&w;#h3>sHp|8^hnA3w?-WK)X?@Z2dgV7`9Cupf-B2RE4x^ zwlw+~!V9C^tyb`J;m2}ksD`w}G9`yu(^--{SQ+wt^Fu4Li~Fft!3QO`upSkAU?o;# z(1Q%GUVWbbkTK-M=T+ULkk3s6Dc9`G4CO6|=&-S&D+rbJQ$`Y-xL~ol;kc(l)VbU>{&>bV+*?ua;$bnDc29RW+Ig16)Vf6=L|fMR_P2b7>6}0 zdlB#-gj|j*C~M=F^2=K*k~=tl6YM3SXXi&K-`EvEXnWz&4D-^hQRBJI3gKKDj^6|> z*WhHSim1qAffNt60Mve9lfw^+&0bx-AM0%j>QP3%W=S@(l=(nrJ678mRQ(#+sI@d{ zdb#5fo#T;hK7xJ=M58wZf|?DHwD%!OZ3JrTGV5#{cfQwuiMvz%!CQ}CubJ7`z?@rSF<+KHNV2goc)a6hP0oHB@3LLKSH2w{um&J*z1Ka2 zLIR>lvOvh>Oxe%?3A@v<_T|}${zf_&@C~^FCo#jB(W9VLO?DX{)n(BQ0(V0`mI|9Y z#U3WwxixJkU_NTvA>5q(A@r2dnEXJp#6B=pww$XGU}~1~c``UKqQb=^*2P|4Dq*_! zhY^i61Sy%T5$Td0O6^C>h(xVvT!}Y##WeT8+s+Uuz=7)~V$>!zU;%d>H)rm*6^IrsCma%|cifwDLk_ z!^W2voQ)D;I$=v2E>iSaBw!d7aD+|LWl2iD!cBw`Q5p1~fk_xGiPi8e^mY&#viTAk zmaKL8m;JQ4bY(n6uBZt02z#noMMxTfF-RzjKre-c+@B)#J3pN-Zv7F}JtAwNk3j?OkpVCL6W1)Q$FLAj zGI!tX;g`O{%pt=0|q54Jyj##w*4e*|_;Us2Tn?!#^R(>u}|FAw1G_ z#wQsagnj9$TAC`2B_XgB$wNq~Sxgl?#0+QWWcB{G`c6~&SosbtRt}Tukw`TQ!oG1= zYyL(y<;Wh+H24>=E}Gs=Hs2%fg;&Qdvr74{E!R?Bd zIRQ?{{xkLJ_44P@y3^#(Be%(pk%$liKbUUo76wSoVfJmt9iTKL3z{uW6L&?jYg>EY zsx{kRiW@q%<$VZvbS(TKKTO4{Ad6l^IeY(F^3}=mX9|FZmQ`~RErNxlBPl3ast}W$T4V?SW=6kIGn@-^`qJv| zZXwhK4Kl1a4E}nLI`rdOi?^pd6;LZ-|8G&INHgOeC5q{_#s+SXb0r(;5ryHFsoTJD zx$VtNDh=-Tx3t!NTlk=hgAaSM)#U}e>_-Ex(|JoX*hWmBPPdTIa-2(BIOUJ|Iddy| zwY*J%z%W$}*;uSoB!BIJB6N6UhQUIQE_yz_qzI>J^KBi}BY>=s6i!&Tc@qiz!=i?7 zxiX$U`wY+pL|g$eMs`>($`tgd_(wYg79#sL4Fo+aAXig?OQz2#X0Qak(8U8^&8==C z#-0^IygzQfJG4SWwS5vko2aaOJn*kM+f1-)aG{T43VJAgxdP(fJ4&U{XR90*#a)G8+clOwdF?hJ?D) zmxu>0>M|g_QRHe_7G|q6o`C>9x4xd$Gl7lAuR~+FtNid=%DRsnf}YI*yOToWO%xnP zY*1G5yDnTGv{{xg5FhWU65q3-|-(+-rJ2WCeSJn(7Az>ej4Jp9+l-GyZ_| zJ8}>iA4g|}q1AhEEv#uWR&$g&Uyht?fVU(qk(j?^D`))s>oG08pow!f>P1u71P%oL2)UC4GeS87&G?{)NE;D=my1Q9{~;y zJULE=bG6jXE28Y11YmoZoo945`MM*`v%5b=_02*0cwzDve#3(4M}NPt`)?SCa|7*q z-94ks(R6WH-l9fE4m4}10WSu&O`|;ZCIT%vL$_pbABY!}s33@~gIvZ0H4co|=_-T$ zF#lC7r`89_+RL9wYN=E3YwR?2{$^ki(KKd>smX(Wh*^VmQh|Ob5$n_%N{!{9xP~LJO0^=V?BK8AbCEFBhDd$^yih$>U z(o{RReCU{#zHSEavFNdc8Yt<%N9pd1flD{ZVSWQu*ea1t#$J5f6*6;tCx=&;EIN^S}*3s%=M#)`~=nz!&Q0&{EP|9nzWyS<#!QxP;!E8&3D}?QKh^ zqGum|+;xu9QE=F#fe2ws5+y1Igr&l`fLyLKry=1}(W+2W`waeOR`ZXlW1B{|;4sE3 zn^ZVlR11hiV~p<~TaSen8I~ay#7Ql=-_|U@$8yjZsZ=Vi+^`JV2+kn+oiSUi%omO_+7}saXnJ9 z5ETilbag(g#jZPopCgJu+n@(i7g}3EK2@N zd64$77H5a`i%b%a^iRjMaprwzWz(`=7E6QY)o)gek7H)yZ-BLw^6FAoHwTj9nJtWc ztKaytMlWGLg29W{?gr|rx&snb@XyvR_}x3fmC>d=-nQp5ab3*whTw}DfUcKlMDDx` z-%?ek^*|Kqooy#>2lfklZ|jN4X$&n6f)RNNPl(+0S>t(8xSeOGj~X0CGRrWmm(WXT z))DDW_t&y$D#2`9<-+JT0x1==26*gpWPV~IF=rePVF%e-I&y$@5eo~A+>yZ&z6&7> z*INESfBHGNegTWga&d@;n;FSCGyW?}e_Qw#GTLHo*fWxuuG@I~5VA!A1pOdRTiPA~ z^AGe(yo=9bwLJD}@oDf$d+34~=(vIuPtOKiP}obDc|?@hY}J*@V|UynBeAkYa?S{@ z_f$U=K+>deTAi&=a*xv>Ruyw$UsTWY=Yn=xjf;s)6NQu>_niQ_idmzIwuL`Scf)f= zyzK?D5a5)^D@H&qN%F6Zd0JeXX*Knbe~VLe^gi|?JK67&mB4jrapV-$`hCQT;C{%T z*pjxB+Y|~LD9bmMN%Iq}S$F$x1yWU7@GcR91V8h;!O2I5MN_rq*gRx(k8T!1WSDTp zr9eJO4$~H94aG^6k5p8k=kFJ>4lnY0q_Bsa$@vTRW6uY?slH|Qt)Yu6Yun&pfJ zBi!h;6x?FDs&79#PT*HSCEUsKws#s%TFy*=2PAfb`>gEPBn+D-WdfXA?MkB=<8kb_ z1+4D11mdHG0EcAyg4dneLtfJ8)RyHQl@6hWJNe(d_EjyCHf7%Xsd)S4A-4COz{G@% z5xQ!P>AS@H@;4Ws)N91)3A6PleMe2<& z!(zv#%Uc?N`(Xmm)OJPYt)BM`nRjoWA&P0Yxl@c9Y02zlPH1J5l$nhPrMwu=atkz4 z)a-1+OEL;d@ctx=s<<+3Sv1VYy0RYmiji|#hy$66#`5;u~BkH4^$EGZ-Y4xyZ=%3KuaeLYKAUr$xMtIh_5mga> zPz<#G0mQ7IxEw-yO}BueN}RaFlg$RwCDB)vLF$wDu%qZyLYsPKdcbHD23$qn9i#JFqIo#OK?u7db2-$GatzO!On87%}Br};~#}n zziVB;qf_4(K$u>Qyz$ln_kBGS!CD-t4Y}9oxL@7@Sx*?NOAzdeINUD>Hl#*V%pfA; zSA`==YatS*G*crJ3`3ll4)vKss&)UtY#7ZxiVoG%9(4<%`WWcjX2jV(^g7Yhj+h5J z$5=?S=tuCyEt74^6jo@6y|@~N>&cVfFNtaRl=)Gm!vR;Bc$3-;ySCI$%kdmjQ|si` z{$q_YCe6vjy6re9jGN|`43D``)1PODtz0)vhV4XV36nVpOnMx2uM%qZ<3TtcI%>BQ zf0(J`{JqPPJxw>k#&nIvoZ5e9Sno)B2r+E0G} z@&M|zf4E0Q$O*NBR2I;?i7N} z@2^Su#`%qeX}m3cbSojiLk#84kvW1fICNPS`OyT0SpUoA0(s^2m~J<^eKE!dhJx_N zG_T}0&(<*an>oF=@?6?55g&IxSgY3?7|@pmDRE6gJyJNPH6un~%0hZ@?h=hI6O$b^ z)29#<4$E)cE-5IFbRpk9JVrw$$966UDyw;Iym4OY4Fc!&s1ZH4BJ1-$9<)Zt1c)N- zU^&9hsk6z?3%<9kGKHW|6~k;&cghtWz`oz`_YjVuvy;B;T67=L2c6=8`7WyTBv*QH zNv*bo1#KOk{O&)@&pkd*?v+kcJ8tM>AGx$~WMhH{L40_N=bkrVg+^p!H)IqXCQf2_ z0fPig=8CEo>p4vE(nc^DKbZ|9_Xo}$i4zJ`jVh95; z5%aNP3@``=EJ=Vt9U`y+$YtX;%OPzgZ_3+;+mh{p#W&y4-%%Bf`LhOy-*kB0qnB^m z_nBTz_b?-`F$*ymByshU>D)za2g`0j^ioo;A#QeL@x3@|+_!=YXA5f6Xg(Ack&WOg zJ<2i|Fd6OmyH!@YSMVxb;=M)ZDhBt)4`5T*>cUXWPG#%@$&*>K&u3#|`fm2mj*FKVf?du{xZ}WKWETTFhq6_fO$PS5(ItF=3~pFp~*j z!ys1<4EL1)#{`mz@gW|t-FpPkd%pK)n_Rb)F;z7cQ6dym_>YI3&e!=!m006oS3Mjq{q ze%hNzW=G0jpfl2K(x`CDuZCsJV*hm9T~%5n7R_g}VFpk`G((D^MWVMAmRp--T{`P; zwMgD<;e`fm`g3|fPns|6qnd{|FCHY*YAguXH(?%sx%4+Gu|Y)_8mk4EljxmP+MP`* z`SUbI{TCIN2OV+$y#g->Jqv#$wL;}4xJmah#$0`v^ughM_XjTA$B}ux)JZuY5-GW4 zKy440I+w=ZtE-_i+0xImq}vyzD68?8;94-5L~_O6Ty>X3itdA-x?6P(c4jkr+f!H( zUDeqiG>3bn^Sf8(`_YwqPeJ9&-@OCQZm4X{FfRMeBtN4E9Ca@;GVpU*L>lVb;@=PH zTQvTr?^jKyCKh&ZVOI*<y%T*Aw(XCPrFC=39*y$A`FSzxBiQ#W+uW10d8&gYp4{teh;^p@anft+z$5!Hv&@h0X-@xJG>hbTCxjDwMiWK@1b%8wYL6BrV zT41m}tX8g-`P@vj4T!Mlk8F0S!MA`^J=SCy9-jdwDe^hVDa`WwyI^H@ryt=F5y6>b zT8&iI6&j8edAfX^ycgWbnMZQ26Q~`LmdEScKC8|~$Jgyw(>18NAQ$9AwCRmri!96L zp^)b0P2CR-9S%cG$#rU}MXnx21T#031o>2VrDs@sa-FpjfvgLPW>Q&LHUoNOtmkt# zoDZ=5OGp{^vO~=p29^`aXd8K?(+f-bW`N$U;-o;%f?RcR!k02Nod2h^^8ly%Z67#E zC3|IOuj~^YBO=Fklo@3mvd6I{Z*&FZ>iq* zxh|JuJoo2$p8MJ3zO@dQ;%1#~Mrm48 zB0053{1bDi_a@jo<4!@!`w4}B(&Qb`~IeSBh zu+_yIYl2Wgk+?x4pCmAM>x_SqBPUj#c`C`k>_fp@qPlAAwD$!zOxRkL7;=|nu(#ut zyF^;&hm-D_;ji{d6rOloACu5*NkF4IC3@rifMG(|^Skv$H&^YnYL*rpw=UCi;JOuz zN*NX(7wZXS4tF@6PIWAs%*j!$RoL*3sh)}iry%thDvN5AUM888q_(>|Tzt|Yea3AyMYBgm$H_`F^v2%)bux)3s znFIEBDK;-JS5SH|;1?afJb<*=c5puu=w%tv#ihn*R!^Hd$KWAp4$#`joJ*)$kNtZ z2Al6h>Z>(u?3tmzA4^d+jLKx{97!Pb4;CX&u;M||**7zXI7hO6nrdMx*Xa=|-`#1^ zBQ?Ha&7cd7hN=%y4yUp?zl8~Lo;%mQrDe8!ce-W_K94FFMN*g(w8q-_K5S+c0{o29X&PzpV;UJE^!xnFc%b@>kvW4m#xiOj-L*DadC&2N#0Us z;<-(m1WB7$=j6hjcPC6JB)D3T2#IC`ibu#yi!uK7W2!j|Z>~RaJ*&XXy#ytIk2DIp z5?Qd^s90_?ILjU#>ZWk5HXts}grg_!Gmgm!d?eLGR7xEP zvTCrslV~94ym5_i<5oqy(@@?wN}lIdtiY8=?|Ng!XeYnly`@9wCGx2S$3x|0x8T2h zz7A85Vb2>s44rKpI_4Y7_Pnd2^mYj2%^jM|Du>u4`^Psda^JIP%*DK6bo`Vf&f{!% zDTYCwF5Nhi=)QhU2$@eQv&ZzxsX+Hl+gP6kW|e!n9IU2>Vh~cioI{>4WvR}t*4Hpz z%5z?HjLGoka}Q3AbX9AkY|Yjf^M(>@tBAI9JO5pDCQu0R3Nns>)LC#vB2p96C*?K? zvX$un$sBDx$1=+NNj*@Oa@u*b@O*XBr_sg@8sCUq-|LK!MUmC)epklrv}5O_^<{NP zX16|c$9Wtbks3y7geI^tF5oRZJu;v zwkW8j+8Ccxo9stEDOT_Go&j%$KCgVO7pm+^%PKEPBZqbMw%s@732XS{cX+wCSjH1s z5)bc=g**<^NNsroY` z?}fHHlgu^B?2r{^^gQ&j zbF~T((>|Yg&C5WKL8DCnl1}Z3!YHFW2S1|;Xr0`Uz-;=FxEwYc4QpeAtnm7^f~uzX zl;xA!?>MLR?tL80Iudm;mi{!ewL91KhG7Hsa-XepKi<2mc6%zf0GwtbfJ1Zf-<@Xu z#|XWDzv|04t)&9Id!UxAAkN{t5qC%%8-WV3i;3duS19%m2||Y{!3pR1=g|zQYAMqc zff)_2nj-O4wfxy;UNM?|Uieo!^J$A*uDe>@V(NKH;KS;Y_dtE8${p>RdcrW;=2*fj4~d?OG0l-(g?ik}vz} z)5-wDppVts>K-=|@{=!53?=8)Jw#RGpS_FWpbwtn}{v!JEJ$q-sr7F6&OPBuI# zuVNFMPte79XgEu!P&qRq8u4J>r%$l-IQ00Lin90(_KtC)aR_de zxN=pY2<1b29_^AG2WJIGmmX4rv3$!`l15{e(H!1^+x9voZ6;882YAE12q7+lgy+>) zj|s0CyzI9=Mo!R}&LXB`&DYpZ7c?0r(&KNV+~TULd0y^e;G{KVR4nL0KvU9mr8&$^ zxrM-9P8zE`J?aZ(iB~Rz<{vvnk2HaZU#K$aVFfYnbAXVUOLU#As5JvS%+26 zi$sNuPY}dLGUS$0g&;oBqhzv2dY`l3@6Na403M!Sh${B|7(y|_cONa;6BrtUe@ZzV z7SThtHT8k?Rwc)(Z}@BP#H@JJHz&GR&M=E@P9KJ89yQKmRh&I~%vbL1L-K3E>7>CH z)Y!=jXVb1iPrAoAZZ3}3wU*5~nrV!ZjL5zqJ<@NwjHCZC>68Cc<{&E_#S;E*jOdjtg?uKN|l`P8sjz&Qf7a^z9 z;{3-8T+H4y99_zc;JYIvs!sk$G}` z??mt*Mm9Z@glCZb!X?!xXD-21sFDPEpZOK{sbQseQ$%6~b;n+*z0hRoR}0Pe>B|#t z$XrVcXv8M|q*Z8MY&r9J0A=d^1bHpjrUXu)qEj~$%%=gZp`^~%O*lzxUquG^p6;n; z^(3HL+hx4gRP?4N*b2p9!^|2~rcw3!9nQj$vmZusbXYz_x^AVc`3qBFm(jS9ueU5h z^AnNnbswfQ2Jq=W=T+p-V|nQco@bOAH$pLQZ+BKH8E$iM>IDz z3|wc?QP`yI=X5YTlp8h}%p6{Deq?S0QD$Ug>ih1SdPZg237Rl{S~=Ha4~-ckMoIWMn+X@@`V6 z#HHZj>MQbt$Qqp*9T(cjc^lxZ7UO(>PwzF-qEr(wo`vaulxdall|KP`7p4gd`23&Jy=#sAes*0diLB(U$Nx46VQvP)8idSs8^zaV91xw*O-JMH=)FoJshRob|_)O)ojtfP))WHCr(;*2;VMQ75^ zfN@a^f#o<|*9X;3IcGodLUz-3i~FAu+zI4c5h+nW^h_!^)b*B_xw-l4O$TB(ixaqW ziMoa%i=BeS<-F45kMO;Tw|FWa`G2c!SuOA3CbowPhF6csf1|&qqugUrj;UgGHm| z;j^yoH?MZhR;AYOW_XW2Lg2j%%ejL)B@*bUMD`g<#Z${1+fa57r7X82 zcqY-cfPnK%Y^3@szRner zt)bBToYCph6Jv*W+&t?&9FG4(Iu2w46 z4B#AcFy_^J@f*6<{>CN}Sj969*DYV*e7<61U>GoN{tz!Do90+jApFueVY_IW(MQF; zl?4yA_(MvMwN&pWKVyg{3uU_+y6RMdot2vu%mC?st=N0pf-~JZXE?3JFf)j<{1xsU z`2ephz)#HzsWEP!inHm2hI(V(~@W zY7gGU-lO52cHD&SY)>QHgy$=>^X%u0TQZfCizro!*weMyvZC=;MWOawdAx~`3C*W` z%^#^$uRP;gyqEE0<(i8xcQY$oc+6mY#z{-XFxsO1(cN8Y)>p;^q9|5bk`Z*p|c!?(rErw#y;yT(%@c7trQBv6cj)$3>pI z>tz+;IB?D=aQV=s(n)o63*yn8dX1m7#Z4G{%fF@K2o5n3jxR~mU?nzMi#;}8e#(>{ zy{Z4!AI)jZ8TY;nq1aq}tq;~=zzoTv)er06oeX3;9{uP{LWR*2%9cmE%S^`~!BW>X zn3PZFTf3g*dG68~^1*q@#^Ge(_8puPEFLD8OS|0b2a{5e=N4S%;~f3tC>F6UxK#v9 z)N-#Mv8=ePCh1KsUKD1A8jF_%$MPf|_yCN9oy%*@um6D{w*2|4GY zb}gafrSC+f=b*W{)!a!fqwZ9)K>fk=i4qf!4M?0v{CMNTo2A9}mQzV=%3UT&i{3{W z>ulG#M!K7%jPf6Mjff9BMslgQq3zIogY);Cv3v;&b#;^=sh#(Bn%W)H*bHNaLwdpq z85%fUTUJJNjYO_426T2TBj0D{6t zw&S_HZ|C?pI_2q(9Fas&@uJs6nVX;P*5K#6p|#)_(8PM-{L(;2wl`ma{ZAd5gA)?y z>0GSLoK<*FwW+G8@-M3vcffg7I(qm7lzF)n`Q9iCvp*mn7=|CjlpG{x z&r0n}XLWZ!>=lynUr7D`6n`7a_ZgT< zm!i;&?Fb0Q2QmqmCHfZ7ex=_tU~(7b)L?RIvPyEAU=gLIZ-VTAA~WR00yKyTXg^(G zqWLZJs!FnQYMOH3*fN&Tn(IKMLf{Ki?pRo8zZJ6YVyj)y0^)-sR}2-)%mI(Aw2AgT zbbp1T{qB(OSNJd0cVBH^tI>HR(q+#*lmi@LWe*rZz&M2h1L_=50uZ1e*n#E*`6?aw zj`ka&JpceRGe@}Ey1)Q~O}0qHRg4K_u>4e1arvJ7Q9!=t5AuzG`n=a-f0}{+lnCE#zu$`oVn44eS&T?N*wz~t~E&oQDBrB_MSg z_yVrQehWbD0xHX|v-hpselAu;O7s;P*!uAT`dr~}Lie=tknaGoiU?;*8Cwgala-65 zosOB4mATbdXJFujzgA4?UkCKE093A1KM?W&Pw>A?IACqg1z~IZYkdP70EeCfjii(n z3k%ax?4|rY(87N&_vhsyVK1zp@uils|B%`(V4e3%sj5f|i(eIhiSg-fHK1Pb0-mS^ zeh?WA7#{hhNci5e;?n*iVy|)iJiR>|8{TN3!=VBC2dN)~^ISSW_(g<^rHr$)nVrdA z39BMa5wl5q+5F@)4b%5-> zA^-P20l_e^S2PTa&HE2wf3jf)#)2ITVXzndeuMpPo8}kphQKhegB%QO+yBpDpgkcl z1nlPp14#+^bIA7__h16pMFECzKJ3p4`;Rf$gnr%{!5#oG42AH&X8hV8061%4W91ku z`OW_hyI+uBOqYXkVC&BqoKWmv;|{O|4d#Nay<)gkxBr^^N48(VDF7Sj#H1i3>9138 zkhxAU7;M)I18&d!Yw!V9zQA0tp(G4<8U5GX{YoYCQ?p56FxcD-2FwO5fqyx@__=$L zeK6Sg3>XQv)qz1?zW-k$_j`-)tf+yRU_%fXrenc>$^70d1Q-W?T#vy;6#Y-Q-<2)+ z5iTl6MA7j9m&oBhRXTKr*$3gec z3E;zX457RGZwUvD$l&8e42Qb^cbq>zYy@ive8`2N9vk=#6+AQlZZ7qk=?(ap1q0n0 z{B9Fte-{Gi-Tvax1)M+d1}Fyg@9X~sh1m|hsDcZuYOnxriBPN;z)q3<=-yBN2iM6V A?*IS* literal 0 HcmV?d00001 diff --git a/web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.properties b/web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..462686e25d --- /dev/null +++ b/web/ASC.OAuth/authorization/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/web/ASC.OAuth/authorization/Dockerfile b/web/ASC.OAuth/authorization/Dockerfile new file mode 100644 index 0000000000..0c870f1506 --- /dev/null +++ b/web/ASC.OAuth/authorization/Dockerfile @@ -0,0 +1,10 @@ +FROM maven:3.8.3-openjdk-17 AS MAVEN_BUILD +WORKDIR /build/ +COPY . . +WORKDIR /build/authorization +RUN mvn clean package -DskipTests=true + +FROM openjdk:17 +WORKDIR /app +COPY --from=MAVEN_BUILD /build/authorization/target/authorization-0.0.1.jar /app/ +ENTRYPOINT ["java", "-jar", "authorization-0.0.1.jar"] \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/HELP.md b/web/ASC.OAuth/authorization/HELP.md new file mode 100644 index 0000000000..fceddec55a --- /dev/null +++ b/web/ASC.OAuth/authorization/HELP.md @@ -0,0 +1,30 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.2/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.2/maven-plugin/reference/html/#build-image) +* [Spring Reactive Web](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsingle/#web.reactive) +* [Spring Data R2DBC](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsingle/#data.sql.r2dbc) +* [OAuth2 Authorization Server](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsingle/#web.security.oauth2.authorization-server) +* [Spring HATEOAS](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsingle/#web.spring-hateoas) +* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/3.1.2/reference/htmlsingle/#data.sql.jpa-and-spring-data) + +### Guides +The following guides illustrate how to use some features concretely: + +* [Building a Reactive RESTful Web Service](https://spring.io/guides/gs/reactive-rest-service/) +* [Accessing data with R2DBC](https://spring.io/guides/gs/accessing-data-r2dbc/) +* [Building a Hypermedia-Driven RESTful Web Service](https://spring.io/guides/gs/rest-hateoas/) +* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) + +### Additional Links +These additional references should also help you: + +* [R2DBC Homepage](https://r2dbc.io) + +## Missing R2DBC Driver + +Make sure to include a [R2DBC Driver](https://r2dbc.io/drivers/) to connect to your database. diff --git a/web/ASC.OAuth/authorization/mvnw b/web/ASC.OAuth/authorization/mvnw new file mode 100755 index 0000000000..66df285428 --- /dev/null +++ b/web/ASC.OAuth/authorization/mvnw @@ -0,0 +1,308 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.2.0 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin ; then + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" + else + javaExecutable="$(readlink -f "\"$javaExecutable\"")" + fi + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=$(cd "$wdir/.." || exit 1; pwd) + fi + # end of workaround + done + printf '%s' "$(cd "$basedir" || exit 1; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" +else + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; + esac + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget > /dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + fi + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi +fi + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] && + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# shellcheck disable=SC2086 # safe args +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/web/ASC.OAuth/authorization/mvnw.cmd b/web/ASC.OAuth/authorization/mvnw.cmd new file mode 100644 index 0000000000..95ba6f54ac --- /dev/null +++ b/web/ASC.OAuth/authorization/mvnw.cmd @@ -0,0 +1,205 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.2.0 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/web/ASC.OAuth/authorization/pom.xml b/web/ASC.OAuth/authorization/pom.xml new file mode 100644 index 0000000000..c2be0e6787 --- /dev/null +++ b/web/ASC.OAuth/authorization/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + + com.onlyoffice + base + 0.0.1 + + + com.onlyoffice + authorization + 0.0.1 + authorization + ONLYOFFICE Docspace Authorization Server + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + ${mysql.connector.version} + + + com.h2database + h2 + ${h2.connector.version} + test + + + + + + org.springframework.boot + spring-boot-starter-cache + + + com.hazelcast + hazelcast + 5.3.1 + + + + + + + + + org.springframework.boot + spring-boot-starter-oauth2-authorization-server + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-crypto + + + org.bouncycastle + bcprov-jdk15on + 1.70 + + + + + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + + + + io.github.resilience4j + resilience4j-spring-boot3 + 2.1.0 + + + + + + + + org.apache.httpcomponents.client5 + httpclient5 + ${apache.client.version} + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/AuthorizationApplication.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/AuthorizationApplication.java new file mode 100644 index 0000000000..490777cbe9 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/AuthorizationApplication.java @@ -0,0 +1,13 @@ +package com.onlyoffice.authorization; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AuthorizationApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthorizationApplication.class, args); + } + +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/caching/AuthorizationCache.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/caching/AuthorizationCache.java new file mode 100644 index 0000000000..6ea09bb6d2 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/caching/AuthorizationCache.java @@ -0,0 +1,40 @@ +package com.onlyoffice.authorization.caching; + +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.onlyoffice.authorization.configuration.caching.authorization.CacheAuthorizationMapConfig; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class AuthorizationCache { + private final HazelcastInstance hazelcastInstance; + + public OAuth2Authorization put(String key, OAuth2Authorization authorization){ + log.debug("Adding authorization {} to the cache", key); + IMap map = hazelcastInstance + .getMap(CacheAuthorizationMapConfig.AUTHORIZATIONS); + return map.putIfAbsent(key, authorization); + } + + public OAuth2Authorization get(String key){ + log.debug("Getting authorization {} from the cache", key); + IMap map = hazelcastInstance + .getMap(CacheAuthorizationMapConfig.AUTHORIZATIONS); + return map.get(key); + } + + public void delete(String key) { + log.debug("Removing authorization {} from the map", key); + IMap map = hazelcastInstance + .getMap(CacheAuthorizationMapConfig.AUTHORIZATIONS); + map.evict(key); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java new file mode 100644 index 0000000000..056814aba4 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java @@ -0,0 +1,88 @@ +package com.onlyoffice.authorization.configuration; + +import com.onlyoffice.authorization.extensions.filters.CookieCsrfFilter; +import com.onlyoffice.authorization.extensions.filters.SimpleCORSFilter; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.util.Timeout; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; + +@Configuration +@ConfigurationProperties(prefix = "application.server") +@EnableWebSecurity +@Getter +@Setter +@RequiredArgsConstructor +public class ApplicationConfiguration { + private String url; + private String frontendUrl = "http://127.0.0.1:3005"; + private String login = "/login"; + private String logout = "/logout"; + + private int maxConnections = 100; + private int defaultPerRoute = 20; + private int connectionRequestTimeout = 3; // request's connection timeout in seconds + private int responseTimeout = 3; // timeout to get response in seconds + + @Bean + public RestTemplate restTemplate() { + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(maxConnections); + connectionManager.setDefaultMaxPerRoute(defaultPerRoute); + + RequestConfig requestConfig = RequestConfig + .custom() + .setConnectionRequestTimeout(Timeout.of(Duration.ofSeconds(connectionRequestTimeout))) + .setResponseTimeout(Timeout.of(Duration.ofSeconds(responseTimeout))) + .build(); + + HttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig).build(); + + return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient)); + } + + @Bean + SecurityFilterChain configureSecurityFilterChain(HttpSecurity http) throws Exception { + return http + .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().permitAll()) + .formLogin( + form -> form + .loginPage(this.login) + .loginProcessingUrl(this.login) + .permitAll() + ) + .logout( + logout -> logout + .logoutUrl(this.logout) + .clearAuthentication(true) + .invalidateHttpSession(true) + .deleteCookies("JSESSIONID") + ) + .csrf(c -> { + c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); + c.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()); + }) + .addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class) + .addFilterAfter(new SimpleCORSFilter(), BasicAuthenticationFilter.class) + .build(); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java new file mode 100644 index 0000000000..8356f973f4 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java @@ -0,0 +1,116 @@ +package com.onlyoffice.authorization.configuration; + +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.proc.SecurityContext; +import com.onlyoffice.authorization.extensions.filters.CookieCsrfFilter; +import com.onlyoffice.authorization.extensions.filters.SimpleCORSFilter; +import com.onlyoffice.authorization.extensions.jwks.JwksKeyPairGenerator; +import com.onlyoffice.authorization.extensions.providers.DocspaceAuthenticationProvider; +import jakarta.servlet.RequestDispatcher; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; +import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; +import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import java.security.NoSuchAlgorithmException; + +@Configuration +@RequiredArgsConstructor +public class AuthorizationServerConfiguration { + @Autowired + @Qualifier("ec") + private JwksKeyPairGenerator generator; + private final DocspaceAuthenticationProvider authenticationProvider; + private final ApplicationConfiguration applicationConfiguration; + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { + OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); + + http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) + .authorizationEndpoint(e -> { + e.consentPage("/oauth2/consent"); + e.authenticationProvider(authenticationProvider); + }); + + http.exceptionHandling(e -> e.defaultAuthenticationEntryPointFor((request, response, authException) -> { + RequestDispatcher dispatcher = request.getRequestDispatcher(applicationConfiguration.getLogin()); + dispatcher.forward(request, response); + }, new AntPathRequestMatcher(applicationConfiguration.getLogin()))); + + http.csrf(c -> { + c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); + c.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()); + }); + http.addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class); + http.addFilterAfter(new SimpleCORSFilter(), BasicAuthenticationFilter.class); + + return http.build(); + } + + @Bean + public AuthorizationServerSettings authorizationServerSettings() { + return AuthorizationServerSettings.builder() + .issuer(applicationConfiguration.getUrl()) + .build(); + } + + @Bean + public ClientSettings clientSettings() { + return ClientSettings.builder() + .requireAuthorizationConsent(true) + .requireProofKey(true) + .build(); + } + + @Bean + public JwtEncoder jwtEncoder(JWKSource jwkSource) { + return new NimbusJwtEncoder(jwkSource); + } + + @Bean + public JwtDecoder jwtDecoder(JWKSource jwkSource) { + return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource); + } + + @Bean + public JWKSource jwkSource() throws NoSuchAlgorithmException { + JWKSet jwkSet = new JWKSet(generator.generateKey()); + return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); + } + + @Bean + public OAuth2TokenCustomizer jwtCustomizer() { + return context -> context + .getJwsHeader() + .algorithm(SignatureAlgorithm.ES256); + } + @Bean + public PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/DocspaceConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/DocspaceConfiguration.java new file mode 100644 index 0000000000..d8765f19bc --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/DocspaceConfiguration.java @@ -0,0 +1,14 @@ +package com.onlyoffice.authorization.configuration; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "docspace.server") +@Getter +@Setter +public class DocspaceConfiguration { + private String url; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/RegisteredClientConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/RegisteredClientConfiguration.java new file mode 100644 index 0000000000..4fb28241f6 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/RegisteredClientConfiguration.java @@ -0,0 +1,16 @@ +package com.onlyoffice.authorization.configuration; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "registered.client") +@Getter +@Setter +public class RegisteredClientConfiguration { + private int accessTokenMinutesTTL = 60; + private int refreshTokenDaysTTL = 365; + private int authorizationCodeMinutesTTL = 1; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/CacheConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/CacheConfiguration.java new file mode 100644 index 0000000000..42a72788a3 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/CacheConfiguration.java @@ -0,0 +1,109 @@ +package com.onlyoffice.authorization.configuration.caching; + +import com.hazelcast.config.*; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.util.List; +import java.util.UUID; + +@Configuration +@Slf4j +public class CacheConfiguration { + @Bean + public HazelcastInstance hazelcastInstance(Config config) { + return Hazelcast.newHazelcastInstance(config); + } + + @Profile(value = {"prod", "production"}) + @Bean + public Config createProductionConfig( + List mapConfigs, + NetworkConfig networkConfig, + PartitionGroupConfig groupConfig + ) { + log.info("Initializing a new production hazelcast configuration"); + Config config = new Config(); + config.setClusterName("Authorization Server"); + config.setInstanceName("Authorization Server Cache - " + UUID.randomUUID()); + config.setPartitionGroupConfig(groupConfig); + config.setNetworkConfig(networkConfig); + config.setProperty("hazelcast.socket.server.bind.any", "false"); + config.setProperty("hazelcast.heartbeat.failuredetector.type", "deadline"); + config.setProperty("hazelcast.heartbeat.interval.seconds", "60"); + config.setProperty("hazelcast.max.no.heartbeat.seconds", "180"); + config.getJetConfig().setEnabled(false); + mapConfigs.forEach(mapConfig -> config.addMapConfig(mapConfig)); + return config; + } + + @ConditionalOnMissingBean(value = Config.class) + @Bean + public Config createDevelopmentConfig( + List mapConfigs, + NetworkConfig networkConfig, + PartitionGroupConfig groupConfig + ) { + log.info("Initializing a new development hazelcast configuration"); + Config config = new Config(); + config.setClusterName("DEV Cache"); + config.setInstanceName("DEV Cache - " + UUID.randomUUID()); + config.setPartitionGroupConfig(groupConfig); + config.setNetworkConfig(networkConfig); + config.setProperty("hazelcast.health.monitoring.level","NOISY"); + config.setProperty("hazelcast.socket.server.bind.any", "false"); + config.setProperty("hazelcast.logging.type", "slf4j"); + config.setProperty("hazelcast.heartbeat.failuredetector.type", "deadline"); + config.setProperty("hazelcast.heartbeat.interval.seconds", "30"); + config.setProperty("hazelcast.max.no.heartbeat.seconds", "180"); + config.getJetConfig().setEnabled(false); + mapConfigs.forEach(mapConfig -> config.addMapConfig(mapConfig)); + return config; + } + + @Bean + public PartitionGroupConfig partitionGroupConfig() { + log.info("Initializing a new partitioning config"); + return new PartitionGroupConfig().setEnabled(true) + .setGroupType(PartitionGroupConfig.MemberGroupType.PER_MEMBER); + } + + @ConditionalOnMissingBean(value = NetworkConfig.class) + @Bean + public NetworkConfig developmentNetworkConfig() { + log.info("Initializing a new development network config"); + JoinConfig joinConfig = new JoinConfig() + .setTcpIpConfig(new TcpIpConfig() + .setEnabled(true) + .setConnectionTimeoutSeconds(30) + .setMembers(List.of("127.0.0.1:5901"))); + + return new NetworkConfig() + .setJoin(joinConfig) + .setPort(5901) + .setPortAutoIncrement(true) + .setReuseAddress(true); + } + + @Profile(value = {"prod", "production"}) + @Bean + public NetworkConfig productionNetworkConfig() { + log.info("Initializing a new production network config"); + JoinConfig joinConfig = new JoinConfig() + .setKubernetesConfig( + new KubernetesConfig() + .setEnabled(true) + ); + + joinConfig.getMulticastConfig().setEnabled(false); + return new NetworkConfig() + .setJoin(joinConfig) + .setPort(5701) + .setPortAutoIncrement(false); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/authorization/CacheAuthorizationMapConfig.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/authorization/CacheAuthorizationMapConfig.java new file mode 100644 index 0000000000..be6963255b --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/caching/authorization/CacheAuthorizationMapConfig.java @@ -0,0 +1,46 @@ +package com.onlyoffice.authorization.configuration.caching.authorization; + +import com.hazelcast.config.*; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Configuration +@ConfigurationProperties(prefix = "application.cache.authorization") +@RequiredArgsConstructor +@Getter +@Setter +public class CacheAuthorizationMapConfig { + public static final String AUTHORIZATIONS = "authorization"; + private int mapSizeMB = 100; + private int mapSecondsTTL = 50; + private int mapSecondsIdle = 60 * 60; + private int mapAsyncBackup = 1; + private int mapBackup = 1; + + @Bean + public MapConfig mapConfig() { + EvictionConfig evictionConfig = new EvictionConfig() + .setSize(mapSizeMB) + .setMaxSizePolicy(MaxSizePolicy.USED_HEAP_SIZE) + .setEvictionPolicy(EvictionPolicy.LFU); + + MapConfig mapConfig = new MapConfig(AUTHORIZATIONS) + .setName("Cache Authorizations Config") + .setTimeToLiveSeconds(mapSecondsTTL) + .setMaxIdleSeconds(mapSecondsIdle) + .setAsyncBackupCount(mapAsyncBackup) + .setBackupCount(mapBackup) + .setReadBackupData(false) + .setEvictionConfig(evictionConfig) + .setMetadataPolicy(MetadataPolicy.CREATE_ON_UPDATE); + mapConfig.getMapStoreConfig().setInitialLoadMode(MapStoreConfig.InitialLoadMode.EAGER); + return mapConfig; + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/GenericQueueConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/GenericQueueConfiguration.java new file mode 100644 index 0000000000..78671b51b1 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/GenericQueueConfiguration.java @@ -0,0 +1,24 @@ +package com.onlyoffice.authorization.configuration.messaging; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class GenericQueueConfiguration { + private String exchange; + private String queue; + private String routing; + + private String deadQueue; + private String deadExchange; + private String deadRouting; + + private int deadMaxBytes = 15000000; + + private int maxBytes = 20000000; + private int deliveryLimit = 3; + private int messageTTL = 100000; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/RabbitMQConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/RabbitMQConfiguration.java new file mode 100644 index 0000000000..c940311f35 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/messaging/RabbitMQConfiguration.java @@ -0,0 +1,79 @@ +package com.onlyoffice.authorization.configuration.messaging; + +import com.onlyoffice.authorization.dto.messages.AuthorizationMessage; +import com.onlyoffice.authorization.dto.messages.ConsentMessage; +import lombok.Getter; +import lombok.Setter; +import org.springframework.amqp.core.AcknowledgeMode; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper; +import org.springframework.amqp.support.converter.Jackson2JavaTypeMapper; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +@Configuration +@ConfigurationProperties(prefix = "messaging.rabbitmq.configuration") +@Getter +@Setter +public class RabbitMQConfiguration { + private GenericQueueConfiguration authorization; + private GenericQueueConfiguration consent; + private int prefetch = 500; + + @Bean + public MessageConverter jsonMessageConverter() { + Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); + DefaultJackson2JavaTypeMapper classMapper = new DefaultJackson2JavaTypeMapper(); + classMapper.setTrustedPackages("*"); + classMapper.setIdClassMapping(Map.of( + "authorization", AuthorizationMessage.class, + "consent", ConsentMessage.class + )); + messageConverter.setClassMapper(classMapper); + messageConverter.setTypePrecedence(Jackson2JavaTypeMapper.TypePrecedence.TYPE_ID); + return messageConverter; + } + + @Bean("rabbitListenerContainerFactory") + public RabbitListenerContainerFactory rabbitFactory( + ConnectionFactory connectionFactory, + MessageConverter converter + ) { + var factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory); + factory.setMessageConverter(converter); + return factory; + } + + @Bean("prefetchRabbitListenerContainerFactory") + public RabbitListenerContainerFactory prefetchRabbitListenerContainerFactory( + ConnectionFactory rabbitConnectionFactory, + MessageConverter converter + ) { + var factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(rabbitConnectionFactory); + factory.setMessageConverter(converter); + factory.setPrefetchCount(prefetch); + factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); + return factory; + } + + public AmqpTemplate rabbitTemplate( + ConnectionFactory connectionFactory, + MessageConverter converter + ) { + final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(converter); + return rabbitTemplate; + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java new file mode 100644 index 0000000000..76eb06f190 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java @@ -0,0 +1,75 @@ +package com.onlyoffice.authorization.controllers; + +import com.onlyoffice.authorization.configuration.ApplicationConfiguration; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.security.Principal; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Controller +@RequiredArgsConstructor +@Slf4j +public class AuthorizationConsentController { + private final ApplicationConfiguration configuration; + private final RegisteredClientRepository registeredClientRepository; + private final OAuth2AuthorizationConsentService authorizationConsentService; + + @GetMapping(value = "/oauth2/consent") + public String consent( + Principal principal, Model model, + @RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId, + @RequestParam(OAuth2ParameterNames.SCOPE) String scope, + @RequestParam(OAuth2ParameterNames.STATE) String state + ) { + log.debug("Got a new consent request for client {} with scopes {} and state {}", clientId, scope, state); + Set scopesToApprove = new HashSet<>(); + Set previouslyApprovedScopes = new HashSet<>(); + RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId); + OAuth2AuthorizationConsent currentAuthorizationConsent = + this.authorizationConsentService.findById(registeredClient.getId(), principal.getName()); + Set authorizedScopes; + + if (currentAuthorizationConsent != null) { + authorizedScopes = currentAuthorizationConsent.getScopes(); + } else { + authorizedScopes = Collections.emptySet(); + } + + for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) { + if (authorizedScopes.contains(requestedScope)) { + previouslyApprovedScopes.add(requestedScope); + } else { + scopesToApprove.add(requestedScope); + } + } + + String url = String.format( + "redirect:%s/consent?clientId=%s&state=%s&principalName=%s", + configuration.getFrontendUrl(), + clientId, + state, + principal.getName() + ); + + if (scope.length() > 0) + url += String.format("&scopes=%s", String.join(",", scopesToApprove)); + + if (previouslyApprovedScopes.size() > 0) + url += String.format("&previouslyApprovedScopes=%s", String.join(",", previouslyApprovedScopes)); + + return url; + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java new file mode 100644 index 0000000000..a87ca5f147 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java @@ -0,0 +1,27 @@ +package com.onlyoffice.authorization.controllers; + +import com.onlyoffice.authorization.configuration.ApplicationConfiguration; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +@RequiredArgsConstructor +@Slf4j +public class LoginController { + private final String FORWARD = "FORWARD"; + private final ApplicationConfiguration configuration; + + @GetMapping("/login") + public String login(HttpServletRequest request) { + log.debug("A new login request"); + if (request.getDispatcherType().name() == null || !request.getDispatcherType().name().equals(FORWARD)) + return String.format("redirect:%s/error", configuration.getFrontendUrl()); + return String.format( + "redirect:%s/login?%s", + configuration.getFrontendUrl(), + request.getQueryString()); + } +} \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/UsernamePasswordCredentials.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/UsernamePasswordCredentials.java new file mode 100644 index 0000000000..eabe1c05bf --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/UsernamePasswordCredentials.java @@ -0,0 +1,14 @@ +package com.onlyoffice.authorization.dto; + +import lombok.Builder; +import lombok.Data; + +/** + * + */ +@Data +@Builder +public class UsernamePasswordCredentials { + private String username; + private String password; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/AuthorizationMessage.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/AuthorizationMessage.java new file mode 100644 index 0000000000..9fdf671d25 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/AuthorizationMessage.java @@ -0,0 +1,38 @@ +package com.onlyoffice.authorization.dto.messages; + +import lombok.*; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Date; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class AuthorizationMessage implements Serializable { + private String id; + private String registeredClientId; + private String principalName; + private String authorizationGrantType; + private String authorizedScopes; + private String attributes; + private String state; + private String authorizationCodeValue; + private Date authorizationCodeIssuedAt; + private Date authorizationCodeExpiresAt; + private String authorizationCodeMetadata; + private String accessTokenValue; + private Date accessTokenIssuedAt; + private Date accessTokenExpiresAt; + private String accessTokenMetadata; + private String accessTokenType; + private String accessTokenScopes; + private String refreshTokenValue; + private Date refreshTokenIssuedAt; + private Date refreshTokenExpiresAt; + private String refreshTokenMetadata; + private Timestamp modifiedAt; + private Boolean invalidated; +} \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/ConsentMessage.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/ConsentMessage.java new file mode 100644 index 0000000000..ca098ca688 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/ConsentMessage.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.dto.messages; + +import lombok.*; + +import java.io.Serializable; +import java.sql.Timestamp; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class ConsentMessage implements Serializable { + private String registeredClientId; + private String principalName; + private String scopes; + private Timestamp modifiedAt; + private Boolean invalidated; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/wrappers/MessageWrapper.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/wrappers/MessageWrapper.java new file mode 100644 index 0000000000..fc45b7abdc --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/dto/messages/wrappers/MessageWrapper.java @@ -0,0 +1,19 @@ +package com.onlyoffice.authorization.dto.messages.wrappers; + +import com.rabbitmq.client.Channel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MessageWrapper implements Serializable { + private long tag; + private Channel channel; + private E data; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Authorization.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Authorization.java new file mode 100644 index 0000000000..08931410a3 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Authorization.java @@ -0,0 +1,73 @@ +package com.onlyoffice.authorization.entities; + +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.Immutable; + +import java.sql.Timestamp; +import java.util.Date; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Immutable +@Entity +@Table(name = "identity_authorizations") +public class Authorization { + @Id + @Column + private String id; + @Column(name = "registered_client_id") + private String registeredClientId; + @Column(name = "principal_name") + private String principalName; + @Column(name = "authorization_grant_type") + private String authorizationGrantType; + @Column(name = "authorized_scopes", length = 1000) + private String authorizedScopes; + @Lob + @Column(name = "attributes", length = 4000) + private String attributes; + @Column(name = "state", length = 500) + private String state; + @Lob + @Column(name = "authorization_code_value", length = 4000) + private String authorizationCodeValue; + @Column(name = "authorization_code_issued_at") + private Date authorizationCodeIssuedAt; + @Column(name = "authorization_code_expires_at") + private Date authorizationCodeExpiresAt; + @Column(name = "authorization_code_metadata") + private String authorizationCodeMetadata; + @Lob + @Column(name = "access_token_value", length = 4000) + private String accessTokenValue; + @Column(name = "access_token_issued_at") + private Date accessTokenIssuedAt; + @Column(name = "access_token_expires_at") + private Date accessTokenExpiresAt; + @Lob + @Column(name = "access_token_metadata", length = 2000) + private String accessTokenMetadata; + @Column(name = "access_token_type") + private String accessTokenType; + @Column(name = "access_token_scopes", length = 1000) + private String accessTokenScopes; + @Lob + @Column(name = "refresh_token_value", length = 4000) + private String refreshTokenValue; + @Column(name = "refresh_token_issued_at") + private Date refreshTokenIssuedAt; + @Column(name = "refresh_token_expires_at") + private Date refreshTokenExpiresAt; + @Lob + @Column(name = "refresh_token_metadata", length = 2000) + private String refreshTokenMetadata; + @Column(name = "modified_at") + private Timestamp modifiedAt; + @Column(name = "invalidated") + private Boolean invalidated; +} + diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Client.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Client.java new file mode 100644 index 0000000000..770434284a --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Client.java @@ -0,0 +1,44 @@ +package com.onlyoffice.authorization.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Immutable; + +import java.time.Instant; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Immutable +@Entity +@Table(name = "identity_clients") +public class Client { + @Id + @Column(name = "client_id") + private String clientId; + @Column(name = "client_name") + private String clientName; + @Column(name = "client_secret") + private String clientSecret; + @Column(name = "client_issued_at") + private Instant clientIssuedAt; + @Column(name = "authentication_method") + private String clientAuthenticationMethod; + @Column(name = "redirect_uri") + private String redirectUri; + @Column(name = "logout_redirect_uri") + private String postLogoutRedirectUri; + @Column(name = "scopes") + private String scopes; + @Column(name = "tenant_id") + private Integer tenantId; + @Column(name = "invalidated") + private Boolean invalidated; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Consent.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Consent.java new file mode 100644 index 0000000000..abe0311b4c --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/entities/Consent.java @@ -0,0 +1,55 @@ +package com.onlyoffice.authorization.entities; + +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.Immutable; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Objects; + +@IdClass(Consent.ConsentId.class) +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +@Immutable +@Entity +@Table(name = "identity_consents") +public class Consent { + @Id + @Column(name = "registered_client_id") + private String registeredClientId; + @Id + @Column(name = "principal_name") + private String principalName; + @Column(name = "scopes") + @Lob + private String scopes; + @Column(name = "modified_at") + private Timestamp modifiedAt; + @Column(name = "invalidated") + private Boolean invalidated; + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class ConsentId implements Serializable { + private static final long serialVersionUID = 1L; + private String registeredClientId; + private String principalName; + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConsentId that = (ConsentId) o; + return registeredClientId.equals(that.registeredClientId) && principalName.equals(that.principalName); + } + + public int hashCode() { + return Objects.hash(registeredClientId, principalName); + } + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/AuthenticationMethodNotFoundException.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/AuthenticationMethodNotFoundException.java new file mode 100644 index 0000000000..414f03c686 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/AuthenticationMethodNotFoundException.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.exceptions; + +public class AuthenticationMethodNotFoundException extends RuntimeException { + public AuthenticationMethodNotFoundException() { + } + + public AuthenticationMethodNotFoundException(String message) { + super(message); + } + + public AuthenticationMethodNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public AuthenticationMethodNotFoundException(Throwable cause) { + super(cause); + } + + public AuthenticationMethodNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ClientNotFoundException.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ClientNotFoundException.java new file mode 100644 index 0000000000..e30c7e4b2a --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ClientNotFoundException.java @@ -0,0 +1,23 @@ +package com.onlyoffice.authorization.exceptions; + +public class ClientNotFoundException extends RuntimeException { + public ClientNotFoundException() { + super(); + } + + public ClientNotFoundException(String message) { + super(message); + } + + public ClientNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ClientNotFoundException(Throwable cause) { + super(cause); + } + + protected ClientNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ReadOnlyOperationException.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ReadOnlyOperationException.java new file mode 100644 index 0000000000..e288c8cef8 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/exceptions/ReadOnlyOperationException.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.exceptions; + +public class ReadOnlyOperationException extends RuntimeException { + public ReadOnlyOperationException() { + } + + public ReadOnlyOperationException(String message) { + super(message); + } + + public ReadOnlyOperationException(String message, Throwable cause) { + super(message, cause); + } + + public ReadOnlyOperationException(Throwable cause) { + super(cause); + } + + public ReadOnlyOperationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/CookieCsrfFilter.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/CookieCsrfFilter.java new file mode 100644 index 0000000000..3e131bed8b --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/CookieCsrfFilter.java @@ -0,0 +1,26 @@ +package com.onlyoffice.authorization.extensions.filters; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE + 1) +public class CookieCsrfFilter extends OncePerRequestFilter { + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); + if (csrfToken != null) + response.setHeader(csrfToken.getHeaderName(), csrfToken.getToken()); + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/SimpleCORSFilter.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/SimpleCORSFilter.java new file mode 100644 index 0000000000..1fa013f9e9 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/filters/SimpleCORSFilter.java @@ -0,0 +1,31 @@ +package com.onlyoffice.authorization.extensions.filters; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleCORSFilter extends OncePerRequestFilter { + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:3005"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + + if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + chain.doFilter(request, response); + } + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/ECGenerator.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/ECGenerator.java new file mode 100644 index 0000000000..eb5722f375 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/ECGenerator.java @@ -0,0 +1,64 @@ +package com.onlyoffice.authorization.extensions.jwks; + + +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.EllipticCurve; +import java.util.UUID; + +@Component +@Qualifier("ec") +@Primary +public class ECGenerator implements JwksKeyPairGenerator { + public JWK generateKey() throws NoSuchAlgorithmException { + KeyPair keyPair = generateKeyPair(); + ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic(); + ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate(); + Curve curve = Curve.forECParameterSpec(publicKey.getParams()); + return new ECKey.Builder(curve, publicKey) + .privateKey(privateKey) + .keyID(UUID.randomUUID().toString()) + .build(); + } + + public KeyPair generateKeyPair() throws NoSuchAlgorithmException { + EllipticCurve ellipticCurve = new EllipticCurve( + new ECFieldFp( + new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")), + new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"), + new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291")); + ECPoint ecPoint = new ECPoint( + new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"), + new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109")); + ECParameterSpec ecParameterSpec = new ECParameterSpec( + ellipticCurve, + ecPoint, + new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"), + 1); + + KeyPair keyPair; + + try { + java.security.KeyPairGenerator keyPairGenerator = java.security.KeyPairGenerator.getInstance("EC"); + keyPairGenerator.initialize(ecParameterSpec); + keyPair = keyPairGenerator.generateKeyPair(); + } catch (Exception ex) { + throw new NoSuchAlgorithmException(ex); + } + + return keyPair; + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/JwksKeyPairGenerator.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/JwksKeyPairGenerator.java new file mode 100644 index 0000000000..597ff45075 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/JwksKeyPairGenerator.java @@ -0,0 +1,14 @@ +package com.onlyoffice.authorization.extensions.jwks; + +import com.nimbusds.jose.jwk.JWK; + +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; + +/** + * + */ +public interface JwksKeyPairGenerator { + JWK generateKey() throws NoSuchAlgorithmException; + KeyPair generateKeyPair() throws NoSuchAlgorithmException; +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/RSAGenerator.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/RSAGenerator.java new file mode 100644 index 0000000000..4bfce685ca --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/jwks/RSAGenerator.java @@ -0,0 +1,34 @@ +package com.onlyoffice.authorization.extensions.jwks; + + +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.RSAKey; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.UUID; + +@Component +@Qualifier("rsa") +public class RSAGenerator implements JwksKeyPairGenerator { + public JWK generateKey() throws NoSuchAlgorithmException { + KeyPair keyPair = generateKeyPair(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + return new RSAKey.Builder(publicKey) + .privateKey(privateKey) + .keyID(UUID.randomUUID().toString()) + .build(); + } + + public KeyPair generateKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + return keyPairGenerator.generateKeyPair(); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/providers/DocspaceAuthenticationProvider.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/providers/DocspaceAuthenticationProvider.java new file mode 100644 index 0000000000..df90d9ab3a --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/providers/DocspaceAuthenticationProvider.java @@ -0,0 +1,60 @@ +package com.onlyoffice.authorization.extensions.providers; + +import com.onlyoffice.authorization.configuration.DocspaceConfiguration; +import com.onlyoffice.authorization.dto.UsernamePasswordCredentials; +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +@RequiredArgsConstructor +@Slf4j +public class DocspaceAuthenticationProvider implements AuthenticationProvider { + private final DocspaceConfiguration docspaceConfiguration; + private final RestTemplate restTemplate; + + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + log.debug("trying to authenticate a docspace user {}", authentication.getPrincipal().toString()); + UsernamePasswordAuthenticationToken a = (UsernamePasswordAuthenticationToken) authentication; + if (isDocspaceAuthenticated(a.getPrincipal().toString(), a.getCredentials().toString())) { + return new UsernamePasswordAuthenticationToken(a.getPrincipal(), a.getCredentials(), null); + } + + throw new BadCredentialsException("invalid username or password"); + } + + public boolean supports(Class authentication) { + return UsernamePasswordAuthenticationToken.class.equals(authentication); + } + + @Bulkhead(name = "docspaceBulkhead", fallbackMethod = "docspaceAuthenticatedFallback") + private boolean isDocspaceAuthenticated(String username, String password) { + try { + log.debug("trying to authenticate user with name {} and password {}", username, password); + return restTemplate.postForEntity( + String.format("%s/api/2.0/authentication", docspaceConfiguration.getUrl()), + UsernamePasswordCredentials + .builder() + .username(username) + .password(password) + .build(), + Object.class + ).getStatusCode().is2xxSuccessful(); + } catch (Exception e) { + log.error("could not authenticate a docspace user: {}", e.getMessage()); + return false; + } + } + + private boolean isDocspaceAuthenticated(String username, String password, Throwable e) { + log.warn("Number of concurrent calls to Docpsace API has been reached: {}", e.getMessage()); + return false; + } +} \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/repositories/DocspaceRegisteredClientRepository.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/repositories/DocspaceRegisteredClientRepository.java new file mode 100644 index 0000000000..4088e9c514 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/repositories/DocspaceRegisteredClientRepository.java @@ -0,0 +1,114 @@ +package com.onlyoffice.authorization.extensions.repositories; + +import com.onlyoffice.authorization.configuration.RegisteredClientConfiguration; +import com.onlyoffice.authorization.entities.Client; +import com.onlyoffice.authorization.exceptions.ClientNotFoundException; +import com.onlyoffice.authorization.exceptions.ReadOnlyOperationException; +import com.onlyoffice.authorization.repositories.ClientRepository; +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; +import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import java.time.Duration; +import java.util.Arrays; +import java.util.stream.Collectors; + +@Repository +@RequiredArgsConstructor +@Transactional( + readOnly = true, + timeout = 2000 +) +@Slf4j +public class DocspaceRegisteredClientRepository implements RegisteredClientRepository { + private final RegisteredClientConfiguration configuration; + private final ClientRepository clientRepository; + + public void save(RegisteredClient registeredClient) { + throw new ReadOnlyOperationException("Docspace registered client repository supports only read operations"); + } + + @RateLimiter(name = "getRateLimiter", fallbackMethod = "findClientFallback") + public RegisteredClient findById(String id) { + log.debug("trying to find client with id {}", id); + Assert.hasText(id, "id cannot be empty"); + try { + return toObject(clientRepository.findById(id) + .orElseThrow(() -> new ClientNotFoundException(String + .format("could not find client with id %s", id)) + )); + } catch (ClientNotFoundException e) { + log.error(e.getMessage()); + return null; + } + } + + @RateLimiter(name = "getRateLimiter", fallbackMethod = "findClientFallback") + public RegisteredClient findByClientId(String clientId) { + log.debug("trying to find client with client_id {}", clientId); + Assert.hasText(clientId, "client_id cannot be empty"); + try { + return toObject(clientRepository.findClientByClientId(clientId) + .orElseThrow(() -> new ClientNotFoundException(String + .format("could not find client with client_id %s", clientId)))); + } catch (ClientNotFoundException e) { + log.error(e.getMessage()); + return null; + } + } + + private RegisteredClient findClientFallback(String id, Throwable e) { + log.warn("Request is blocked due to rate-limiting for client with id/client_id {}. {}", id, e.getMessage()); + return null; + } + + private RegisteredClient toObject(Client client) { + return RegisteredClient.withId(client.getClientId()) + .clientId(client.getClientId()) + .clientIdIssuedAt(client.getClientIssuedAt()) + .clientSecret(client.getClientSecret()) + .clientName(client.getClientName()) + .clientAuthenticationMethod(client.getClientAuthenticationMethod() + .equals("client_secret_post") ? + ClientAuthenticationMethod.CLIENT_SECRET_POST : + ClientAuthenticationMethod.CLIENT_SECRET_JWT + ) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) + .redirectUris((uris) -> uris.add(client.getRedirectUri())) + .scopes((scopes) -> scopes.addAll(Arrays.stream(client + .getScopes().split(",")) + .collect(Collectors.toSet())) + ) + .clientSettings(ClientSettings + .builder() + .requireProofKey(true) + .requireAuthorizationConsent(true) + .build() + ) + .tokenSettings(TokenSettings + .builder() + .accessTokenTimeToLive(Duration + .ofMinutes(configuration.getAccessTokenMinutesTTL()) + ) + .refreshTokenTimeToLive(Duration + .ofDays(configuration.getRefreshTokenDaysTTL()) + ) + .authorizationCodeTimeToLive(Duration + .ofMinutes(configuration.getAuthorizationCodeMinutesTTL()) + ) + .reuseRefreshTokens(false) + .build() + ) + .build(); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationConsentService.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationConsentService.java new file mode 100644 index 0000000000..e033919d45 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationConsentService.java @@ -0,0 +1,90 @@ +package com.onlyoffice.authorization.extensions.services; + +import com.onlyoffice.authorization.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.dto.messages.ConsentMessage; +import com.onlyoffice.authorization.entities.Consent; +import com.onlyoffice.authorization.repositories.ConsentRepository; +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; + +@Service +@RequiredArgsConstructor +@Transactional( + readOnly = true, + timeout = 2000 +) +@Slf4j +public class DocspaceOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService { + private final RabbitMQConfiguration configuration; + private final ConsentRepository consentRepository; + + private final AmqpTemplate amqpTemplate; + + @RateLimiter(name = "mutateRateLimiter") + public void save(OAuth2AuthorizationConsent authorizationConsent) { + Assert.notNull(authorizationConsent, "authorization consent cannot be null"); + log.debug("trying to save consent with client_id {}", authorizationConsent.getRegisteredClientId()); + this.amqpTemplate.convertAndSend( + configuration.getConsent().getExchange(), + configuration.getConsent().getRouting(), + toMessage(authorizationConsent) + ); + } + + @RateLimiter(name = "mutateRateLimiter") + public void remove(OAuth2AuthorizationConsent authorizationConsent) { + Assert.notNull(authorizationConsent, "authorization consent cannot be null"); + log.debug("trying to remove consent with client_id {}", authorizationConsent.getRegisteredClientId()); + var msg = toMessage(authorizationConsent); + msg.setInvalidated(true); + this.amqpTemplate.convertAndSend( + configuration.getConsent().getExchange(), + configuration.getConsent().getRouting(), + msg + ); + } + + @RateLimiter(name = "getRateLimiter", fallbackMethod = "findConsentFallback") + public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) { + log.debug("trying to remove consent with client_id {} and principal name", registeredClientId, principalName); + Assert.hasText(registeredClientId, "registered client id cannot be empty"); + Assert.hasText(principalName, "principal name cannot be empty"); + return this.consentRepository.findByRegisteredClientIdAndPrincipalName( + registeredClientId, principalName).map(this::toObject).orElse(null); + } + + private OAuth2AuthorizationConsent findConsentFallback(String registeredClientId, String principalName, Throwable e) { + log.warn("Request is blocked due to rate-limiting for client id {} with principal name {}. Reason: {}", + registeredClientId, principalName, e.getMessage()); + return null; + } + + private OAuth2AuthorizationConsent toObject(Consent consent) { + String registeredClientId = consent.getRegisteredClientId(); + OAuth2AuthorizationConsent.Builder builder = OAuth2AuthorizationConsent.withId( + registeredClientId, consent.getPrincipalName()); + Arrays.stream(consent.getScopes().split(",")).forEach(s -> builder.scope(s)); + return builder.build(); + } + + private ConsentMessage toMessage(OAuth2AuthorizationConsent authorizationConsent) { + return ConsentMessage + .builder() + .registeredClientId(authorizationConsent.getRegisteredClientId()) + .principalName(authorizationConsent.getPrincipalName()) + .scopes(String.join(",", authorizationConsent.getScopes())) + .modifiedAt(Timestamp.from(Instant.now())) + .build(); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationService.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationService.java new file mode 100644 index 0000000000..e424477460 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/extensions/services/DocspaceOAuth2AuthorizationService.java @@ -0,0 +1,349 @@ +package com.onlyoffice.authorization.extensions.services; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.onlyoffice.authorization.caching.AuthorizationCache; +import com.onlyoffice.authorization.configuration.messaging.RabbitMQConfiguration; +import com.onlyoffice.authorization.dto.messages.AuthorizationMessage; +import com.onlyoffice.authorization.entities.Authorization; +import com.onlyoffice.authorization.repositories.AuthorizationRepository; +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; +import org.springframework.security.oauth2.core.OAuth2Token; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; +import org.springframework.security.oauth2.server.authorization.OAuth2TokenType; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +@Service +@RequiredArgsConstructor +@Transactional( + readOnly = true, + timeout = 2000 +) +@Slf4j +public class DocspaceOAuth2AuthorizationService implements OAuth2AuthorizationService { + private final RabbitMQConfiguration configuration; + + private final AuthorizationRepository authorizationRepository; + private final RegisteredClientRepository registeredClientRepository; + + private final AmqpTemplate amqpTemplate; + private final AuthorizationCache cache; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @PostConstruct + public void init() { + ClassLoader classLoader = DocspaceOAuth2AuthorizationService.class.getClassLoader(); + List securityModules = SecurityJackson2Modules.getModules(classLoader); + this.objectMapper.registerModules(securityModules); + this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module()); + this.objectMapper.registerModule(new JavaTimeModule()); + } + + @RateLimiter(name = "mutateRateLimiter") + public void save(OAuth2Authorization authorization) { + log.debug("trying to save authorization with id {}", authorization.getId()); + Assert.notNull(authorization, "authorization cannot be null"); + + String state = authorization.getAttribute(OAuth2ParameterNames.STATE); + OAuth2Authorization.Token authorizationCode = + authorization.getToken(OAuth2AuthorizationCode.class); + OAuth2Authorization.Token accessToken = + authorization.getToken(OAuth2AccessToken.class); + OAuth2Authorization.Token refreshToken = + authorization.getToken(OAuth2RefreshToken.class); + + cache.put(authorization.getId(), authorization); + log.debug("Adding authorization with id {} to the cache", authorization.getId()); + if (state != null && !state.isBlank()) { + log.debug("Adding authorization with state {} to the cache", state); + cache.put(state, authorization); + } else if (authorizationCode != null && authorizationCode.getToken() != null) { + log.debug("Adding authorization with code {} to the cache", authorizationCode.getToken()); + cache.put(authorizationCode.getToken().getTokenValue(), authorization); + } else if (accessToken != null && accessToken.getToken() != null) { + log.debug("Adding authorization with access token {} to the cache", accessToken.getToken().getTokenValue()); + cache.put(accessToken.getToken().getTokenValue(), authorization); + } else if (refreshToken != null && refreshToken.getToken() != null) { + log.debug("Adding authorization with refresh token {} to the cache", refreshToken.getToken().getTokenValue()); + cache.put(refreshToken.getToken().getTokenValue(), authorization); + } + + this.amqpTemplate.convertAndSend( + configuration.getAuthorization().getExchange(), + configuration.getAuthorization().getRouting(), + toMessage(authorization) + ); + } + + @RateLimiter(name = "mutateRateLimiter") + public void remove(OAuth2Authorization authorization) { + log.debug("trying to remove authorization with id {}", authorization.getId()); + Assert.notNull(authorization, "authorization cannot be null"); + + String state = authorization.getAttribute(OAuth2ParameterNames.STATE); + OAuth2Authorization.Token authorizationCode = + authorization.getToken(OAuth2AuthorizationCode.class); + OAuth2Authorization.Token accessToken = + authorization.getToken(OAuth2AccessToken.class); + OAuth2Authorization.Token refreshToken = + authorization.getToken(OAuth2RefreshToken.class); + + cache.delete(authorization.getId()); + log.debug("Deleting authorization with id {} from the cache", authorization.getId()); + if (state != null && !state.isBlank()) { + log.debug("Deleting authorization with state {} from the cache", state); + cache.delete(state); + } else if (authorizationCode != null && authorizationCode.getToken() != null) { + log.debug("Deleting authorization with code {} from the cache", authorizationCode.getToken().getTokenValue()); + cache.delete(authorizationCode.getToken().getTokenValue()); + } else if (accessToken != null && accessToken.getToken() != null) { + log.debug("Deleting authorization with access token {} from the cache", accessToken.getToken().getTokenValue()); + cache.delete(accessToken.getToken().getTokenValue()); + } else if (refreshToken != null && refreshToken.getToken() != null) { + log.debug("Deleting authorization with refresh token {} from the cache", refreshToken.getToken().getTokenValue()); + cache.delete(refreshToken.getToken().getTokenValue()); + } + + var msg = toMessage(authorization); + msg.setAccessTokenValue("***"); + msg.setRefreshTokenValue("***"); + msg.setInvalidated(true); + + this.amqpTemplate.convertSendAndReceive( + configuration.getAuthorization().getExchange(), + configuration.getAuthorization().getRouting(), + msg + ); + } + + @RateLimiter(name = "getRateLimiter", fallbackMethod = "findAuthorizationFallback") + public OAuth2Authorization findById(String id) { + log.debug("trying to find authorization with id {}", id); + Assert.hasText(id, "id cannot be empty"); + + var authorization = this.cache.get(id); + if (authorization != null) { + log.debug("found authorization with id {} in the cache", id); + this.cache.delete(authorization.getId()); + log.debug("authorization with id {} has been removed from the cache", authorization.getId()); + return authorization; + } + + return this.authorizationRepository.findById(id).map(this::toObject).orElse(null); + } + + private OAuth2Authorization findAuthorizationFallback(String id, Throwable e) { + log.warn("Request is blocked due to rate-limiting. Authorization id {}. Reason: {}", + id, e.getMessage()); + return null; + } + + @RateLimiter(name = "getRateLimiter", fallbackMethod = "findAuthorizationByTokenFallback") + public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) { + log.debug("trying to find authorization with token {}", token); + Assert.hasText(token, "token cannot be empty"); + + var authorization = this.cache.get(token); + if (authorization != null) { + log.debug("found authorization with token {} in the cache", token); + this.cache.delete(authorization.getId()); + log.debug("authorization with token {} has been removed from the cache", token); + return authorization; + } + + Optional result; + if (tokenType == null) { + log.debug("trying to find authorization by any value"); + result = this.authorizationRepository.findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(token); + } else if (OAuth2ParameterNames.STATE.equals(tokenType.getValue())) { + log.debug("trying to find authorization by state"); + result = this.authorizationRepository.findByState(token); + } else if (OAuth2ParameterNames.CODE.equals(tokenType.getValue())) { + log.debug("trying to find authorization by authorization code"); + result = this.authorizationRepository.findByAuthorizationCodeValue(token); + } else if (OAuth2ParameterNames.ACCESS_TOKEN.equals(tokenType.getValue())) { + log.debug("trying to find authorization by access token"); + result = this.authorizationRepository.findByAccessTokenValue(token); + } else if (OAuth2ParameterNames.REFRESH_TOKEN.equals(tokenType.getValue())) { + log.debug("trying to find authorization by refresh token"); + result = this.authorizationRepository.findByRefreshTokenValue(token); + } else { + log.debug("empty authorization"); + result = Optional.empty(); + } + + return result.map(this::toObject).orElse(null); + } + + private OAuth2Authorization findAuthorizationByTokenFallback(String token, OAuth2TokenType tokenType, Throwable e) { + log.warn("Request is blocked due to rate-limiting. Authorization token {} with type {}. Reason: {}", + token, tokenType.getValue(), e.getMessage()); + return null; + } + + private OAuth2Authorization toObject(Authorization entity) { + RegisteredClient registeredClient = this.registeredClientRepository.findById(entity.getRegisteredClientId()); + if (registeredClient == null) { + throw new DataRetrievalFailureException( + "the registered client with id '" + entity.getRegisteredClientId() + "' was not found in the registered client repository."); + } + + OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient) + .id(entity.getId()) + .principalName(entity.getPrincipalName()) + .authorizationGrantType(resolveAuthorizationGrantType(entity.getAuthorizationGrantType())) + .authorizedScopes(StringUtils.commaDelimitedListToSet(entity.getAuthorizedScopes())) + .attributes(attributes -> attributes.putAll(parseMap(entity.getAttributes()))); + if (entity.getState() != null) { + builder.attribute(OAuth2ParameterNames.STATE, entity.getState()); + } + + if (entity.getAuthorizationCodeValue() != null) { + OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode( + entity.getAuthorizationCodeValue(), + entity.getAuthorizationCodeIssuedAt().toInstant(), + entity.getAuthorizationCodeExpiresAt().toInstant()); + builder.token(authorizationCode, metadata -> metadata.putAll(parseMap(entity.getAuthorizationCodeMetadata()))); + } + + if (entity.getAccessTokenValue() != null) { + OAuth2AccessToken accessToken = new OAuth2AccessToken( + OAuth2AccessToken.TokenType.BEARER, + entity.getAccessTokenValue(), + entity.getAccessTokenIssuedAt().toInstant(), + entity.getAccessTokenExpiresAt().toInstant(), + StringUtils.commaDelimitedListToSet(entity.getAccessTokenScopes())); + builder.token(accessToken, metadata -> metadata.putAll(parseMap(entity.getAccessTokenMetadata()))); + } + + if (entity.getRefreshTokenValue() != null) { + OAuth2RefreshToken refreshToken = new OAuth2RefreshToken( + entity.getRefreshTokenValue(), + entity.getRefreshTokenIssuedAt().toInstant(), + entity.getRefreshTokenExpiresAt().toInstant()); + builder.token(refreshToken, metadata -> metadata.putAll(parseMap(entity.getRefreshTokenMetadata()))); + } + + return builder.build(); + } + + private AuthorizationMessage toMessage(OAuth2Authorization authorization) { + AuthorizationMessage message = AuthorizationMessage + .builder() + .id(authorization.getId()) + .registeredClientId(authorization.getRegisteredClientId()) + .principalName(authorization.getPrincipalName()) + .authorizationGrantType(authorization.getAuthorizationGrantType().getValue()) + .authorizedScopes(StringUtils.collectionToDelimitedString(authorization.getAuthorizedScopes(), ",")) + .attributes(writeMap(authorization.getAttributes())) + .state(authorization.getAttribute(OAuth2ParameterNames.STATE)) + .build(); + + OAuth2Authorization.Token authorizationCode = + authorization.getToken(OAuth2AuthorizationCode.class); + setTokenValues( + authorizationCode, + message::setAuthorizationCodeValue, + message::setAuthorizationCodeIssuedAt, + message::setAuthorizationCodeExpiresAt, + message::setAuthorizationCodeMetadata + ); + + OAuth2Authorization.Token accessToken = + authorization.getToken(OAuth2AccessToken.class); + setTokenValues( + accessToken, + message::setAccessTokenValue, + message::setAccessTokenIssuedAt, + message::setAccessTokenExpiresAt, + message::setAccessTokenMetadata + ); + + if (accessToken != null && accessToken.getToken().getScopes() != null) { + message.setAccessTokenScopes(StringUtils.collectionToDelimitedString(accessToken.getToken().getScopes(), ",")); + } + + OAuth2Authorization.Token refreshToken = + authorization.getToken(OAuth2RefreshToken.class); + + setTokenValues( + refreshToken, + message::setRefreshTokenValue, + message::setRefreshTokenIssuedAt, + message::setRefreshTokenExpiresAt, + message::setRefreshTokenMetadata + ); + + return message; + } + + private void setTokenValues( + OAuth2Authorization.Token token, + Consumer tokenValueConsumer, + Consumer issuedAtConsumer, + Consumer expiresAtConsumer, + Consumer metadataConsumer) { + if (token != null) { + OAuth2Token oAuth2Token = token.getToken(); + tokenValueConsumer.accept(oAuth2Token.getTokenValue()); + issuedAtConsumer.accept(Date.from(oAuth2Token.getIssuedAt())); + expiresAtConsumer.accept(Date.from(oAuth2Token.getExpiresAt())); + metadataConsumer.accept(writeMap(token.getMetadata())); + } + } + + private Map parseMap(String data) { + try { + return this.objectMapper.readValue(data, new TypeReference>() { + }); + } catch (Exception ex) { + throw new IllegalArgumentException(ex.getMessage(), ex); + } + } + + private String writeMap(Map metadata) { + try { + return this.objectMapper.writeValueAsString(metadata); + } catch (Exception ex) { + throw new IllegalArgumentException(ex.getMessage(), ex); + } + } + + private static AuthorizationGrantType resolveAuthorizationGrantType(String authorizationGrantType) { + if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(authorizationGrantType)) { + return AuthorizationGrantType.AUTHORIZATION_CODE; + } else if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(authorizationGrantType)) { + return AuthorizationGrantType.CLIENT_CREDENTIALS; + } else if (AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(authorizationGrantType)) { + return AuthorizationGrantType.REFRESH_TOKEN; + } + return new AuthorizationGrantType(authorizationGrantType); + } +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/AuthorizationRepository.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/AuthorizationRepository.java new file mode 100644 index 0000000000..46a01b7596 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/AuthorizationRepository.java @@ -0,0 +1,22 @@ +package com.onlyoffice.authorization.repositories; + +import com.onlyoffice.authorization.entities.Authorization; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.query.Param; + +import java.util.Optional; + +public interface AuthorizationRepository extends Repository { + Optional findById(String id); + Optional findByState(String state); + Optional findByAuthorizationCodeValue(String authorizationCode); + Optional findByAccessTokenValue(String accessToken); + Optional findByRefreshTokenValue(String refreshToken); + @Query("SELECT a FROM Authorization a WHERE a.state = :token" + + " OR a.authorizationCodeValue = :token" + + " OR a.accessTokenValue = :token" + + " OR a.refreshTokenValue = :token" + ) + Optional findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValue(@Param("token") String token); +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ClientRepository.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ClientRepository.java new file mode 100644 index 0000000000..5e2a4cf8a1 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ClientRepository.java @@ -0,0 +1,11 @@ +package com.onlyoffice.authorization.repositories; + +import com.onlyoffice.authorization.entities.Client; +import org.springframework.data.repository.Repository; + +import java.util.Optional; + +public interface ClientRepository extends Repository { + Optional findById(String id); + Optional findClientByClientId(String clientId); +} diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ConsentRepository.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ConsentRepository.java new file mode 100644 index 0000000000..386f68de43 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/repositories/ConsentRepository.java @@ -0,0 +1,10 @@ +package com.onlyoffice.authorization.repositories; + +import com.onlyoffice.authorization.entities.Consent; +import org.springframework.data.repository.Repository; + +import java.util.Optional; + +public interface ConsentRepository extends Repository { + Optional findByRegisteredClientIdAndPrincipalName(String registeredClientId, String principalName); +} diff --git a/web/ASC.OAuth/authorization/src/main/resources/application.yml b/web/ASC.OAuth/authorization/src/main/resources/application.yml new file mode 100644 index 0000000000..7773fc84c7 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/resources/application.yml @@ -0,0 +1,82 @@ +server: + port: 8080 + +spring: + application: + name: authorization + profiles: + active: ${PROFILE:dev} + datasource: + url: jdbc:mysql://${JDBC_URL:onlyoffice-mysql-server}/${JDBC_DATABASE:docspace} + username: ${JDBC_USER_NAME:root} + password: ${JDBC_PASSWORD:my-secret-pw} + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + properties: + hibernate: + dialect: org.hibernate.dialect.MySQLDialect + rabbitmq: + host: ${RABBIT_HOST:onlyoffice-rabbitmq} + port: ${RABBIT_PORT:5671} + username: ${RABBIT_USER_NAME:guest} + password: ${RABBIT_PASSWORD:guest} + listener: + simple: + retry: + enabled: true + initial-interval: 1000 + max-attempts: 3 + max-interval: 3000 + multiplier: 3.0 + +application: + server: + url: http://onlyoffice-oauth-authorization:8080 + +docspace: + server: + url: http://${DOCSPACE_ADDRESS:localhost:8092} + +resilience4j: + bulkhead: + instances: + docspaceBulkhead: + maxConcurrentCalls: 100 + maxWaitDuration: 400ms + ratelimiter: + configs: + default: + limitRefreshPeriod: 1s + limitForPeriod: 1000 + timeoutDuration: 500ms + registerHealthIndicator: true + eventConsumerBufferSize: 100 + instances: + getRateLimiter: + baseConfig: default + mutateRateLimiter: + baseConfig: default + timelimiter: + instances: + mutateTimeLimiter: + timeoutDuration: 2s + readTimeLimiter: + timeoutDuration: 1s + +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + env: + post: + enabled: true + +logging: + level: + root: INFO + org: + hibernate: + stat: DEBUG + SQL: DEBUG \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/resources/templates/authorized.html b/web/ASC.OAuth/authorization/src/main/resources/templates/authorized.html new file mode 100644 index 0000000000..96440b4fb5 --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/resources/templates/authorized.html @@ -0,0 +1,10 @@ + + + + + Title + + +
Authorized
+ + \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/main/resources/templates/error.html b/web/ASC.OAuth/authorization/src/main/resources/templates/error.html new file mode 100644 index 0000000000..8cf832506f --- /dev/null +++ b/web/ASC.OAuth/authorization/src/main/resources/templates/error.html @@ -0,0 +1,10 @@ + + + + + Title + + +
Error
+ + \ No newline at end of file diff --git a/web/ASC.OAuth/authorization/src/test/java/com/onlyoffice/authorization/AuthorizationApplicationTests.java b/web/ASC.OAuth/authorization/src/test/java/com/onlyoffice/authorization/AuthorizationApplicationTests.java new file mode 100644 index 0000000000..c990233e4d --- /dev/null +++ b/web/ASC.OAuth/authorization/src/test/java/com/onlyoffice/authorization/AuthorizationApplicationTests.java @@ -0,0 +1,13 @@ +package com.onlyoffice.authorization; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AuthorizationApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/web/ASC.OAuth/client/.gitignore b/web/ASC.OAuth/client/.gitignore new file mode 100644 index 0000000000..4d29575de8 --- /dev/null +++ b/web/ASC.OAuth/client/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/web/ASC.OAuth/client/README.md b/web/ASC.OAuth/client/README.md new file mode 100644 index 0000000000..58beeaccd8 --- /dev/null +++ b/web/ASC.OAuth/client/README.md @@ -0,0 +1,70 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in your browser. + +The page will reload when you make changes.\ +You may also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can't go back!** + +If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. + +You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) + +### Analyzing the Bundle Size + +This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) + +### Making a Progressive Web App + +This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) + +### Advanced Configuration + +This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) + +### Deployment + +This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) + +### `npm run build` fails to minify + +This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/web/ASC.OAuth/client/package.json b/web/ASC.OAuth/client/package.json new file mode 100644 index 0000000000..9a212540d8 --- /dev/null +++ b/web/ASC.OAuth/client/package.json @@ -0,0 +1,41 @@ +{ + "name": "client", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "axios": "^1.4.0", + "react": "^18.2.0", + "react-cookie": "^5.0.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0", + "react-scripts": "5.0.1", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/web/ASC.OAuth/client/public/favicon.ico b/web/ASC.OAuth/client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a11777cc471a4344702741ab1c8a588998b1311a GIT binary patch literal 3870 zcma);c{J4h9>;%nil|2-o+rCuEF-(I%-F}ijC~o(k~HKAkr0)!FCj~d>`RtpD?8b; zXOC1OD!V*IsqUwzbMF1)-gEDD=A573Z-&G7^LoAC9|WO7Xc0Cx1g^Zu0u_SjAPB3vGa^W|sj)80f#V0@M_CAZTIO(t--xg= z!sii`1giyH7EKL_+Wi0ab<)&E_0KD!3Rp2^HNB*K2@PHCs4PWSA32*-^7d{9nH2_E zmC{C*N*)(vEF1_aMamw2A{ZH5aIDqiabnFdJ|y0%aS|64E$`s2ccV~3lR!u<){eS` z#^Mx6o(iP1Ix%4dv`t@!&Za-K@mTm#vadc{0aWDV*_%EiGK7qMC_(`exc>-$Gb9~W!w_^{*pYRm~G zBN{nA;cm^w$VWg1O^^<6vY`1XCD|s_zv*g*5&V#wv&s#h$xlUilPe4U@I&UXZbL z0)%9Uj&@yd03n;!7do+bfixH^FeZ-Ema}s;DQX2gY+7g0s(9;`8GyvPY1*vxiF&|w z>!vA~GA<~JUqH}d;DfBSi^IT*#lrzXl$fNpq0_T1tA+`A$1?(gLb?e#0>UELvljtQ zK+*74m0jn&)5yk8mLBv;=@}c{t0ztT<v;Avck$S6D`Z)^c0(jiwKhQsn|LDRY&w(Fmi91I7H6S;b0XM{e zXp0~(T@k_r-!jkLwd1_Vre^v$G4|kh4}=Gi?$AaJ)3I+^m|Zyj#*?Kp@w(lQdJZf4 z#|IJW5z+S^e9@(6hW6N~{pj8|NO*>1)E=%?nNUAkmv~OY&ZV;m-%?pQ_11)hAr0oAwILrlsGawpxx4D43J&K=n+p3WLnlDsQ$b(9+4 z?mO^hmV^F8MV{4Lx>(Q=aHhQ1){0d*(e&s%G=i5rq3;t{JC zmgbn5Nkl)t@fPH$v;af26lyhH!k+#}_&aBK4baYPbZy$5aFx4}ka&qxl z$=Rh$W;U)>-=S-0=?7FH9dUAd2(q#4TCAHky!$^~;Dz^j|8_wuKc*YzfdAht@Q&ror?91Dm!N03=4=O!a)I*0q~p0g$Fm$pmr$ zb;wD;STDIi$@M%y1>p&_>%?UP($15gou_ue1u0!4(%81;qcIW8NyxFEvXpiJ|H4wz z*mFT(qVx1FKufG11hByuX%lPk4t#WZ{>8ka2efjY`~;AL6vWyQKpJun2nRiZYDij$ zP>4jQXPaP$UC$yIVgGa)jDV;F0l^n(V=HMRB5)20V7&r$jmk{UUIe zVjKroK}JAbD>B`2cwNQ&GDLx8{pg`7hbA~grk|W6LgiZ`8y`{Iq0i>t!3p2}MS6S+ zO_ruKyAElt)rdS>CtF7j{&6rP-#c=7evGMt7B6`7HG|-(WL`bDUAjyn+k$mx$CH;q2Dz4x;cPP$hW=`pFfLO)!jaCL@V2+F)So3}vg|%O*^T1j>C2lx zsURO-zIJC$^$g2byVbRIo^w>UxK}74^TqUiRR#7s_X$e)$6iYG1(PcW7un-va-S&u zHk9-6Zn&>T==A)lM^D~bk{&rFzCi35>UR!ZjQkdSiNX*-;l4z9j*7|q`TBl~Au`5& z+c)*8?#-tgUR$Zd%Q3bs96w6k7q@#tUn`5rj+r@_sAVVLqco|6O{ILX&U-&-cbVa3 zY?ngHR@%l{;`ri%H*0EhBWrGjv!LE4db?HEWb5mu*t@{kv|XwK8?npOshmzf=vZA@ zVSN9sL~!sn?r(AK)Q7Jk2(|M67Uy3I{eRy z_l&Y@A>;vjkWN5I2xvFFTLX0i+`{qz7C_@bo`ZUzDugfq4+>a3?1v%)O+YTd6@Ul7 zAfLfm=nhZ`)P~&v90$&UcF+yXm9sq!qCx3^9gzIcO|Y(js^Fj)Rvq>nQAHI92ap=P z10A4@prk+AGWCb`2)dQYFuR$|H6iDE8p}9a?#nV2}LBCoCf(Xi2@szia7#gY>b|l!-U`c}@ zLdhvQjc!BdLJvYvzzzngnw51yRYCqh4}$oRCy-z|v3Hc*d|?^Wj=l~18*E~*cR_kU z{XsxM1i{V*4GujHQ3DBpl2w4FgFR48Nma@HPgnyKoIEY-MqmMeY=I<%oG~l!f<+FN z1ZY^;10j4M4#HYXP zw5eJpA_y(>uLQ~OucgxDLuf}fVs272FaMxhn4xnDGIyLXnw>Xsd^J8XhcWIwIoQ9} z%FoSJTAGW(SRGwJwb=@pY7r$uQRK3Zd~XbxU)ts!4XsJrCycrWSI?e!IqwqIR8+Jh zlRjZ`UO1I!BtJR_2~7AbkbSm%XQqxEPkz6BTGWx8e}nQ=w7bZ|eVP4?*Tb!$(R)iC z9)&%bS*u(lXqzitAN)Oo=&Ytn>%Hzjc<5liuPi>zC_nw;Z0AE3Y$Jao_Q90R-gl~5 z_xAb2J%eArrC1CN4G$}-zVvCqF1;H;abAu6G*+PDHSYFx@Tdbfox*uEd3}BUyYY-l zTfEsOqsi#f9^FoLO;ChK<554qkri&Av~SIM*{fEYRE?vH7pTAOmu2pz3X?Wn*!ROX ztd54huAk&mFBemMooL33RV-*1f0Q3_(7hl$<#*|WF9P!;r;4_+X~k~uKEqdzZ$5Al zV63XN@)j$FN#cCD;ek1R#l zv%pGrhB~KWgoCj%GT?%{@@o(AJGt*PG#l3i>lhmb_twKH^EYvacVY-6bsCl5*^~L0 zonm@lk2UvvTKr2RS%}T>^~EYqdL1q4nD%0n&Xqr^cK^`J5W;lRRB^R-O8b&HENO||mo0xaD+S=I8RTlIfVgqN@SXDr2&-)we--K7w= zJVU8?Z+7k9dy;s;^gDkQa`0nz6N{T?(A&Iz)2!DEecLyRa&FI!id#5Z7B*O2=PsR0 zEvc|8{NS^)!d)MDX(97Xw}m&kEO@5jqRaDZ!+%`wYOI<23q|&js`&o4xvjP7D_xv@ z5hEwpsp{HezI9!~6O{~)lLR@oF7?J7i>1|5a~UuoN=q&6N}EJPV_GD`&M*v8Y`^2j zKII*d_@Fi$+i*YEW+Hbzn{iQk~yP z>7N{S4)r*!NwQ`(qcN#8SRQsNK6>{)X12nbF`*7#ecO7I)Q$uZsV+xS4E7aUn+U(K baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ literal 0 HcmV?d00001 diff --git a/web/ASC.OAuth/client/public/index.html b/web/ASC.OAuth/client/public/index.html new file mode 100644 index 0000000000..3286290496 --- /dev/null +++ b/web/ASC.OAuth/client/public/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + React App + + + +
+ + diff --git a/web/ASC.OAuth/client/src/App.jsx b/web/ASC.OAuth/client/src/App.jsx new file mode 100644 index 0000000000..62657e63a8 --- /dev/null +++ b/web/ASC.OAuth/client/src/App.jsx @@ -0,0 +1,38 @@ +import { + createBrowserRouter, + RouterProvider, +} from "react-router-dom"; +import { CookiesProvider } from "react-cookie"; + +import Login from "./Login"; +import Consent from "./Consent"; +import Error from "./Error"; + +const router = createBrowserRouter([ + { + path: "/", + element:
Home
+ }, + { + path: "/login", + element: , + }, + { + path: "/consent", + element: + }, + { + path: "/error", + element: + } +]); + +function App() { + return ( + + + + ); +}; + +export default App; diff --git a/web/ASC.OAuth/client/src/Consent.jsx b/web/ASC.OAuth/client/src/Consent.jsx new file mode 100644 index 0000000000..a37db6ffec --- /dev/null +++ b/web/ASC.OAuth/client/src/Consent.jsx @@ -0,0 +1,144 @@ +import React from "react"; +import { useSearchParams } from "react-router-dom"; +import { useCookies } from 'react-cookie'; + +export default function Consent() { + const [searchParams] = useSearchParams(); + const [cookies] = useCookies(['XSRF-TOKEN']); + const clientId = searchParams.get("clientId") || ""; + const principalName = searchParams.get("principalName") || ""; + const state = searchParams.get("state") || ""; + const scopes = searchParams.get("scopes").split(",") || []; + const previouslyApprovedScopes = searchParams.get("previouslyApprovedScopes") ? searchParams.get("previouslyApprovedScopes").split(",") : []; + + const approve = async () => { + const formData = new FormData(); + formData.append("client_id", clientId); + formData.append("state", state); + scopes.forEach(scope => { + formData.append("scope", scope); + }); + const resp = await fetch(`${process.env.REACT_APP_AUTHORIZATION_SERVER}/oauth2/authorize`, { + method: 'POST', + body: formData, + headers: { + 'X-XSRF-TOKEN': cookies['XSRF-TOKEN'], + }, + credentials: "include", + redirect: "follow" + }); + + if (resp.redirected) + window.location.href = resp.url; + } + + // TODO: Loader, error page and so on + return ( +
+
+

App permissions

+
+
+
+

+ + The application + + {clientId} + + wants to access your account + + {principalName} +

+
+
+
+
+

+ The following permissions are requested by the above app. +
+ Please review these and consent if you approve. +

+
+
+
+
+
+ + + {scopes.length > 0 && ( +
+ {scopes.map((scope) => (<> + + {scope} + + ))} +
+ )} + {previouslyApprovedScopes.length > 0 && ( + <> +

+ You have already granted the following permissions to the + above app: +

+ {previouslyApprovedScopes.map((scope) => ( + <> +
+ + {scope} + +
+ + ))} + + )} +
+ +
+
+ +
+
+
+
+
+
+

+ + Your consent to provide access is required. +
+ If you do not approve, click Cancel, in which case no information + will be shared with the app. +
+

+
+
+
+ ); +} + +/* +FORMDATA + +client_id: fc8482ff-b1e4-4397-8a48-13b88f3c25fe +state: huIv-Dc0E01S_lGYPbjXAdSz4Fo5r3pA4eFhaU5G23I= +scope: accounts:read +*/ diff --git a/web/ASC.OAuth/client/src/Error.jsx b/web/ASC.OAuth/client/src/Error.jsx new file mode 100644 index 0000000000..407d83bc84 --- /dev/null +++ b/web/ASC.OAuth/client/src/Error.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export default function Error() { + return ( +
Error
+ ) +}; \ No newline at end of file diff --git a/web/ASC.OAuth/client/src/Login.jsx b/web/ASC.OAuth/client/src/Login.jsx new file mode 100644 index 0000000000..f7fee73453 --- /dev/null +++ b/web/ASC.OAuth/client/src/Login.jsx @@ -0,0 +1,86 @@ +import React, { useState } from "react"; +import axios from "axios"; +import { useSearchParams } from "react-router-dom"; +import { useCookies } from 'react-cookie'; + +export default function Login() { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [searchParams, setSearchParams] = useSearchParams(); + const [cookies] = useCookies(['XSRF-TOKEN']); + + const login = async () => { + const formData = new FormData(); + formData.append("username", username); + formData.append("password", password); + formData.append("_csrf", cookies['XSRF-TOKEN']); + await fetch(`${process.env.REACT_APP_AUTHORIZATION_SERVER}/login?${searchParams.toString()}`, { + method: 'POST', + body: formData, + headers: { + 'X-XSRF-TOKEN': cookies['XSRF-TOKEN'], + }, + credentials: "include", + redirect: "manual" + }); + + window.location.href = `${process.env.REACT_APP_AUTHORIZATION_SERVER}/oauth2/authorize?${searchParams.toString()}&continue`; + } + + return ( +
+
+
+ {searchParams.get("error") && ( +
+
Invalid Email or Password
+
+ )} + {searchParams.get("logout") && ( +
+
You have been logged out.
+
+ )} +
+
+

Login Form

+
+
+
+
+ + setUsername(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ +
+
+
+
+
+
+
+ ); +} diff --git a/web/ASC.OAuth/client/src/index.css b/web/ASC.OAuth/client/src/index.css new file mode 100644 index 0000000000..5a81df5468 --- /dev/null +++ b/web/ASC.OAuth/client/src/index.css @@ -0,0 +1,10 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/web/ASC.OAuth/client/src/index.jsx b/web/ASC.OAuth/client/src/index.jsx new file mode 100644 index 0000000000..62553e66e6 --- /dev/null +++ b/web/ASC.OAuth/client/src/index.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; + +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +import './index.css'; + +const root = ReactDOM.createRoot(document.getElementById('root')); + +root.render( + + + +); + +reportWebVitals(); diff --git a/web/ASC.OAuth/client/src/reportWebVitals.js b/web/ASC.OAuth/client/src/reportWebVitals.js new file mode 100644 index 0000000000..5253d3ad9e --- /dev/null +++ b/web/ASC.OAuth/client/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/web/ASC.OAuth/docker-compose.yml b/web/ASC.OAuth/docker-compose.yml new file mode 100644 index 0000000000..c7435a7e19 --- /dev/null +++ b/web/ASC.OAuth/docker-compose.yml @@ -0,0 +1,45 @@ +version: "3.8" + +services: + onlyoffice-oauth-authorization: + build: + context: ./ + dockerfile: ${OAUTH_AUTHORIZATION_DOCKERFILE} + container_name: onlyoffice-oauth-authorization + restart: always + ports: + - 8080:8080 + environment: + PROFILE: ${PROFILE} + JDBC_URL: ${JDBC_URL} + JDBC_DATABASE: ${JDBC_DATABASE} + JDBC_USER_NAME: ${JDBC_USER_NAME} + JDBC_PASSWORD: ${JDBC_PASSWORD} + RABBIT_HOST: ${RABBIT_HOST} + RABBIT_PORT: ${RABBIT_PORT} + RABBIT_USER_NAME: ${RABBIT_USER_NAME} + RABBIT_PASSWORD: ${RABBIT_PASSWORD} + DOCSPACE_ADDRESS: ${DOCSPACE_ADDRESS} + onlyoffice-oauth-api: + build: + context: ./ + dockerfile: ${OAUTH_API_DOCKERFILE} + container_name: onlyoffice-oauth-api + ports: + - 9090:9090 + - 8585:8585 + environment: + PROFILE: ${PROFILE} + JDBC_URL: ${JDBC_URL} + JDBC_DATABASE: ${JDBC_DATABASE} + JDBC_USER_NAME: ${JDBC_USER_NAME} + JDBC_PASSWORD: ${JDBC_PASSWORD} + RABBIT_HOST: ${RABBIT_HOST} + RABBIT_PORT: ${RABBIT_PORT} + RABBIT_USER_NAME: ${RABBIT_USER_NAME} + RABBIT_PASSWORD: ${RABBIT_PASSWORD} + +networks: + default: + name: ${NETWORK_NAME} + external: true diff --git a/web/ASC.OAuth/pom.xml b/web/ASC.OAuth/pom.xml new file mode 100644 index 0000000000..d0c80efdbe --- /dev/null +++ b/web/ASC.OAuth/pom.xml @@ -0,0 +1,121 @@ + + + 4.0.0 + com.onlyoffice + base + 0.0.1 + pom + ONLYOFFICE Docspace Authorization Server + + api + authorization + configuration + + + + 17 + 17 + 17 + UTF-8 + + 3.1.2 + + 5.2.1 + + 8.0.33 + 2.2.220 + + 1.5.5.Final + 1.18.28 + + + + + + + org.springframework.boot + spring-boot-starter-actuator + ${spring.boot.version} + + + + + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.13.4 + + + org.projectlombok + lombok + ${lombok.version} + true + + + + + + + org.springframework.boot + spring-boot-starter-test + ${spring.boot.version} + test + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + org.projectlombok + lombok + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + + + + + \ No newline at end of file From 11c322f03b1f195384e20cbeff4b47e1816b85d8 Mon Sep 17 00:00:00 2001 From: Dmitrii Vershinin Date: Wed, 13 Sep 2023 17:41:05 +0500 Subject: [PATCH 009/362] chore: client url --- .../authorization/configuration/ApplicationConfiguration.java | 2 +- web/ASC.OAuth/authorization/src/main/resources/application.yml | 1 + web/ASC.OAuth/docker-compose.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java index 056814aba4..bda44dd866 100644 --- a/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java +++ b/web/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java @@ -32,7 +32,7 @@ import java.time.Duration; @RequiredArgsConstructor public class ApplicationConfiguration { private String url; - private String frontendUrl = "http://127.0.0.1:3005"; + private String frontendUrl; private String login = "/login"; private String logout = "/logout"; diff --git a/web/ASC.OAuth/authorization/src/main/resources/application.yml b/web/ASC.OAuth/authorization/src/main/resources/application.yml index 7773fc84c7..a910a19ea0 100644 --- a/web/ASC.OAuth/authorization/src/main/resources/application.yml +++ b/web/ASC.OAuth/authorization/src/main/resources/application.yml @@ -32,6 +32,7 @@ spring: application: server: url: http://onlyoffice-oauth-authorization:8080 + frontendUrl: http://${FRONTEND_ADDRESS:127.0.0.1:3005} docspace: server: diff --git a/web/ASC.OAuth/docker-compose.yml b/web/ASC.OAuth/docker-compose.yml index c7435a7e19..a1a17d9488 100644 --- a/web/ASC.OAuth/docker-compose.yml +++ b/web/ASC.OAuth/docker-compose.yml @@ -20,6 +20,7 @@ services: RABBIT_USER_NAME: ${RABBIT_USER_NAME} RABBIT_PASSWORD: ${RABBIT_PASSWORD} DOCSPACE_ADDRESS: ${DOCSPACE_ADDRESS} + FRONTEND_ADDRESS: ${FRONTEND_ADDRESS} onlyoffice-oauth-api: build: context: ./ From ac496b82a2f51cb97099ca388595dbf2843ec31f Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Fri, 22 Sep 2023 15:38:11 +0300 Subject: [PATCH 010/362] Add oauth service proxy --- build/build.backend.docker.ps1 | 3 + build/install/docker/.env | 4 +- build/install/docker/Dockerfile | 1 + build/install/docker/Dockerfile.app | 1 + build/install/docker/Dockerfile.runtime | 1 + .../nginx/templates/upstream.conf.template | 6 ++ build/install/docker/docspace.profiles.yml | 1 + build/install/docker/docspace.yml | 56 +++++++++---------- build/start/start.backend.docker.ps1 | 2 + config/nginx/onlyoffice.conf | 8 +++ 10 files changed, 54 insertions(+), 29 deletions(-) diff --git a/build/build.backend.docker.ps1 b/build/build.backend.docker.ps1 index b956267f68..d7a09fe53d 100644 --- a/build/build.backend.docker.ps1 +++ b/build/build.backend.docker.ps1 @@ -13,6 +13,7 @@ $LocalIp = (Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where $Doceditor = ($LocalIp + ":5013") $Login = ($LocalIp + ":5011") $Client = ($LocalIp + ":5001") +$Oauth = ($LocalIp + ":9090") $PortalUrl = ("http://" + $LocalIp) $ProxyVersion="v1.0.0" @@ -92,6 +93,7 @@ $Env:Baseimage_Proxy_Run="onlyoffice/4testing-docspace-proxy-runtime:$ProxyVersi $Env:SERVICE_DOCEDITOR=$Doceditor $Env:SERVICE_LOGIN=$Login $Env:SERVICE_CLIENT=$Client +$Env:SERVICE_OAUTH=$Oauth $Env:ROOT_DIR=$RootDir $Env:BUILD_PATH="/var/www" $Env:SRC_PATH="$RootDir\publish\services" @@ -105,6 +107,7 @@ Write-Host "LOCAL IP: $LocalIp" -ForegroundColor Blue Write-Host "SERVICE_DOCEDITOR: $Env:SERVICE_DOCEDITOR" -ForegroundColor Blue Write-Host "SERVICE_LOGIN: $Env:SERVICE_LOGIN" -ForegroundColor Blue Write-Host "SERVICE_CLIENT: $Env:SERVICE_CLIENT" -ForegroundColor Blue +Write-Host "SERVICE_OAUTH: $Env:SERVICE_OAUTH" -ForegroundColor Blue Write-Host "INSTALLATION_TYPE: $Env:INSTALLATION_TYPE" -ForegroundColor Blue Set-Location -Path $PSScriptRoot \ No newline at end of file diff --git a/build/install/docker/.env b/build/install/docker/.env index cb1d433c15..ae626f42ed 100644 --- a/build/install/docker/.env +++ b/build/install/docker/.env @@ -105,6 +105,7 @@ DOCEDITOR_HOST=${CONTAINER_PREFIX}doceditor LOGIN_HOST=${CONTAINER_PREFIX}login HELTHCHECKS_HOST=${CONTAINER_PREFIX}healthchecks + OAUTH_HOST=${CONTAINER_PREFIX}oauth # router upstream environment # SERVICE_API_SYSTEM=${API_SYSTEM_HOST}:${SERVICE_PORT} @@ -124,7 +125,8 @@ SERVICE_DOCEDITOR=${DOCEDITOR_HOST}:5013 SERVICE_LOGIN=${LOGIN_HOST}:5011 SERVICE_HELTHCHECKS=${HELTHCHECKS_HOST}:${SERVICE_PORT} - + SERVICE_OAUTH=${OAUTH_HOST}:9090 + NETWORK_NAME=${PRODUCT} COMPOSE_IGNORE_ORPHANS=True diff --git a/build/install/docker/Dockerfile b/build/install/docker/Dockerfile index 3bb935b739..b6d466d29e 100644 --- a/build/install/docker/Dockerfile +++ b/build/install/docker/Dockerfile @@ -176,6 +176,7 @@ RUN chown nginx:nginx /etc/nginx/* -R && \ sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ if [[ -z "${SERVICE_CLIENT}" ]] ; then sed -i 's/127.0.0.1:5001/$service_client/' /etc/nginx/conf.d/onlyoffice.conf; fi && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/Dockerfile.app b/build/install/docker/Dockerfile.app index da0fba648a..f207117f21 100644 --- a/build/install/docker/Dockerfile.app +++ b/build/install/docker/Dockerfile.app @@ -163,6 +163,7 @@ RUN sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice. sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/http:\/\/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/Dockerfile.runtime b/build/install/docker/Dockerfile.runtime index b10fa0aa6d..b6bbfa4110 100644 --- a/build/install/docker/Dockerfile.runtime +++ b/build/install/docker/Dockerfile.runtime @@ -120,6 +120,7 @@ RUN chown onlyoffice:onlyoffice /etc/nginx/* -R && \ sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5001/$service_client/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/config/nginx/templates/upstream.conf.template b/build/install/docker/config/nginx/templates/upstream.conf.template index 54e70d9b2a..49a6825c7a 100644 --- a/build/install/docker/config/nginx/templates/upstream.conf.template +++ b/build/install/docker/config/nginx/templates/upstream.conf.template @@ -48,6 +48,12 @@ map $SERVICE_API $service_api { default $SERVICE_API; } +map $SERVICE_OAUTH $service_oauth { + volatile; + "" 127.0.0.1:9090; + default $SERVICE_OAUTH; +} + map $SERVICE_STUDIO $service_studio { volatile; "" 127.0.0.1:5003; diff --git a/build/install/docker/docspace.profiles.yml b/build/install/docker/docspace.profiles.yml index feaa046128..f16c2bcfc2 100644 --- a/build/install/docker/docspace.profiles.yml +++ b/build/install/docker/docspace.profiles.yml @@ -261,6 +261,7 @@ services: - SERVICE_NOTIFY=${SERVICE_NOTIFY} - SERVICE_PEOPLE_SERVER=${SERVICE_PEOPLE_SERVER} - SERVICE_SOCKET=${SERVICE_SOCKET} + - SERVICE_OAUTH=${SERVICE_OAUTH} - SERVICE_STUDIO_NOTIFY=${SERVICE_STUDIO_NOTIFY} - SERVICE_API=${SERVICE_API} - SERVICE_API_SYSTEM=${SERVICE_API_SYSTEM} diff --git a/build/install/docker/docspace.yml b/build/install/docker/docspace.yml index 091b9a8395..8decb941fa 100644 --- a/build/install/docker/docspace.yml +++ b/build/install/docker/docspace.yml @@ -1,6 +1,5 @@ version: "3.8" -x-healthcheck: - &x-healthcheck +x-healthcheck: &x-healthcheck test: curl --fail http://127.0.0.1 || exit 1 interval: 60s retries: 5 @@ -64,48 +63,48 @@ services: image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup-background:${DOCKER_TAG}" container_name: ${BACKUP_BACKGRUOND_TASKS_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_BACKUP_BACKGRUOND_TASKS}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_BACKUP_BACKGRUOND_TASKS}/health/ || exit 1 onlyoffice-backup: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-backup:${DOCKER_TAG}" container_name: ${BACKUP_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_BACKUP}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_BACKUP}/health/ || exit 1 onlyoffice-clear-events: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-clear-events:${DOCKER_TAG}" container_name: ${CLEAR_EVENTS_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_CLEAR_EVENTS}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_CLEAR_EVENTS}/health/ || exit 1 onlyoffice-files: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files:${DOCKER_TAG}" container_name: ${FILES_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_FILES}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_FILES}/health/ || exit 1 onlyoffice-files-services: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-files-services:${DOCKER_TAG}" container_name: ${FILES_SERVICES_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_FILES_SERVICES}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_FILES_SERVICES}/health/ || exit 1 onlyoffice-people-server: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-people-server:${DOCKER_TAG}" container_name: ${PEOPLE_SERVER_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_PEOPLE_SERVER}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_PEOPLE_SERVER}/health/ || exit 1 onlyoffice-socket: <<: *x-service-base @@ -119,32 +118,32 @@ services: image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio-notify:${DOCKER_TAG}" container_name: ${STUDIO_NOTIFY_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_STUDIO_NOTIFY}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_STUDIO_NOTIFY}/health/ || exit 1 onlyoffice-api: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api:${DOCKER_TAG}" container_name: ${API_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_API}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_API}/health/ || exit 1 onlyoffice-api-system: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-api-system:${DOCKER_TAG}" container_name: ${API_SYSTEM_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_API_SYSTEM}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_API_SYSTEM}/health/ || exit 1 onlyoffice-studio: <<: *x-service-base image: "${REPO}/${DOCKER_IMAGE_PREFIX}-studio:${DOCKER_TAG}" container_name: ${STUDIO_HOST} healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_STUDIO}/health/ || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_STUDIO}/health/ || exit 1 onlyoffice-ssoauth: <<: *x-service-base @@ -161,8 +160,8 @@ services: expose: - "5013" healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_DOCEDITOR}/health || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_DOCEDITOR}/health || exit 1 onlyoffice-login: <<: *x-service-base @@ -171,16 +170,16 @@ services: expose: - "5011" healthcheck: - <<: *x-healthcheck - test: curl --fail http://${SERVICE_LOGIN}/health || exit 1 + <<: *x-healthcheck + test: curl --fail http://${SERVICE_LOGIN}/health || exit 1 onlyoffice-router: image: "${REPO}/${DOCKER_IMAGE_PREFIX}-router:${DOCKER_TAG}" container_name: ${ROUTER_HOST} restart: always healthcheck: - <<: *x-healthcheck - test: nginx -t || exit 1 + <<: *x-healthcheck + test: nginx -t || exit 1 expose: - "8081" - "8099" @@ -208,6 +207,7 @@ services: - SERVICE_NOTIFY=${SERVICE_NOTIFY} - SERVICE_PEOPLE_SERVER=${SERVICE_PEOPLE_SERVER} - SERVICE_SOCKET=${SERVICE_SOCKET} + - SERVICE_OAUTH=${SERVICE_OAUTH} - SERVICE_STUDIO_NOTIFY=${SERVICE_STUDIO_NOTIFY} - SERVICE_API=${SERVICE_API} - SERVICE_API_SYSTEM=${SERVICE_API_SYSTEM} diff --git a/build/start/start.backend.docker.ps1 b/build/start/start.backend.docker.ps1 index b864499a2a..74f37213c8 100644 --- a/build/start/start.backend.docker.ps1 +++ b/build/start/start.backend.docker.ps1 @@ -13,6 +13,7 @@ $LocalIp = (Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where $Doceditor = ($LocalIp + ":5013") $Login = ($LocalIp + ":5011") $Client = ($LocalIp + ":5001") +$Oauth = ($LocalIp + ":9090") Set-Location -Path $DockerDir @@ -25,6 +26,7 @@ $Env:DOCUMENT_SERVER_IMAGE_NAME="onlyoffice/documentserver-de:latest" $Env:SERVICE_DOCEDITOR=$Doceditor $Env:SERVICE_LOGIN=$Login $Env:SERVICE_CLIENT=$Client +$Env:SERVICE_OAUTH=$Oauth $Env:ROOT_DIR=$RootDir $Env:BUILD_PATH="/var/www" $Env:SRC_PATH="$RootDir\publish\services" diff --git a/config/nginx/onlyoffice.conf b/config/nginx/onlyoffice.conf index e35743d718..4a0ba719d9 100644 --- a/config/nginx/onlyoffice.conf +++ b/config/nginx/onlyoffice.conf @@ -265,10 +265,18 @@ server { } } + location /api/clients { + proxy_pass http://127.0.0.1:9090; + + proxy_set_header X-API-Version 1; + proxy_set_header X-Tenant 1; + } + location /sso { rewrite sso/(.*) /$1 break; proxy_pass http://127.0.0.1:9834; } + location ~* /(ssologin.ashx|login.ashx|storage) { proxy_pass http://127.0.0.1:5003; } From ebdffb55ea8c81c33de1b49eb55c447ff1faa231 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Fri, 22 Sep 2023 15:38:32 +0300 Subject: [PATCH 011/362] Update yarn.lock --- yarn.lock | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8ee1022b45..e46200ec61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3147,7 +3147,7 @@ __metadata: react-player: ^1.15.3 react-router: ^6.10.0 react-router-dom: ^6.10.0 - react-tooltip: 5.21.1 + react-tooltip: ^5.21.1 react-viewer: ^3.2.2 react-virtualized-auto-sizer: ^1.0.7 react-window: ^1.8.8 @@ -22258,19 +22258,6 @@ __metadata: languageName: node linkType: hard -"react-tooltip@npm:5.21.1": - version: 5.21.1 - resolution: "react-tooltip@npm:5.21.1" - dependencies: - "@floating-ui/dom": ^1.0.0 - classnames: ^2.3.0 - peerDependencies: - react: ">=16.14.0" - react-dom: ">=16.14.0" - checksum: 44fbe22169eecc12b32e401460997c3b26bae96f70c527260ad41b5015c2ead37b8f713e01737be2fb748ffbb7b6ee8c461a9f46b064c36e6b39a542aab1b852 - languageName: node - linkType: hard - "react-tooltip@npm:^5.21.1": version: 5.21.4 resolution: "react-tooltip@npm:5.21.4" From 8e751923d9f7e764d71b37075ce53c24c5af5492 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Fri, 22 Sep 2023 17:28:37 +0300 Subject: [PATCH 012/362] Web:OAuth2: add CRUD --- packages/client/src/store/OAuthStore.js | 39 +++++++++-- packages/client/src/store/index.js | 5 ++ packages/common/api/oauth/index.ts | 88 +++++++++++++++++++++++++ packages/common/utils/oauth/dto.ts | 45 +++++++++++++ packages/common/utils/oauth/enums.ts | 10 +++ 5 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 packages/common/api/oauth/index.ts create mode 100644 packages/common/utils/oauth/dto.ts create mode 100644 packages/common/utils/oauth/enums.ts diff --git a/packages/client/src/store/OAuthStore.js b/packages/client/src/store/OAuthStore.js index 207fa4431b..85452bf610 100644 --- a/packages/client/src/store/OAuthStore.js +++ b/packages/client/src/store/OAuthStore.js @@ -1,5 +1,14 @@ import { makeAutoObservable, runInAction } from "mobx"; +import { + addClient, + deleteClient, + getClient, + getClientList, + regenerateSecret, + updateClient, +} from "@docspace/common/api/oauth"; + const clients = [...Array(5)].map((value, index) => { return { enabled: true, @@ -41,8 +50,30 @@ class OAuthStore { makeAutoObservable(this); } - getClients = () => { + fetchClient = async (clientId) => { + await getClient(clientId); + }; + + fetchClients = async (page, limit) => { this.clients = clients; + + await getClientList(0, 20); + }; + + saveClient = async (client) => { + await addClient(client); + }; + + updateClient = async (clientId, client) => { + await updateClient(clientId, client); + }; + + regenerateSecret = async (clientId) => { + await regenerateSecret(clientId); + }; + + deleteClient = async (clientId) => { + await deleteClient(clientId); }; setCurrentClient = (client) => { @@ -59,9 +90,9 @@ class OAuthStore { this.clients[index].enabled = !this.clients[index].enabled; }; - deleteClient = (id) => { - this.clients = this.clients.filter((proj) => proj.id !== id); - }; + // deleteClient = (id) => { + // this.clients = this.clients.filter((proj) => proj.id !== id); + // }; editClient = (client) => { const index = this.clients.findIndex((proj) => proj.id === client.id); diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js index 3010af5f37..29a0d4d444 100644 --- a/packages/client/src/store/index.js +++ b/packages/client/src/store/index.js @@ -38,6 +38,10 @@ import PublicRoomStore from "./PublicRoomStore"; import WebhooksStore from "./WebhooksStore"; import ClientLoadingStore from "./ClientLoadingStore"; +import OAuthStore from "./OAuthStore"; + +const oauthStore = new OAuthStore(); + const oformsStore = new OformsStore(authStore); const selectedFolderStore = new SelectedFolderStore(authStore.settingsStore); @@ -223,6 +227,7 @@ const store = { webhooksStore, clientLoadingStore, publicRoomStore, + oauthStore, }; export default store; diff --git a/packages/common/api/oauth/index.ts b/packages/common/api/oauth/index.ts new file mode 100644 index 0000000000..ff9263bdae --- /dev/null +++ b/packages/common/api/oauth/index.ts @@ -0,0 +1,88 @@ +import axios, { AxiosRequestConfig } from "axios"; + +import { ClientDTO, ClientListDTO } from "../../utils/oauth/dto"; + +const axiosConfig: AxiosRequestConfig = { + baseURL: "/api", + responseType: "json", + timeout: 0, + withCredentials: true, + headers: { "X-API-Version": "1", "X-Tenant": "1" }, +}; + +const client = axios.create(axiosConfig); + +const request = (options: any): Promise => { + const onSuccess = (response: any) => { + return response.data; + }; + + const onError = (error: any) => { + return error; + }; + + return client(options).then(onSuccess).catch(onError); +}; + +export const getClient = async (clientId: string): Promise => { + const client: ClientDTO = await request({ + method: "get", + url: `/clients/${clientId}`, + }); + return client; +}; + +export const getClientList = async ( + page: number, + limit: number +): Promise => { + const clients: ClientListDTO = ( + await request({ + method: "get", + url: `/clients?page=${page}&limit=${limit}`, + }) + ).data; + + return clients; +}; + +export const addClient = async (data: ClientDTO): Promise => { + const client: ClientDTO = await request({ + method: "post", + url: `/clients`, + data, + }); + + return client; +}; + +export const updateClient = async ( + clientId: string, + data: ClientDTO +): Promise => { + const client: ClientDTO = await request({ + method: "put", + url: `/clients/${clientId}`, + data, + }); + + return client; +}; + +export const regenerateSecret = async (clientId: string): Promise => { + const clientSecret: string = ( + await request({ + method: "patch", + url: `/clients/${clientId}`, + }) + ).client_secret; + + return clientSecret; +}; + +export const deleteClient = async (clientId: string): Promise => { + await request({ + method: "delete", + url: `/clients/${clientId}`, + }); +}; diff --git a/packages/common/utils/oauth/dto.ts b/packages/common/utils/oauth/dto.ts new file mode 100644 index 0000000000..aba9d4422b --- /dev/null +++ b/packages/common/utils/oauth/dto.ts @@ -0,0 +1,45 @@ +import { OauthScopes } from "./enums"; + +export type ClientDTO = { + client_id: string; + client_secret: string; + description: string; + terms_url: string; + policy_url: string; + logo_url: string; + authenticationMethod: string; + redirect_uri: string; + logout_redirect_uri: string; + scopes: OauthScopes[]; + tenant: number; + invalidated?: boolean; +}; + +export type ClientListDTO = { + content: ClientDTO[]; + empty: boolean; + first: boolean; + last: true; + number: number; + numberOfElements: number; + pageable: { + offset: number; + pageNumber: number; + pageSize: number; + paged: boolean; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + unpaged: boolean; + }; + size: number; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + totalElements: number; + totalPages: number; +}; diff --git a/packages/common/utils/oauth/enums.ts b/packages/common/utils/oauth/enums.ts new file mode 100644 index 0000000000..6ccfd0d237 --- /dev/null +++ b/packages/common/utils/oauth/enums.ts @@ -0,0 +1,10 @@ +export const enum OauthScopes { + ReadFiles = "files:read", + WriteFiles = "files:write", + ReadRooms = "rooms:read", + WriteRooms = "rooms:write", + ReadAccount = "account.self:read", + WriteAccount = "account.self:write", + ReadAccounts = "accounts:read", + WriteAccounts = "accounts:write", +} From a56a46236c7401496de86638300fa3df1f2d580e Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Mon, 25 Sep 2023 10:09:24 +0300 Subject: [PATCH 013/362] Web:Client:PortalSettings: add OAuth page --- .../developer-tools/OAuth/OAuth.types.ts | 3 + .../categories/developer-tools/OAuth/index.js | 61 ------------------- .../developer-tools/OAuth/index.tsx | 10 +++ .../categories/developer-tools/index.js | 2 + packages/client/src/routes/portalSettings.js | 12 ++++ 5 files changed, 27 insertions(+), 61 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts delete mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts new file mode 100644 index 0000000000..cffe73e672 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts @@ -0,0 +1,3 @@ +export interface OAuthProps {} + +export interface OAuthStore {} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js deleted file mode 100644 index 1743bbc51d..0000000000 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { withTranslation } from "react-i18next"; -import styled from "styled-components"; -import Box from "@docspace/components/box"; -import TextInput from "@docspace/components/text-input"; -import Textarea from "@docspace/components/textarea"; -import Label from "@docspace/components/label"; -import Checkbox from "@docspace/components/checkbox"; -import Button from "@docspace/components/button"; -import ComboBox from "@docspace/components/combobox"; -import Heading from "@docspace/components/heading"; -import { inject, observer } from "mobx-react"; -import { isMobile } from "react-device-detect"; -import BreakpointWarning from "SRC_DIR/components/BreakpointWarning"; -import List from "./sub-components/List"; -import DeleteDialog from "./sub-components/DeleteDialog"; - -const OAuth = (props) => { - const { - t, - setDocumentTitle, - getClients, - deleteClient, - currentClient, - } = props; - - const [isDeleteOpened, setIsDeleteOpened] = useState(false); - - const closeDeleteModal = () => setIsDeleteOpened(false); - const openDeleteModal = () => setIsDeleteOpened(true); - - useEffect(() => getClients(), []); - - setDocumentTitle("OAuth"); - - return ( - <> - - - - ); -}; - -export default inject(({ setup, auth, oauthStore }) => { - const { settingsStore, setDocumentTitle } = auth; - const { getClients, deleteClient, currentClient } = oauthStore; - const { theme } = settingsStore; - - return { - theme, - setDocumentTitle, - getClients, - deleteClient, - currentClient, - }; -})(withTranslation(["Common"])(observer(OAuth))); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx new file mode 100644 index 0000000000..fed19365f2 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import { inject, observer } from "mobx-react"; + +const OAuth = ({}) => { + return
; +}; + +export default inject(({}) => { + return {}; +})(observer(OAuth)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js index a95e42339a..8243247011 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/index.js @@ -17,6 +17,7 @@ import { isMobile, isMobileOnly } from "react-device-detect"; import AppLoader from "@docspace/common/components/AppLoader"; import SSOLoader from "./sub-components/ssoLoader"; import { WebhookConfigsLoader } from "./Webhooks/sub-components/Loaders"; +import OAuth from "./OAuth"; const StyledSubmenu = styled(Submenu)` .sticky { @@ -75,6 +76,7 @@ const DeveloperToolsWrapper = (props) => { name: t("Webhooks:Webhooks"), content: , }, + { id: "oauth", name: "OAuth", content: }, ]; const [currentTab, setCurrentTab] = useState( diff --git a/packages/client/src/routes/portalSettings.js b/packages/client/src/routes/portalSettings.js index 3d5713a706..a5d5039314 100644 --- a/packages/client/src/routes/portalSettings.js +++ b/packages/client/src/routes/portalSettings.js @@ -298,6 +298,18 @@ const PortalSettingsRoutes = { path: "developer-tools/webhooks/:id/:eventId", element: , }, + { + path: "developer-tools/oauth", + element: , + }, + { + path: "developer-tools/oauth/create/:id", + element: , + }, + { + path: "developer-tools/oauth/edit/:id", + element: , + }, { path: "backup", element: , From 3b9c56c5f4674641867faef472712313517c9625 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Mon, 25 Sep 2023 17:02:28 +0300 Subject: [PATCH 014/362] Web:Common:OAuth: add new utils, new interfaces --- packages/common/api/oauth/index.ts | 70 +++++++++++++++++++------- packages/common/utils/oauth/dto.ts | 53 +++++++++++++++++++- packages/common/utils/oauth/index.ts | 73 ++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 packages/common/utils/oauth/index.ts diff --git a/packages/common/api/oauth/index.ts b/packages/common/api/oauth/index.ts index ff9263bdae..9998ce3277 100644 --- a/packages/common/api/oauth/index.ts +++ b/packages/common/api/oauth/index.ts @@ -1,6 +1,17 @@ import axios, { AxiosRequestConfig } from "axios"; -import { ClientDTO, ClientListDTO } from "../../utils/oauth/dto"; +import { + transformToClientProps, + transformToClientDTO, +} from "./../../utils/oauth/index"; + +import { + ClientDTO, + ClientListDTO, + ClientListProps, + ClientProps, + ScopeDTO, +} from "../../utils/oauth/dto"; const axiosConfig: AxiosRequestConfig = { baseURL: "/api", @@ -24,49 +35,56 @@ const request = (options: any): Promise => { return client(options).then(onSuccess).catch(onError); }; -export const getClient = async (clientId: string): Promise => { +export const getClient = async (clientId: string): Promise => { const client: ClientDTO = await request({ method: "get", url: `/clients/${clientId}`, }); - return client; + + return transformToClientProps(client); }; export const getClientList = async ( page: number, limit: number -): Promise => { - const clients: ClientListDTO = ( - await request({ - method: "get", - url: `/clients?page=${page}&limit=${limit}`, - }) - ).data; +): Promise => { + const { data }: { data: ClientListDTO } = await request({ + method: "get", + url: `/clients?page=${page}&limit=${limit}`, + }); + + const clients = { ...data, content: [] as ClientProps[] }; + + data.content.forEach((item) => { + const client = transformToClientProps(item); + + clients.content.push({ ...client }); + }); return clients; }; -export const addClient = async (data: ClientDTO): Promise => { +export const addClient = async (data: ClientProps): Promise => { const client: ClientDTO = await request({ method: "post", url: `/clients`, - data, + data: transformToClientDTO(data), }); - return client; + return transformToClientProps(client); }; export const updateClient = async ( clientId: string, - data: ClientDTO -): Promise => { + data: ClientProps +): Promise => { const client: ClientDTO = await request({ method: "put", url: `/clients/${clientId}`, - data, + data: transformToClientDTO(data), }); - return client; + return transformToClientProps(client); }; export const regenerateSecret = async (clientId: string): Promise => { @@ -86,3 +104,21 @@ export const deleteClient = async (clientId: string): Promise => { url: `/clients/${clientId}`, }); }; + +export const getScope = async (name: string): Promise => { + const scope: ScopeDTO = await request({ + method: "get", + url: `/scopes/${name}`, + }); + + return scope; +}; + +export const getScopeList = async (): Promise => { + const scopeList: ScopeDTO[] = await request({ + method: "get", + url: `/scopes`, + }); + + return scopeList; +}; diff --git a/packages/common/utils/oauth/dto.ts b/packages/common/utils/oauth/dto.ts index aba9d4422b..19418130a3 100644 --- a/packages/common/utils/oauth/dto.ts +++ b/packages/common/utils/oauth/dto.ts @@ -1,4 +1,23 @@ -import { OauthScopes } from "./enums"; +export type ScopeDTO = { + name: string; + description: string; +}; + +export interface ClientProps { + clientId: string; + secret: string; + description: string; + termsUrl: string; + policyUrl: string; + logoUrl: string; + authenticationMethod: string; + redirectUri: string; + logoutRedirectUri: string; + scopes: string[]; + tenant: number; + invalidated?: boolean; + name: string; +} export type ClientDTO = { client_id: string; @@ -10,11 +29,41 @@ export type ClientDTO = { authenticationMethod: string; redirect_uri: string; logout_redirect_uri: string; - scopes: OauthScopes[]; + scopes: string[]; tenant: number; invalidated?: boolean; + name: string; }; +export interface ClientListProps { + content: ClientProps[]; + empty: boolean; + first: boolean; + last: true; + number: number; + numberOfElements: number; + pageable: { + offset: number; + pageNumber: number; + pageSize: number; + paged: boolean; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + unpaged: boolean; + }; + size: number; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + totalElements: number; + totalPages: number; +} + export type ClientListDTO = { content: ClientDTO[]; empty: boolean; diff --git a/packages/common/utils/oauth/index.ts b/packages/common/utils/oauth/index.ts new file mode 100644 index 0000000000..2671e09316 --- /dev/null +++ b/packages/common/utils/oauth/index.ts @@ -0,0 +1,73 @@ +import { ClientDTO, ClientProps } from "./dto"; + +export const transformToClientProps = (clientDto: ClientDTO): ClientProps => { + const { + client_id, + client_secret, + description, + terms_url, + policy_url, + logo_url, + authenticationMethod, + redirect_uri, + logout_redirect_uri, + scopes, + tenant, + invalidated, + name, + } = clientDto; + + const client: ClientProps = { + clientId: client_id, + secret: client_secret, + description, + termsUrl: terms_url, + policyUrl: policy_url, + logoUrl: logo_url, + authenticationMethod, + redirectUri: redirect_uri, + logoutRedirectUri: logout_redirect_uri, + scopes, + tenant, + invalidated, + name, + }; + + return client; +}; + +export const transformToClientDTO = (clientProps: ClientProps): ClientDTO => { + const { + clientId: client_id, + secret: client_secret, + description, + termsUrl: terms_url, + policyUrl: policy_url, + logoUrl: logo_url, + authenticationMethod, + redirectUri: redirect_uri, + logoutRedirectUri: logout_redirect_uri, + scopes, + tenant, + invalidated, + name, + } = clientProps; + + const client: ClientDTO = { + client_id, + client_secret, + description, + terms_url, + policy_url, + logo_url, + authenticationMethod, + redirect_uri, + logout_redirect_uri, + scopes, + tenant, + invalidated, + name, + }; + + return client; +}; From dc1274fb88992ac3a8884818586e368bc25c2aaa Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Mon, 25 Sep 2023 17:03:25 +0300 Subject: [PATCH 015/362] Web:Client:PortalSettings: add OAuth empty page --- packages/client/public/locales/en/OAuth.json | 8 +++++ .../EmptyScreen/EmptyScreen.types.ts | 3 ++ .../sub-components/EmptyScreen/index.tsx | 23 ++++++++++++ .../RegisterNewButton.types.ts | 3 ++ .../RegisterNewButton/index.tsx | 27 ++++++++++++++ public/images/empty_screen_oauth.svg | 35 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 packages/client/public/locales/en/OAuth.json create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/EmptyScreen.types.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/index.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/RegisterNewButton.types.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/index.tsx create mode 100644 public/images/empty_screen_oauth.svg diff --git a/packages/client/public/locales/en/OAuth.json b/packages/client/public/locales/en/OAuth.json new file mode 100644 index 0000000000..dc3e1aec61 --- /dev/null +++ b/packages/client/public/locales/en/OAuth.json @@ -0,0 +1,8 @@ +{ + "OAuth": "OAuth", + "NoOAuthAppHeader": "No OAuth applications", + "NoOAuthAppDescription": "OAuth applications are used to access the ONLYOFFICE DocSpace API", + "RegisterNewApp": "Register a new application", + "NewApp": "New application", + "EditApp": "Edit application" +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/EmptyScreen.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/EmptyScreen.types.ts new file mode 100644 index 0000000000..8d8e9043b8 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/EmptyScreen.types.ts @@ -0,0 +1,3 @@ +export interface EmptyScreenProps { + t: any; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/index.tsx new file mode 100644 index 0000000000..9f239763b4 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/EmptyScreen/index.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +// @ts-ignore +import EmptyScreenContainer from "@docspace/components/empty-screen-container"; + +import EmptyScreenOauthSvgUrl from "PUBLIC_DIR/images/empty_screen_oauth.svg?url"; + +import RegisterNewButton from "../RegisterNewButton"; + +import { EmptyScreenProps } from "./EmptyScreen.types"; +const OAuthEmptyScreen = ({ t }: EmptyScreenProps) => { + return ( + } + /> + ); +}; + +export default OAuthEmptyScreen; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/RegisterNewButton.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/RegisterNewButton.types.ts new file mode 100644 index 0000000000..fa37b11113 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/RegisterNewButton.types.ts @@ -0,0 +1,3 @@ +export interface RegisterNewButtonProps { + t: any; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/index.tsx new file mode 100644 index 0000000000..38e89981f5 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/RegisterNewButton/index.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { isMobile } from "react-device-detect"; + +import Button from "@docspace/components/button"; + +import { RegisterNewButtonProps } from "./RegisterNewButton.types"; + +const RegisterNewButton = ({ t }: RegisterNewButtonProps) => { + const navigate = useNavigate(); + + const onClick = () => { + navigate("create"); + }; + + return ( + + +
+ +
+ + + +
+
+

+ + Your consent to provide access is required. +
If you do not approve, click Cancel, in which case no information will be shared with the app. +
+

+
+
+ + + \ No newline at end of file diff --git a/common/ASC.OAuth/authorization/src/main/resources/templates/login.html b/common/ASC.OAuth/authorization/src/main/resources/templates/login.html new file mode 100644 index 0000000000..233509ef52 --- /dev/null +++ b/common/ASC.OAuth/authorization/src/main/resources/templates/login.html @@ -0,0 +1,70 @@ + + + + + Login System + + + +
+ + \ No newline at end of file From 8ee516850bde0d4c291ba4a5bf6d9b30b163c993 Mon Sep 17 00:00:00 2001 From: Dmitrii Vershinin Date: Wed, 27 Sep 2023 18:14:21 +0500 Subject: [PATCH 025/362] fix: use server side templates --- .../ApplicationConfiguration.java | 7 +------ .../AuthorizationServerConfiguration.java | 13 ------------ .../AuthorizationConsentController.java | 20 ++++++------------ .../controllers/LoginController.java | 21 ++++++++++++++----- 4 files changed, 23 insertions(+), 38 deletions(-) diff --git a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java index bda44dd866..7f61bb9148 100644 --- a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java +++ b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/ApplicationConfiguration.java @@ -77,12 +77,7 @@ public class ApplicationConfiguration { .invalidateHttpSession(true) .deleteCookies("JSESSIONID") ) - .csrf(c -> { - c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); - c.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()); - }) - .addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class) - .addFilterAfter(new SimpleCORSFilter(), BasicAuthenticationFilter.class) + .build(); } } diff --git a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java index 8356f973f4..fb1dee9bf4 100644 --- a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java +++ b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/configuration/AuthorizationServerConfiguration.java @@ -3,8 +3,6 @@ package com.onlyoffice.authorization.configuration; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; -import com.onlyoffice.authorization.extensions.filters.CookieCsrfFilter; -import com.onlyoffice.authorization.extensions.filters.SimpleCORSFilter; import com.onlyoffice.authorization.extensions.jwks.JwksKeyPairGenerator; import com.onlyoffice.authorization.extensions.providers.DocspaceAuthenticationProvider; import jakarta.servlet.RequestDispatcher; @@ -16,7 +14,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; @@ -30,9 +27,6 @@ import org.springframework.security.oauth2.server.authorization.settings.ClientS import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import org.springframework.security.web.csrf.CookieCsrfTokenRepository; -import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import java.security.NoSuchAlgorithmException; @@ -62,13 +56,6 @@ public class AuthorizationServerConfiguration { dispatcher.forward(request, response); }, new AntPathRequestMatcher(applicationConfiguration.getLogin()))); - http.csrf(c -> { - c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); - c.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()); - }); - http.addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class); - http.addFilterAfter(new SimpleCORSFilter(), BasicAuthenticationFilter.class); - return http.build(); } diff --git a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java index 76eb06f190..82930dc0d4 100644 --- a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java +++ b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/AuthorizationConsentController.java @@ -56,20 +56,12 @@ public class AuthorizationConsentController { } } - String url = String.format( - "redirect:%s/consent?clientId=%s&state=%s&principalName=%s", - configuration.getFrontendUrl(), - clientId, - state, - principal.getName() - ); + model.addAttribute("clientId", clientId); + model.addAttribute("state", state); + model.addAttribute("scopes", scopesToApprove); + model.addAttribute("previouslyApprovedScopes", previouslyApprovedScopes); + model.addAttribute("principalName", principal.getName()); - if (scope.length() > 0) - url += String.format("&scopes=%s", String.join(",", scopesToApprove)); - - if (previouslyApprovedScopes.size() > 0) - url += String.format("&previouslyApprovedScopes=%s", String.join(",", previouslyApprovedScopes)); - - return url; + return "consent"; } } diff --git a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java index a87ca5f147..362b98d622 100644 --- a/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java +++ b/common/ASC.OAuth/authorization/src/main/java/com/onlyoffice/authorization/controllers/LoginController.java @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; @Controller @RequiredArgsConstructor @@ -18,10 +19,20 @@ public class LoginController { public String login(HttpServletRequest request) { log.debug("A new login request"); if (request.getDispatcherType().name() == null || !request.getDispatcherType().name().equals(FORWARD)) - return String.format("redirect:%s/error", configuration.getFrontendUrl()); - return String.format( - "redirect:%s/login?%s", - configuration.getFrontendUrl(), - request.getQueryString()); + return "error"; + return "login"; + } + + @GetMapping("/authorized") + public String authorized( + @RequestParam(name = "error", required = false) String error, + @RequestParam(name = "error_description", required = false) String description + ) { + log.debug("Authorized redirect"); + if (error != null && !error.isBlank() && description != null && !description.isBlank()) { + log.debug("Authorization error has occurred {} - {}", error, description); + return "error"; + } + return "authorized"; } } \ No newline at end of file From 2381fcf68fb023cec798929283af434231504095 Mon Sep 17 00:00:00 2001 From: Dmitrii Vershinin Date: Wed, 27 Sep 2023 18:14:30 +0500 Subject: [PATCH 026/362] chore: remove react client --- common/ASC.OAuth/client/.gitignore | 23 - common/ASC.OAuth/client/README.md | 70 - common/ASC.OAuth/client/package.json | 41 - common/ASC.OAuth/client/public/favicon.ico | Bin 3870 -> 0 bytes common/ASC.OAuth/client/public/index.html | 22 - common/ASC.OAuth/client/src/App.jsx | 38 - common/ASC.OAuth/client/src/Consent.jsx | 144 - common/ASC.OAuth/client/src/Error.jsx | 7 - common/ASC.OAuth/client/src/Login.jsx | 86 - common/ASC.OAuth/client/src/index.css | 10 - common/ASC.OAuth/client/src/index.jsx | 17 - .../ASC.OAuth/client/src/reportWebVitals.js | 13 - common/ASC.OAuth/client/yarn.lock | 13788 ---------------- 13 files changed, 14259 deletions(-) delete mode 100644 common/ASC.OAuth/client/.gitignore delete mode 100644 common/ASC.OAuth/client/README.md delete mode 100644 common/ASC.OAuth/client/package.json delete mode 100644 common/ASC.OAuth/client/public/favicon.ico delete mode 100644 common/ASC.OAuth/client/public/index.html delete mode 100644 common/ASC.OAuth/client/src/App.jsx delete mode 100644 common/ASC.OAuth/client/src/Consent.jsx delete mode 100644 common/ASC.OAuth/client/src/Error.jsx delete mode 100644 common/ASC.OAuth/client/src/Login.jsx delete mode 100644 common/ASC.OAuth/client/src/index.css delete mode 100644 common/ASC.OAuth/client/src/index.jsx delete mode 100644 common/ASC.OAuth/client/src/reportWebVitals.js delete mode 100644 common/ASC.OAuth/client/yarn.lock diff --git a/common/ASC.OAuth/client/.gitignore b/common/ASC.OAuth/client/.gitignore deleted file mode 100644 index 4d29575de8..0000000000 --- a/common/ASC.OAuth/client/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/common/ASC.OAuth/client/README.md b/common/ASC.OAuth/client/README.md deleted file mode 100644 index 58beeaccd8..0000000000 --- a/common/ASC.OAuth/client/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. - -The page will reload when you make changes.\ -You may also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - -### Advanced Configuration - -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) - -### Deployment - -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) - -### `npm run build` fails to minify - -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/common/ASC.OAuth/client/package.json b/common/ASC.OAuth/client/package.json deleted file mode 100644 index 9a212540d8..0000000000 --- a/common/ASC.OAuth/client/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "client", - "version": "0.1.0", - "private": true, - "dependencies": { - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "axios": "^1.4.0", - "react": "^18.2.0", - "react-cookie": "^5.0.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.15.0", - "react-scripts": "5.0.1", - "web-vitals": "^2.1.4" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/common/ASC.OAuth/client/public/favicon.ico b/common/ASC.OAuth/client/public/favicon.ico deleted file mode 100644 index a11777cc471a4344702741ab1c8a588998b1311a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3870 zcma);c{J4h9>;%nil|2-o+rCuEF-(I%-F}ijC~o(k~HKAkr0)!FCj~d>`RtpD?8b; zXOC1OD!V*IsqUwzbMF1)-gEDD=A573Z-&G7^LoAC9|WO7Xc0Cx1g^Zu0u_SjAPB3vGa^W|sj)80f#V0@M_CAZTIO(t--xg= z!sii`1giyH7EKL_+Wi0ab<)&E_0KD!3Rp2^HNB*K2@PHCs4PWSA32*-^7d{9nH2_E zmC{C*N*)(vEF1_aMamw2A{ZH5aIDqiabnFdJ|y0%aS|64E$`s2ccV~3lR!u<){eS` z#^Mx6o(iP1Ix%4dv`t@!&Za-K@mTm#vadc{0aWDV*_%EiGK7qMC_(`exc>-$Gb9~W!w_^{*pYRm~G zBN{nA;cm^w$VWg1O^^<6vY`1XCD|s_zv*g*5&V#wv&s#h$xlUilPe4U@I&UXZbL z0)%9Uj&@yd03n;!7do+bfixH^FeZ-Ema}s;DQX2gY+7g0s(9;`8GyvPY1*vxiF&|w z>!vA~GA<~JUqH}d;DfBSi^IT*#lrzXl$fNpq0_T1tA+`A$1?(gLb?e#0>UELvljtQ zK+*74m0jn&)5yk8mLBv;=@}c{t0ztT<v;Avck$S6D`Z)^c0(jiwKhQsn|LDRY&w(Fmi91I7H6S;b0XM{e zXp0~(T@k_r-!jkLwd1_Vre^v$G4|kh4}=Gi?$AaJ)3I+^m|Zyj#*?Kp@w(lQdJZf4 z#|IJW5z+S^e9@(6hW6N~{pj8|NO*>1)E=%?nNUAkmv~OY&ZV;m-%?pQ_11)hAr0oAwILrlsGawpxx4D43J&K=n+p3WLnlDsQ$b(9+4 z?mO^hmV^F8MV{4Lx>(Q=aHhQ1){0d*(e&s%G=i5rq3;t{JC zmgbn5Nkl)t@fPH$v;af26lyhH!k+#}_&aBK4baYPbZy$5aFx4}ka&qxl z$=Rh$W;U)>-=S-0=?7FH9dUAd2(q#4TCAHky!$^~;Dz^j|8_wuKc*YzfdAht@Q&ror?91Dm!N03=4=O!a)I*0q~p0g$Fm$pmr$ zb;wD;STDIi$@M%y1>p&_>%?UP($15gou_ue1u0!4(%81;qcIW8NyxFEvXpiJ|H4wz z*mFT(qVx1FKufG11hByuX%lPk4t#WZ{>8ka2efjY`~;AL6vWyQKpJun2nRiZYDij$ zP>4jQXPaP$UC$yIVgGa)jDV;F0l^n(V=HMRB5)20V7&r$jmk{UUIe zVjKroK}JAbD>B`2cwNQ&GDLx8{pg`7hbA~grk|W6LgiZ`8y`{Iq0i>t!3p2}MS6S+ zO_ruKyAElt)rdS>CtF7j{&6rP-#c=7evGMt7B6`7HG|-(WL`bDUAjyn+k$mx$CH;q2Dz4x;cPP$hW=`pFfLO)!jaCL@V2+F)So3}vg|%O*^T1j>C2lx zsURO-zIJC$^$g2byVbRIo^w>UxK}74^TqUiRR#7s_X$e)$6iYG1(PcW7un-va-S&u zHk9-6Zn&>T==A)lM^D~bk{&rFzCi35>UR!ZjQkdSiNX*-;l4z9j*7|q`TBl~Au`5& z+c)*8?#-tgUR$Zd%Q3bs96w6k7q@#tUn`5rj+r@_sAVVLqco|6O{ILX&U-&-cbVa3 zY?ngHR@%l{;`ri%H*0EhBWrGjv!LE4db?HEWb5mu*t@{kv|XwK8?npOshmzf=vZA@ zVSN9sL~!sn?r(AK)Q7Jk2(|M67Uy3I{eRy z_l&Y@A>;vjkWN5I2xvFFTLX0i+`{qz7C_@bo`ZUzDugfq4+>a3?1v%)O+YTd6@Ul7 zAfLfm=nhZ`)P~&v90$&UcF+yXm9sq!qCx3^9gzIcO|Y(js^Fj)Rvq>nQAHI92ap=P z10A4@prk+AGWCb`2)dQYFuR$|H6iDE8p}9a?#nV2}LBCoCf(Xi2@szia7#gY>b|l!-U`c}@ zLdhvQjc!BdLJvYvzzzngnw51yRYCqh4}$oRCy-z|v3Hc*d|?^Wj=l~18*E~*cR_kU z{XsxM1i{V*4GujHQ3DBpl2w4FgFR48Nma@HPgnyKoIEY-MqmMeY=I<%oG~l!f<+FN z1ZY^;10j4M4#HYXP zw5eJpA_y(>uLQ~OucgxDLuf}fVs272FaMxhn4xnDGIyLXnw>Xsd^J8XhcWIwIoQ9} z%FoSJTAGW(SRGwJwb=@pY7r$uQRK3Zd~XbxU)ts!4XsJrCycrWSI?e!IqwqIR8+Jh zlRjZ`UO1I!BtJR_2~7AbkbSm%XQqxEPkz6BTGWx8e}nQ=w7bZ|eVP4?*Tb!$(R)iC z9)&%bS*u(lXqzitAN)Oo=&Ytn>%Hzjc<5liuPi>zC_nw;Z0AE3Y$Jao_Q90R-gl~5 z_xAb2J%eArrC1CN4G$}-zVvCqF1;H;abAu6G*+PDHSYFx@Tdbfox*uEd3}BUyYY-l zTfEsOqsi#f9^FoLO;ChK<554qkri&Av~SIM*{fEYRE?vH7pTAOmu2pz3X?Wn*!ROX ztd54huAk&mFBemMooL33RV-*1f0Q3_(7hl$<#*|WF9P!;r;4_+X~k~uKEqdzZ$5Al zV63XN@)j$FN#cCD;ek1R#l zv%pGrhB~KWgoCj%GT?%{@@o(AJGt*PG#l3i>lhmb_twKH^EYvacVY-6bsCl5*^~L0 zonm@lk2UvvTKr2RS%}T>^~EYqdL1q4nD%0n&Xqr^cK^`J5W;lRRB^R-O8b&HENO||mo0xaD+S=I8RTlIfVgqN@SXDr2&-)we--K7w= zJVU8?Z+7k9dy;s;^gDkQa`0nz6N{T?(A&Iz)2!DEecLyRa&FI!id#5Z7B*O2=PsR0 zEvc|8{NS^)!d)MDX(97Xw}m&kEO@5jqRaDZ!+%`wYOI<23q|&js`&o4xvjP7D_xv@ z5hEwpsp{HezI9!~6O{~)lLR@oF7?J7i>1|5a~UuoN=q&6N}EJPV_GD`&M*v8Y`^2j zKII*d_@Fi$+i*YEW+Hbzn{iQk~yP z>7N{S4)r*!NwQ`(qcN#8SRQsNK6>{)X12nbF`*7#ecO7I)Q$uZsV+xS4E7aUn+U(K baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ diff --git a/common/ASC.OAuth/client/public/index.html b/common/ASC.OAuth/client/public/index.html deleted file mode 100644 index 3286290496..0000000000 --- a/common/ASC.OAuth/client/public/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - React App - - - -
- - diff --git a/common/ASC.OAuth/client/src/App.jsx b/common/ASC.OAuth/client/src/App.jsx deleted file mode 100644 index 62657e63a8..0000000000 --- a/common/ASC.OAuth/client/src/App.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import { - createBrowserRouter, - RouterProvider, -} from "react-router-dom"; -import { CookiesProvider } from "react-cookie"; - -import Login from "./Login"; -import Consent from "./Consent"; -import Error from "./Error"; - -const router = createBrowserRouter([ - { - path: "/", - element:
Home
- }, - { - path: "/login", - element: , - }, - { - path: "/consent", - element: - }, - { - path: "/error", - element: - } -]); - -function App() { - return ( - - - - ); -}; - -export default App; diff --git a/common/ASC.OAuth/client/src/Consent.jsx b/common/ASC.OAuth/client/src/Consent.jsx deleted file mode 100644 index a37db6ffec..0000000000 --- a/common/ASC.OAuth/client/src/Consent.jsx +++ /dev/null @@ -1,144 +0,0 @@ -import React from "react"; -import { useSearchParams } from "react-router-dom"; -import { useCookies } from 'react-cookie'; - -export default function Consent() { - const [searchParams] = useSearchParams(); - const [cookies] = useCookies(['XSRF-TOKEN']); - const clientId = searchParams.get("clientId") || ""; - const principalName = searchParams.get("principalName") || ""; - const state = searchParams.get("state") || ""; - const scopes = searchParams.get("scopes").split(",") || []; - const previouslyApprovedScopes = searchParams.get("previouslyApprovedScopes") ? searchParams.get("previouslyApprovedScopes").split(",") : []; - - const approve = async () => { - const formData = new FormData(); - formData.append("client_id", clientId); - formData.append("state", state); - scopes.forEach(scope => { - formData.append("scope", scope); - }); - const resp = await fetch(`${process.env.REACT_APP_AUTHORIZATION_SERVER}/oauth2/authorize`, { - method: 'POST', - body: formData, - headers: { - 'X-XSRF-TOKEN': cookies['XSRF-TOKEN'], - }, - credentials: "include", - redirect: "follow" - }); - - if (resp.redirected) - window.location.href = resp.url; - } - - // TODO: Loader, error page and so on - return ( -
-
-

App permissions

-
-
-
-

- - The application - - {clientId} - - wants to access your account - - {principalName} -

-
-
-
-
-

- The following permissions are requested by the above app. -
- Please review these and consent if you approve. -

-
-
-
-
-
- - - {scopes.length > 0 && ( -
- {scopes.map((scope) => (<> - - {scope} - - ))} -
- )} - {previouslyApprovedScopes.length > 0 && ( - <> -

- You have already granted the following permissions to the - above app: -

- {previouslyApprovedScopes.map((scope) => ( - <> -
- - {scope} - -
- - ))} - - )} -
- -
-
- -
-
-
-
-
-
-

- - Your consent to provide access is required. -
- If you do not approve, click Cancel, in which case no information - will be shared with the app. -
-

-
-
-
- ); -} - -/* -FORMDATA - -client_id: fc8482ff-b1e4-4397-8a48-13b88f3c25fe -state: huIv-Dc0E01S_lGYPbjXAdSz4Fo5r3pA4eFhaU5G23I= -scope: accounts:read -*/ diff --git a/common/ASC.OAuth/client/src/Error.jsx b/common/ASC.OAuth/client/src/Error.jsx deleted file mode 100644 index 407d83bc84..0000000000 --- a/common/ASC.OAuth/client/src/Error.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export default function Error() { - return ( -
Error
- ) -}; \ No newline at end of file diff --git a/common/ASC.OAuth/client/src/Login.jsx b/common/ASC.OAuth/client/src/Login.jsx deleted file mode 100644 index f7fee73453..0000000000 --- a/common/ASC.OAuth/client/src/Login.jsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useState } from "react"; -import axios from "axios"; -import { useSearchParams } from "react-router-dom"; -import { useCookies } from 'react-cookie'; - -export default function Login() { - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [searchParams, setSearchParams] = useSearchParams(); - const [cookies] = useCookies(['XSRF-TOKEN']); - - const login = async () => { - const formData = new FormData(); - formData.append("username", username); - formData.append("password", password); - formData.append("_csrf", cookies['XSRF-TOKEN']); - await fetch(`${process.env.REACT_APP_AUTHORIZATION_SERVER}/login?${searchParams.toString()}`, { - method: 'POST', - body: formData, - headers: { - 'X-XSRF-TOKEN': cookies['XSRF-TOKEN'], - }, - credentials: "include", - redirect: "manual" - }); - - window.location.href = `${process.env.REACT_APP_AUTHORIZATION_SERVER}/oauth2/authorize?${searchParams.toString()}&continue`; - } - - return ( -
-
-
- {searchParams.get("error") && ( -
-
Invalid Email or Password
-
- )} - {searchParams.get("logout") && ( -
-
You have been logged out.
-
- )} -
-
-

Login Form

-
-
-
-
- - setUsername(e.target.value)} - /> -
-
- - setPassword(e.target.value)} - /> -
-
- -
-
-
-
-
-
-
- ); -} diff --git a/common/ASC.OAuth/client/src/index.css b/common/ASC.OAuth/client/src/index.css deleted file mode 100644 index 5a81df5468..0000000000 --- a/common/ASC.OAuth/client/src/index.css +++ /dev/null @@ -1,10 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/common/ASC.OAuth/client/src/index.jsx b/common/ASC.OAuth/client/src/index.jsx deleted file mode 100644 index 62553e66e6..0000000000 --- a/common/ASC.OAuth/client/src/index.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; - -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -import './index.css'; - -const root = ReactDOM.createRoot(document.getElementById('root')); - -root.render( - - - -); - -reportWebVitals(); diff --git a/common/ASC.OAuth/client/src/reportWebVitals.js b/common/ASC.OAuth/client/src/reportWebVitals.js deleted file mode 100644 index 5253d3ad9e..0000000000 --- a/common/ASC.OAuth/client/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/common/ASC.OAuth/client/yarn.lock b/common/ASC.OAuth/client/yarn.lock deleted file mode 100644 index 461234bba7..0000000000 --- a/common/ASC.OAuth/client/yarn.lock +++ /dev/null @@ -1,13788 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 6 - cacheKey: 8 - -"@aashutoshrathi/word-wrap@npm:^1.2.3": - version: 1.2.6 - resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" - checksum: ada901b9e7c680d190f1d012c84217ce0063d8f5c5a7725bb91ec3c5ed99bb7572680eb2d2938a531ccbaec39a95422fcd8a6b4a13110c7d98dd75402f66a0cd - languageName: node - linkType: hard - -"@adobe/css-tools@npm:^4.0.1": - version: 4.3.1 - resolution: "@adobe/css-tools@npm:4.3.1" - checksum: ad43456379ff391132aff687ece190cb23ea69395e23c9b96690eeabe2468da89a4aaf266e4f8b6eaab53db3d1064107ce0f63c3a974e864f4a04affc768da3f - languageName: node - linkType: hard - -"@alloc/quick-lru@npm:^5.2.0": - version: 5.2.0 - resolution: "@alloc/quick-lru@npm:5.2.0" - checksum: bdc35758b552bcf045733ac047fb7f9a07c4678b944c641adfbd41f798b4b91fffd0fdc0df2578d9b0afc7b4d636aa6e110ead5d6281a2adc1ab90efd7f057f8 - languageName: node - linkType: hard - -"@ampproject/remapping@npm:^2.2.0": - version: 2.2.1 - resolution: "@ampproject/remapping@npm:2.2.1" - dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 - languageName: node - linkType: hard - -"@apideck/better-ajv-errors@npm:^0.3.1": - version: 0.3.6 - resolution: "@apideck/better-ajv-errors@npm:0.3.6" - dependencies: - json-schema: ^0.4.0 - jsonpointer: ^5.0.0 - leven: ^3.1.0 - peerDependencies: - ajv: ">=8" - checksum: b70ec9aae3b30ba1ac06948e585cd96aabbfe7ef6a1c27dc51e56c425f01290a58e9beb19ed95ee64da9f32df3e9276cd1ea58e78792741d74a519cb56955491 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.8.3": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" - dependencies: - "@babel/highlight": ^7.22.13 - chalk: ^2.4.2 - checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.22.20, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": - version: 7.22.20 - resolution: "@babel/compat-data@npm:7.22.20" - checksum: efedd1d18878c10fde95e4d82b1236a9aba41395ef798cbb651f58dbf5632dbff475736c507b8d13d4c8f44809d41c0eb2ef0d694283af9ba5dd8339b6dab451 - languageName: node - linkType: hard - -"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": - version: 7.22.20 - resolution: "@babel/core@npm:7.22.20" - dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.13 - "@babel/generator": ^7.22.15 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-module-transforms": ^7.22.20 - "@babel/helpers": ^7.22.15 - "@babel/parser": ^7.22.16 - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.22.20 - "@babel/types": ^7.22.19 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.3 - semver: ^6.3.1 - checksum: 73663a079194b5dc406b2e2e5e50db81977d443e4faf7ef2c27e5836cd9a359e81e551115193dc9b1a93471275351a972e54904f4d3aa6cb156f51e26abf6765 - languageName: node - linkType: hard - -"@babel/eslint-parser@npm:^7.16.3": - version: 7.22.15 - resolution: "@babel/eslint-parser@npm:7.22.15" - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1 - eslint-visitor-keys: ^2.1.0 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.11.0 - eslint: ^7.5.0 || ^8.0.0 - checksum: efdc749164a40de1b68e3ed395f441dfb7864c85d0a2ee3e4bc4f06dd0b7f675acb9be97cdc9025b88b3e80d38749a2b30e392ce7f6a79313c3aaf82ba8ccd68 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.22.15, @babel/generator@npm:^7.7.2": - version: 7.22.15 - resolution: "@babel/generator@npm:7.22.15" - dependencies: - "@babel/types": ^7.22.15 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 5b2a3ccdc3634f6ea86e0a442722bcd430238369432d31f15b428a4ee8013c2f4f917b5b135bf4fc1d0a3e2f87f10fd4ce5d07955ecc2d3b9400a05c2a481374 - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: 53da330f1835c46f26b7bf4da31f7a496dee9fd8696cca12366b94ba19d97421ce519a74a837f687749318f94d1a37f8d1abcbf35e8ed22c32d16373b2f6198d - languageName: node - linkType: hard - -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" - dependencies: - "@babel/types": ^7.22.15 - checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6": - version: 7.22.15 - resolution: "@babel/helper-compilation-targets@npm:7.22.15" - dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.15 - browserslist: ^4.21.9 - lru-cache: ^5.1.1 - semver: ^6.3.1 - checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-member-expression-to-functions": ^7.22.15 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 52c500d8d164abb3a360b1b7c4b8fff77bc4a5920d3a2b41ae6e1d30617b0dc0b972c1f5db35b1752007e04a748908b4a99bc872b73549ae837e87dcdde005a3 - languageName: node - linkType: hard - -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - regexpu-core: ^5.3.1 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6 - languageName: node - linkType: hard - -"@babel/helper-define-polyfill-provider@npm:^0.4.2": - version: 0.4.2 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.2" - dependencies: - "@babel/helper-compilation-targets": ^7.22.6 - "@babel/helper-plugin-utils": ^7.22.5 - debug: ^4.1.1 - lodash.debounce: ^4.0.8 - resolve: ^1.14.2 - peerDependencies: - "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 1f6dec0c5d0876d278fe15b71238eccc5f74c4e2efa2c78aaafa8bc2cc96336b8e68d94cd1a78497356c96e8b91b8c1f4452179820624d1702aee2f9832e6569 - languageName: node - linkType: hard - -"@babel/helper-environment-visitor@npm:^7.22.20, @babel/helper-environment-visitor@npm:^7.22.5": - version: 7.22.20 - resolution: "@babel/helper-environment-visitor@npm:7.22.20" - checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-function-name@npm:7.22.5" - dependencies: - "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a - languageName: node - linkType: hard - -"@babel/helper-hoist-variables@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-hoist-variables@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc - languageName: node - linkType: hard - -"@babel/helper-member-expression-to-functions@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-member-expression-to-functions@npm:7.22.15" - dependencies: - "@babel/types": ^7.22.15 - checksum: c7c5d01c402dd8902c2ec3093f203ed0fc3bc5f669328a084d2e663c4c06dd0415480ee8220c6f96ba9b2dc49545c0078f221fc3900ab1e65de69a12fe7b361f - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-module-imports@npm:7.22.15" - dependencies: - "@babel/types": ^7.22.15 - checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.22.15, @babel/helper-module-transforms@npm:^7.22.20, @babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9": - version: 7.22.20 - resolution: "@babel/helper-module-transforms@npm:7.22.20" - dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.20 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 8fce25362df8711bd4620f41c5c18769edfeafe7f8f1dae9691966ef368e57f9da68dfa1707cd63c834c89dc4eaa82c26f12ea33e88fd262ac62844b11dcc389 - languageName: node - linkType: hard - -"@babel/helper-optimise-call-expression@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: c70ef6cc6b6ed32eeeec4482127e8be5451d0e5282d5495d5d569d39eb04d7f1d66ec99b327f45d1d5842a9ad8c22d48567e93fc502003a47de78d122e355f7c - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 - languageName: node - linkType: hard - -"@babel/helper-remap-async-to-generator@npm:^7.22.5, @babel/helper-remap-async-to-generator@npm:^7.22.9": - version: 7.22.20 - resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-wrap-function": ^7.22.20 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 - languageName: node - linkType: hard - -"@babel/helper-replace-supers@npm:^7.22.5, @babel/helper-replace-supers@npm:^7.22.9": - version: 7.22.20 - resolution: "@babel/helper-replace-supers@npm:7.22.20" - dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-member-expression-to-functions": ^7.22.15 - "@babel/helper-optimise-call-expression": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639 - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-simple-access@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 - languageName: node - linkType: hard - -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: 1012ef2295eb12dc073f2b9edf3425661e9b8432a3387e62a8bc27c42963f1f216ab3124228015c748770b2257b4f1fda882ca8fa34c0bf485e929ae5bc45244 - languageName: node - linkType: hard - -"@babel/helper-split-export-declaration@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helper-split-export-declaration@npm:7.22.6" - dependencies: - "@babel/types": ^7.22.5 - checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.22.19, @babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.22.5": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-validator-option@npm:7.22.15" - checksum: 68da52b1e10002a543161494c4bc0f4d0398c8fdf361d5f7f4272e95c45d5b32d974896d44f6a0ea7378c9204988879d73613ca683e13bd1304e46d25ff67a8d - languageName: node - linkType: hard - -"@babel/helper-wrap-function@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-wrap-function@npm:7.22.20" - dependencies: - "@babel/helper-function-name": ^7.22.5 - "@babel/template": ^7.22.15 - "@babel/types": ^7.22.19 - checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helpers@npm:7.22.15" - dependencies: - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.22.15 - "@babel/types": ^7.22.15 - checksum: 49f61a93cbae4df3328bda67af5db743fead659ae4242571226c3596b7df78546189cdf991fed1eca33b559de8abf396a90a001f474a1bab351418f07b7ae6ef - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.22.13": - version: 7.22.20 - resolution: "@babel/highlight@npm:7.22.20" - dependencies: - "@babel/helper-validator-identifier": ^7.22.20 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.16": - version: 7.22.16 - resolution: "@babel/parser@npm:7.22.16" - bin: - parser: ./bin/babel-parser.js - checksum: 944c756b5bdeb07b9fec16ecef6b3c61aff9d4c4b924abadcf01afa1840a740b8e2357ae00482b5b37daad6d2bfd848c947f27ad65138d687b6fdc924bc59edd - languageName: node - linkType: hard - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 8910ca21a7ec7c06f7b247d4b86c97c5aa15ef321518f44f6f490c5912fdf82c605aaa02b90892e375d82ccbedeadfdeadd922c1b836c9dd4c596871bf654753 - languageName: node - linkType: hard - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.15 - peerDependencies: - "@babel/core": ^7.13.0 - checksum: fbefedc0da014c37f1a50a8094ce7dbbf2181ae93243f23d6ecba2499b5b20196c2124d6a4dfe3e9e0125798e80593103e456352a4beb4e5c6f7c75efb80fdac - languageName: node - linkType: hard - -"@babel/plugin-proposal-class-properties@npm:^7.16.0": - version: 7.18.6 - resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 - languageName: node - linkType: hard - -"@babel/plugin-proposal-decorators@npm:^7.16.4": - version: 7.22.15 - resolution: "@babel/plugin-proposal-decorators@npm:7.22.15" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.9 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/plugin-syntax-decorators": ^7.22.10 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bbe8ebf46fa21035db88b751bc4b7becaf3ac87ad2f8d82838794b7396d4c9b198a3906f2409ea063c08834292a15b048cfaf38dea609939840dc53f32ac0e47 - languageName: node - linkType: hard - -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.16.0": - version: 7.18.6 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d - languageName: node - linkType: hard - -"@babel/plugin-proposal-numeric-separator@npm:^7.16.0": - version: 7.18.6 - resolution: "@babel/plugin-proposal-numeric-separator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-chaining@npm:^7.16.0": - version: 7.21.0 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" - dependencies: - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 - languageName: node - linkType: hard - -"@babel/plugin-proposal-private-methods@npm:^7.16.0": - version: 7.18.6 - resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad - languageName: node - linkType: hard - -"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": - version: 7.21.0-placeholder-for-preset-env.2 - resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 - languageName: node - linkType: hard - -"@babel/plugin-proposal-private-property-in-object@npm:^7.16.0": - version: 7.21.11 - resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.11" - dependencies: - "@babel/helper-annotate-as-pure": ^7.18.6 - "@babel/helper-create-class-features-plugin": ^7.21.0 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1b880543bc5f525b360b53d97dd30807302bb82615cd42bf931968f59003cac75629563d6b104868db50abd22235b3271fdf679fea5db59a267181a99cc0c265 - languageName: node - linkType: hard - -"@babel/plugin-syntax-async-generators@npm:^7.8.4": - version: 7.8.4 - resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 - languageName: node - linkType: hard - -"@babel/plugin-syntax-bigint@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-properties@npm:^7.12.13, @babel/plugin-syntax-class-properties@npm:^7.8.3": - version: 7.12.13 - resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" - dependencies: - "@babel/helper-plugin-utils": ^7.12.13 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-static-block@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 - languageName: node - linkType: hard - -"@babel/plugin-syntax-decorators@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/plugin-syntax-decorators@npm:7.22.10" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: baaa10fa52d76ee8b9447f7aedb1c8df7cf2ef83ae29c085c07444e691685aa8b1a326dfb7a3a0e3ae4d5f9fd083175e46ea5e2316d8200f0278f3fd54a58696 - languageName: node - linkType: hard - -"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd - languageName: node - linkType: hard - -"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a - languageName: node - linkType: hard - -"@babel/plugin-syntax-flow@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-flow@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 84c8c40fcfe8e78cecdd6fb90e8f97f419e3f3b27a33de8324ae97d5ce1b87cdd98a636fa21a68d4d2c37c7d63f3a279bb84b6956b849921affed6b806b6ffe7 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-assertions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2b8b5572db04a7bef1e6cd20debf447e4eef7cb012616f5eceb8fa3e23ce469b8f76ee74fd6d1e158ba17a8f58b0aec579d092fb67c5a30e83ccfbc5754916c1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-attributes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 197b3c5ea2a9649347f033342cb222ab47f4645633695205c0250c6bf2af29e643753b8bb24a2db39948bef08e7c540babfd365591eb57fc110cb30b425ffc47 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-meta@npm:^7.10.4, @babel/plugin-syntax-import-meta@npm:^7.8.3": - version: 7.10.4 - resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b - languageName: node - linkType: hard - -"@babel/plugin-syntax-json-strings@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 8829d30c2617ab31393d99cec2978e41f014f4ac6f01a1cecf4c4dd8320c3ec12fdc3ce121126b2d8d32f6887e99ca1a0bad53dedb1e6ad165640b92b24980ce - languageName: node - linkType: hard - -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": - version: 7.10.4 - resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 - languageName: node - linkType: hard - -"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-numeric-separator@npm:^7.10.4, @babel/plugin-syntax-numeric-separator@npm:^7.8.3": - version: 7.10.4 - resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 - languageName: node - linkType: hard - -"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": - version: 7.14.5 - resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda - languageName: node - linkType: hard - -"@babel/plugin-syntax-top-level-await@npm:^7.14.5, @babel/plugin-syntax-top-level-await@npm:^7.8.3": - version: 7.14.5 - resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e - languageName: node - linkType: hard - -"@babel/plugin-syntax-typescript@npm:^7.22.5, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 8ab7718fbb026d64da93681a57797d60326097fd7cb930380c8bffd9eb101689e90142c760a14b51e8e69c88a73ba3da956cb4520a3b0c65743aee5c71ef360a - languageName: node - linkType: hard - -"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c - languageName: node - linkType: hard - -"@babel/plugin-transform-arrow-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 35abb6c57062802c7ce8bd96b2ef2883e3124370c688bbd67609f7d2453802fb73944df8808f893b6c67de978eb2bcf87bbfe325e46d6f39b5fcb09ece11d01a - languageName: node - linkType: hard - -"@babel/plugin-transform-async-generator-functions@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.15" - dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.9 - "@babel/plugin-syntax-async-generators": ^7.8.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: fad98786b446ce63bde0d14a221e2617eef5a7bbca62b49d96f16ab5e1694521234cfba6145b830fbf9af16d60a8a3dbf148e8694830bd91796fe333b0599e73 - languageName: node - linkType: hard - -"@babel/plugin-transform-async-to-generator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.22.5" - dependencies: - "@babel/helper-module-imports": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b95f23f99dcb379a9f0a1c2a3bbea3f8dc0e1b16dc1ac8b484fe378370169290a7a63d520959a9ba1232837cf74a80e23f6facbe14fd42a3cda6d3c2d7168e62 - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoped-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 416b1341858e8ca4e524dee66044735956ced5f478b2c3b9bc11ec2285b0c25d7dbb96d79887169eb938084c95d0a89338c8b2fe70d473bd9dc92e5d9db1732c - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoping@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-block-scoping@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c7091dc000b854ce0c471588ca0704ef1ce78cff954584a9f21c1668fd0669e7c8d5396fb72fe49a2216d9b96a400d435f424f27e41a097ef6c855f9c57df195 - languageName: node - linkType: hard - -"@babel/plugin-transform-class-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-class-properties@npm:7.22.5" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b830152dfc2ff2f647f0abe76e6251babdfbef54d18c4b2c73a6bf76b1a00050a5d998dac80dc901a48514e95604324943a9dd39317073fe0928b559e0e0c579 - languageName: node - linkType: hard - -"@babel/plugin-transform-class-static-block@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-class-static-block@npm:7.22.11" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.11 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - peerDependencies: - "@babel/core": ^7.12.0 - checksum: 69f040506fad66f1c6918d288d0e0edbc5c8a07c8b4462c1184ad2f9f08995d68b057126c213871c0853ae0c72afc60ec87492049dfacb20902e32346a448bcb - languageName: node - linkType: hard - -"@babel/plugin-transform-classes@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-classes@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.9 - "@babel/helper-split-export-declaration": ^7.22.6 - globals: ^11.1.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d3f4d0c107dd8a3557ea3575cc777fab27efa92958b41e4a9822f7499725c1f554beae58855de16ddec0a7b694e45f59a26cea8fbde4275563f72f09c6e039a0 - languageName: node - linkType: hard - -"@babel/plugin-transform-computed-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-computed-properties@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/template": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c2a77a0f94ec71efbc569109ec14ea2aa925b333289272ced8b33c6108bdbb02caf01830ffc7e49486b62dec51911924d13f3a76f1149f40daace1898009e131 - languageName: node - linkType: hard - -"@babel/plugin-transform-destructuring@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-destructuring@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4bccb4765e5287f1d36119d930afb9941ea8f4f001bddb8febff716bac0e09dc58576624f3ec59470630513044dd342075fe11af16d8c1b234cb7406cffca9f0 - languageName: node - linkType: hard - -"@babel/plugin-transform-dotall-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 409b658d11e3082c8f69e9cdef2d96e4d6d11256f005772425fb230cc48fd05945edbfbcb709dab293a1a2f01f9c8a5bb7b4131e632b23264039d9f95864b453 - languageName: node - linkType: hard - -"@babel/plugin-transform-duplicate-keys@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bb1280fbabaab6fab2ede585df34900712698210a3bd413f4df5bae6d8c24be36b496c92722ae676a7a67d060a4624f4d6c23b923485f906bfba8773c69f55b4 - languageName: node - linkType: hard - -"@babel/plugin-transform-dynamic-import@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 78fc9c532210bf9e8f231747f542318568ac360ee6c27e80853962c984283c73da3f8f8aebe83c2096090a435b356b092ed85de617a156cbe0729d847632be45 - languageName: node - linkType: hard - -"@babel/plugin-transform-exponentiation-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f2d660c1b1d51ad5fec1cd5ad426a52187204068c4158f8c4aa977b31535c61b66898d532603eef21c15756827be8277f724c869b888d560f26d7fe848bb5eae - languageName: node - linkType: hard - -"@babel/plugin-transform-export-namespace-from@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 73af5883a321ed56a4bfd43c8a7de0164faebe619287706896fc6ee2f7a4e69042adaa1338c0b8b4bdb9f7e5fdceb016fb1d40694cb43ca3b8827429e8aac4bf - languageName: node - linkType: hard - -"@babel/plugin-transform-flow-strip-types@npm:^7.16.0": - version: 7.22.5 - resolution: "@babel/plugin-transform-flow-strip-types@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-flow": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1ba48187d6f33814be01c6870489f0b1858256cf2b9dd7e62f02af8b30049bf375112f1d44692c5fed3cb9cd26ee2fb32e358cd79b6ad2360a51e8f993e861bf - languageName: node - linkType: hard - -"@babel/plugin-transform-for-of@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-for-of@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f395ae7bce31e14961460f56cf751b5d6e37dd27d7df5b1f4e49fec1c11b6f9cf71991c7ffbe6549878591e87df0d66af798cf26edfa4bfa6b4c3dba1fb2f73a - languageName: node - linkType: hard - -"@babel/plugin-transform-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-function-name@npm:7.22.5" - dependencies: - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: cff3b876357999cb8ae30e439c3ec6b0491a53b0aa6f722920a4675a6dd5b53af97a833051df4b34791fe5b3dd326ccf769d5c8e45b322aa50ee11a660b17845 - languageName: node - linkType: hard - -"@babel/plugin-transform-json-strings@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-json-strings@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-json-strings": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 50665e5979e66358c50e90a26db53c55917f78175127ac2fa05c7888d156d418ffb930ec0a109353db0a7c5f57c756ce01bfc9825d24cbfd2b3ec453f2ed8cba - languageName: node - linkType: hard - -"@babel/plugin-transform-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: ec37cc2ffb32667af935ab32fe28f00920ec8a1eb999aa6dc6602f2bebd8ba205a558aeedcdccdebf334381d5c57106c61f52332045730393e73410892a9735b - languageName: node - linkType: hard - -"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c664e9798e85afa7f92f07b867682dee7392046181d82f5d21bae6f2ca26dfe9c8375cdc52b7483c3fc09a983c1989f60eff9fbc4f373b0c0a74090553d05739 - languageName: node - linkType: hard - -"@babel/plugin-transform-member-expression-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: ec4b0e07915ddd4fda0142fd104ee61015c208608a84cfa13643a95d18760b1dc1ceb6c6e0548898b8c49e5959a994e46367260176dbabc4467f729b21868504 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-amd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-amd@npm:7.22.5" - dependencies: - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 7da4c4ebbbcf7d182abb59b2046b22d86eee340caf8a22a39ef6a727da2d8acfec1f714fcdcd5054110b280e4934f735e80a6848d192b6834c5d4459a014f04d - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-commonjs@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.15" - dependencies: - "@babel/helper-module-transforms": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f8fc85fefa6be8626a378ca38fb84c7359043e7c692c854e9ee250a05121553b7f4a58e127099efe12662ec6bebbfd304ce638a0b4563d7cbd5982f3d877321c - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-systemjs@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.11" - dependencies: - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-module-transforms": ^7.22.9 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d0991e4bdc3352b6a9f4d12b6662e3645d892cd5c3c005ba5f14e65f1e218c6a8f7f4497e64a51d82a046e507aaa7db3143b800b0270dca1824cbd214ff3363d - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-umd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" - dependencies: - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 46622834c54c551b231963b867adbc80854881b3e516ff29984a8da989bd81665bd70e8cba6710345248e97166689310f544aee1a5773e262845a8f1b3e5b8b4 - languageName: node - linkType: hard - -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623 - languageName: node - linkType: hard - -"@babel/plugin-transform-new-target@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-new-target@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 6b72112773487a881a1d6ffa680afde08bad699252020e86122180ee7a88854d5da3f15d9bca3331cf2e025df045604494a8208a2e63b486266b07c14e2ffbf3 - languageName: node - linkType: hard - -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 167babecc8b8fe70796a7b7d34af667ebbf43da166c21689502e5e8cc93180b7a85979c77c9f64b7cce431b36718bd0a6df9e5e0ffea4ae22afb22cfef886372 - languageName: node - linkType: hard - -"@babel/plugin-transform-numeric-separator@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: af064d06a4a041767ec396a5f258103f64785df290e038bba9f0ef454e6c914f2ac45d862bbdad8fac2c7ad47fa4e95356f29053c60c100a0160b02a995fe2a3 - languageName: node - linkType: hard - -"@babel/plugin-transform-object-rest-spread@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.15" - dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.22.15 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 62197a6f12289c1c1bd57f3bed9f0f765ca32390bfe91e0b5561dd94dd9770f4480c4162dec98da094bc0ba99d2c2ebba68de47c019454041b0b7a68ba2ec66d - languageName: node - linkType: hard - -"@babel/plugin-transform-object-super@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-object-super@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b71887877d74cb64dbccb5c0324fa67e31171e6a5311991f626650e44a4083e5436a1eaa89da78c0474fb095d4ec322d63ee778b202d33aa2e4194e1ed8e62d7 - languageName: node - linkType: hard - -"@babel/plugin-transform-optional-catch-binding@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f17abd90e1de67c84d63afea29c8021c74abb2794d3a6eeafb0bbe7372d3db32aefca386e392116ec63884537a4a2815d090d26264d259bacc08f6e3ed05294c - languageName: node - linkType: hard - -"@babel/plugin-transform-optional-chaining@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 6b97abe0e50ca2dd8684fcef2c8d12607637e707aa9d513b7035f5e812efbde9305736b438d422103a7844e04124cad5efa4ff0e6226a57afa1210a1c7485c8e - languageName: node - linkType: hard - -"@babel/plugin-transform-parameters@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-parameters@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 541188bb7d1876cad87687b5c7daf90f63d8208ae83df24acb1e2b05020ad1c78786b2723ca4054a83fcb74fb6509f30c4cacc5b538ee684224261ad5fb047c1 - languageName: node - linkType: hard - -"@babel/plugin-transform-private-methods@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-private-methods@npm:7.22.5" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 321479b4fcb6d3b3ef622ab22fd24001e43d46e680e8e41324c033d5810c84646e470f81b44cbcbef5c22e99030784f7cac92f1829974da7a47a60a7139082c3 - languageName: node - linkType: hard - -"@babel/plugin-transform-private-property-in-object@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.11" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.11 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4d029d84901e53c46dead7a46e2990a7bc62470f4e4ca58a0d063394f86652fd58fe4eea1eb941da3669cd536b559b9d058b342b59300026346b7a2a51badac8 - languageName: node - linkType: hard - -"@babel/plugin-transform-property-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-property-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 796176a3176106f77fcb8cd04eb34a8475ce82d6d03a88db089531b8f0453a2fb8b0c6ec9a52c27948bc0ea478becec449893741fc546dfc3930ab927e3f9f2e - languageName: node - linkType: hard - -"@babel/plugin-transform-react-constant-elements@npm:^7.12.1": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-constant-elements@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 596db90e37174dd703f4859fef3c86156a7c8564d8351168ac6fdca79c912ef8b8746ae04516ac3909d2cc750702d58d451badacb3c54ea998938ad05d99f9d2 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-display-name@npm:^7.16.0, @babel/plugin-transform-react-display-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-display-name@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a12bfd1e4e93055efca3ace3c34722571bda59d9740dca364d225d9c6e3ca874f134694d21715c42cc63d79efd46db9665bd4a022998767f9245f1e29d5d204d - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" - dependencies: - "@babel/plugin-transform-react-jsx": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx@npm:^7.22.15, @babel/plugin-transform-react-jsx@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/plugin-transform-react-jsx@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-jsx": ^7.22.5 - "@babel/types": ^7.22.15 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3899054e89550c3a0ef041af7c47ee266e2e934f498ee80fefeda778a6aa177b48aa8b4d2a8bf5848de977fec564571699ab952d9fa089c4c19b45ddb121df09 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-pure-annotations@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 092021c4f404e267002099ec20b3f12dd730cb90b0d83c5feed3dc00dbe43b9c42c795a18e7c6c7d7bddea20c7dd56221b146aec81b37f2e7eb5137331c61120 - languageName: node - linkType: hard - -"@babel/plugin-transform-regenerator@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/plugin-transform-regenerator@npm:7.22.10" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - regenerator-transform: ^0.15.2 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: e13678d62d6fa96f11cb8b863f00e8693491e7adc88bfca3f2820f80cbac8336e7dec3a596eee6a1c4663b7ececc3564f2cd7fb44ed6d4ce84ac2bb7f39ecc6e - languageName: node - linkType: hard - -"@babel/plugin-transform-reserved-words@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-reserved-words@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3ffd7dbc425fe8132bfec118b9817572799cab1473113a635d25ab606c1f5a2341a636c04cf6b22df3813320365ed5a965b5eeb3192320a10e4cc2c137bd8bfc - languageName: node - linkType: hard - -"@babel/plugin-transform-runtime@npm:^7.16.4": - version: 7.22.15 - resolution: "@babel/plugin-transform-runtime@npm:7.22.15" - dependencies: - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.5 - babel-plugin-polyfill-corejs3: ^0.8.3 - babel-plugin-polyfill-regenerator: ^0.5.2 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 7edf20b13d02f856276221624abf3b8084daa3f265a6e5c70ee0d0c63087fcf726dc8756a9c8bb3d25a1ce8697ab66ec8cdd15be992c21aed9971cb5bfe80a5b - languageName: node - linkType: hard - -"@babel/plugin-transform-shorthand-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a5ac902c56ea8effa99f681340ee61bac21094588f7aef0bc01dff98246651702e677552fa6d10e548c4ac22a3ffad047dd2f8c8f0540b68316c2c203e56818b - languageName: node - linkType: hard - -"@babel/plugin-transform-spread@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-spread@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 5587f0deb60b3dfc9b274e269031cc45ec75facccf1933ea2ea71ced9fd3ce98ed91bb36d6cd26817c14474b90ed998c5078415f0eab531caf301496ce24c95c - languageName: node - linkType: hard - -"@babel/plugin-transform-sticky-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 63b2c575e3e7f96c32d52ed45ee098fb7d354b35c2223b8c8e76840b32cc529ee0c0ceb5742fd082e56e91e3d82842a367ce177e82b05039af3d602c9627a729 - languageName: node - linkType: hard - -"@babel/plugin-transform-template-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-template-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 27e9bb030654cb425381c69754be4abe6a7c75b45cd7f962cd8d604b841b2f0fb7b024f2efc1c25cc53f5b16d79d5e8cfc47cacbdaa983895b3aeefa3e7e24ff - languageName: node - linkType: hard - -"@babel/plugin-transform-typeof-symbol@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 82a53a63ffc3010b689ca9a54e5f53b2718b9f4b4a9818f36f9b7dba234f38a01876680553d2716a645a61920b5e6e4aaf8d4a0064add379b27ca0b403049512 - languageName: node - linkType: hard - -"@babel/plugin-transform-typescript@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-typescript@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-typescript": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c5d96cdbf0e1512707aa1c1e3ac6b370a25fd9c545d26008ce44eb13a47bd7fd67a1eb799c98b5ccc82e33a345fda55c0055e1fe3ed97646ed405dd13020b226 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-escapes@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.10" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 807f40ed1324c8cb107c45358f1903384ca3f0ef1d01c5a3c5c9b271c8d8eec66936a3dcc8d75ddfceea9421420368c2e77ae3adef0a50557e778dfe296bf382 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-property-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2495e5f663cb388e3d888b4ba3df419ac436a5012144ac170b622ddfc221f9ea9bdba839fa2bc0185cb776b578030666406452ec7791cbf0e7a3d4c88ae9574c - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 6b5d1404c8c623b0ec9bd436c00d885a17d6a34f3f2597996343ddb9d94f6379705b21582dfd4cec2c47fd34068872e74ab6b9580116c0566b3f9447e2a7fa06 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: c042070f980b139547f8b0179efbc049ac5930abec7fc26ed7a41d89a048d8ab17d362200e204b6f71c3c20d6991a0e74415e1a412a49adc8131c2a40c04822e - languageName: node - linkType: hard - -"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.16.4": - version: 7.22.20 - resolution: "@babel/preset-env@npm:7.22.20" - dependencies: - "@babel/compat-data": ^7.22.20 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.15 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.15 - "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 - "@babel/plugin-syntax-async-generators": ^7.8.4 - "@babel/plugin-syntax-class-properties": ^7.12.13 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - "@babel/plugin-syntax-import-assertions": ^7.22.5 - "@babel/plugin-syntax-import-attributes": ^7.22.5 - "@babel/plugin-syntax-import-meta": ^7.10.4 - "@babel/plugin-syntax-json-strings": ^7.8.3 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - "@babel/plugin-syntax-top-level-await": ^7.14.5 - "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 - "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.22.15 - "@babel/plugin-transform-async-to-generator": ^7.22.5 - "@babel/plugin-transform-block-scoped-functions": ^7.22.5 - "@babel/plugin-transform-block-scoping": ^7.22.15 - "@babel/plugin-transform-class-properties": ^7.22.5 - "@babel/plugin-transform-class-static-block": ^7.22.11 - "@babel/plugin-transform-classes": ^7.22.15 - "@babel/plugin-transform-computed-properties": ^7.22.5 - "@babel/plugin-transform-destructuring": ^7.22.15 - "@babel/plugin-transform-dotall-regex": ^7.22.5 - "@babel/plugin-transform-duplicate-keys": ^7.22.5 - "@babel/plugin-transform-dynamic-import": ^7.22.11 - "@babel/plugin-transform-exponentiation-operator": ^7.22.5 - "@babel/plugin-transform-export-namespace-from": ^7.22.11 - "@babel/plugin-transform-for-of": ^7.22.15 - "@babel/plugin-transform-function-name": ^7.22.5 - "@babel/plugin-transform-json-strings": ^7.22.11 - "@babel/plugin-transform-literals": ^7.22.5 - "@babel/plugin-transform-logical-assignment-operators": ^7.22.11 - "@babel/plugin-transform-member-expression-literals": ^7.22.5 - "@babel/plugin-transform-modules-amd": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.22.15 - "@babel/plugin-transform-modules-systemjs": ^7.22.11 - "@babel/plugin-transform-modules-umd": ^7.22.5 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 - "@babel/plugin-transform-new-target": ^7.22.5 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 - "@babel/plugin-transform-numeric-separator": ^7.22.11 - "@babel/plugin-transform-object-rest-spread": ^7.22.15 - "@babel/plugin-transform-object-super": ^7.22.5 - "@babel/plugin-transform-optional-catch-binding": ^7.22.11 - "@babel/plugin-transform-optional-chaining": ^7.22.15 - "@babel/plugin-transform-parameters": ^7.22.15 - "@babel/plugin-transform-private-methods": ^7.22.5 - "@babel/plugin-transform-private-property-in-object": ^7.22.11 - "@babel/plugin-transform-property-literals": ^7.22.5 - "@babel/plugin-transform-regenerator": ^7.22.10 - "@babel/plugin-transform-reserved-words": ^7.22.5 - "@babel/plugin-transform-shorthand-properties": ^7.22.5 - "@babel/plugin-transform-spread": ^7.22.5 - "@babel/plugin-transform-sticky-regex": ^7.22.5 - "@babel/plugin-transform-template-literals": ^7.22.5 - "@babel/plugin-transform-typeof-symbol": ^7.22.5 - "@babel/plugin-transform-unicode-escapes": ^7.22.10 - "@babel/plugin-transform-unicode-property-regex": ^7.22.5 - "@babel/plugin-transform-unicode-regex": ^7.22.5 - "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 - "@babel/preset-modules": 0.1.6-no-external-plugins - "@babel/types": ^7.22.19 - babel-plugin-polyfill-corejs2: ^0.4.5 - babel-plugin-polyfill-corejs3: ^0.8.3 - babel-plugin-polyfill-regenerator: ^0.5.2 - core-js-compat: ^3.31.0 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 99357a5cb30f53bacdc0d1cd6dff0f052ea6c2d1ba874d969bba69897ef716e87283e84a59dc52fb49aa31fd1b6f55ed756c64c04f5678380700239f6030b881 - languageName: node - linkType: hard - -"@babel/preset-modules@npm:0.1.6-no-external-plugins": - version: 0.1.6-no-external-plugins - resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" - dependencies: - "@babel/helper-plugin-utils": ^7.0.0 - "@babel/types": ^7.4.4 - esutils: ^2.0.2 - peerDependencies: - "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 - checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 - languageName: node - linkType: hard - -"@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.16.0": - version: 7.22.15 - resolution: "@babel/preset-react@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-transform-react-display-name": ^7.22.5 - "@babel/plugin-transform-react-jsx": ^7.22.15 - "@babel/plugin-transform-react-jsx-development": ^7.22.5 - "@babel/plugin-transform-react-pure-annotations": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c3ef99dfa2e9f57d2e08603e883aa20f47630a826c8e413888a93ae6e0084b5016871e463829be125329d40a1ba0a89f7c43d77b6dab52083c225cb43e63d10e - languageName: node - linkType: hard - -"@babel/preset-typescript@npm:^7.16.0": - version: 7.22.15 - resolution: "@babel/preset-typescript@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-syntax-jsx": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.22.15 - "@babel/plugin-transform-typescript": ^7.22.15 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 02ac4d5c812a52357c8f517f81584725f06f385d54ccfda89dd082e0ed89a94bd9f4d9b05fa1cbdcf426e3489c1921f04c93c5acc5deea83407a64c22ad2feb4 - languageName: node - linkType: hard - -"@babel/regjsgen@npm:^0.8.0": - version: 0.8.0 - resolution: "@babel/regjsgen@npm:0.8.0" - checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": - version: 7.22.15 - resolution: "@babel/runtime@npm:7.22.15" - dependencies: - regenerator-runtime: ^0.14.0 - checksum: 793296df1e41599a935a3d77ec01eb6088410d3fd4dbe4e92f06c6b7bb2f8355024e6d78621a3a35f44e0e23b0b59107f23d585384df4f3123256a1e1492040e - languageName: node - linkType: hard - -"@babel/template@npm:^7.22.15, @babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3": - version: 7.22.15 - resolution: "@babel/template@npm:7.22.15" - dependencies: - "@babel/code-frame": ^7.22.13 - "@babel/parser": ^7.22.15 - "@babel/types": ^7.22.15 - checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.22.15, @babel/traverse@npm:^7.22.20, @babel/traverse@npm:^7.7.2": - version: 7.22.20 - resolution: "@babel/traverse@npm:7.22.20" - dependencies: - "@babel/code-frame": ^7.22.13 - "@babel/generator": ^7.22.15 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.22.16 - "@babel/types": ^7.22.19 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 97da9afa7f8f505ce52c36ac2531129bc4a0e250880aaf9b467dc044f30a5bce2b756c1af4d961958bc225659546e811a7d536ab3d920fd60921087989b841b9 - languageName: node - linkType: hard - -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.22.19 - resolution: "@babel/types@npm:7.22.19" - dependencies: - "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.19 - to-fast-properties: ^2.0.0 - checksum: 2d69740e69b55ba36ece0c17d5afb7b7213b34297157df39ef9ba24965aff677c56f014413052ecc5b2fbbf26910c63e5bb24a969df84d7a17153750cf75915e - languageName: node - linkType: hard - -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 850f9305536d0f2bd13e9e0881cb5f02e4f93fad1189f7b2d4bebf694e3206924eadee1068130d43c11b750efcc9405f88a8e42ef098b6d75239c0f047de1a27 - languageName: node - linkType: hard - -"@csstools/normalize.css@npm:*": - version: 12.0.0 - resolution: "@csstools/normalize.css@npm:12.0.0" - checksum: fbef0f7fe4edbc3ce31b41257f0fa06e0442f11260e41c082a98de9b824997786a16900e7a5c0f4ca8f736dcd25dfd01c153d1c994a07d42c93c0a526ce0774d - languageName: node - linkType: hard - -"@csstools/postcss-cascade-layers@npm:^1.1.1": - version: 1.1.1 - resolution: "@csstools/postcss-cascade-layers@npm:1.1.1" - dependencies: - "@csstools/selector-specificity": ^2.0.2 - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: 8ecd6a929e8ddee3ad0834ab5017f50a569817ba8490d152b11c705c13cf3d9701f74792f375cbd72d8f33a4eeaabb3f984f1514adf8c5a530eb91be70c14cf4 - languageName: node - linkType: hard - -"@csstools/postcss-color-function@npm:^1.1.1": - version: 1.1.1 - resolution: "@csstools/postcss-color-function@npm:1.1.1" - dependencies: - "@csstools/postcss-progressive-custom-properties": ^1.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 087595985ebcc2fc42013d6305185d4cdc842d87fb261185db905dc31eaa24fc23a7cc068fa3da814b3c8b98164107ddaf1b4ab24f4ff5b2a7b5fbcd4c6ceec9 - languageName: node - linkType: hard - -"@csstools/postcss-font-format-keywords@npm:^1.0.1": - version: 1.0.1 - resolution: "@csstools/postcss-font-format-keywords@npm:1.0.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: ed8d9eab9793f0184e000709bcb155d4eb96c49a312e3ea9e549e006b74fd4aafac63cb9f9f01bec5b717a833539ff085c3f1ef7d273b97d587769ef637d50c1 - languageName: node - linkType: hard - -"@csstools/postcss-hwb-function@npm:^1.0.2": - version: 1.0.2 - resolution: "@csstools/postcss-hwb-function@npm:1.0.2" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 352ead754a692f7ed33a712c491012cab5c2f2946136a669a354237cfe8e6faca90c7389ee793cb329b9b0ddec984faa06d47e2f875933aaca417afff74ce6aa - languageName: node - linkType: hard - -"@csstools/postcss-ic-unit@npm:^1.0.1": - version: 1.0.1 - resolution: "@csstools/postcss-ic-unit@npm:1.0.1" - dependencies: - "@csstools/postcss-progressive-custom-properties": ^1.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 09c414c9b7762b5fbe837ff451d7a11e4890f1ed3c92edc3573f02f3d89747f6ac3f2270799b68a332bd7f5de05bb0dfffddb6323fc4020c2bea33ff58314533 - languageName: node - linkType: hard - -"@csstools/postcss-is-pseudo-class@npm:^2.0.7": - version: 2.0.7 - resolution: "@csstools/postcss-is-pseudo-class@npm:2.0.7" - dependencies: - "@csstools/selector-specificity": ^2.0.0 - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: a4494bb8e9a34826944ba6872c91c1e88268caab6d06968897f1a0cc75ca5cfc4989435961fc668a9c6842a6d17f4cda0055fa256d23e598b8bbc6f022956125 - languageName: node - linkType: hard - -"@csstools/postcss-nested-calc@npm:^1.0.0": - version: 1.0.0 - resolution: "@csstools/postcss-nested-calc@npm:1.0.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 53bb783dd61621c11c1e6e352f079577e2eb908de67947ceef31a178e070c06c223baae87acd5c3bd51c664515d2adc16166a129159168626111aff548583790 - languageName: node - linkType: hard - -"@csstools/postcss-normalize-display-values@npm:^1.0.1": - version: 1.0.1 - resolution: "@csstools/postcss-normalize-display-values@npm:1.0.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 75901daec3869ba15e0adfd50d8e2e754ec06d55ac44fbd540748476388d223d53710fb3a3cbfe6695a2bab015a489fb47d9e3914ff211736923f8deb818dc0b - languageName: node - linkType: hard - -"@csstools/postcss-oklab-function@npm:^1.1.1": - version: 1.1.1 - resolution: "@csstools/postcss-oklab-function@npm:1.1.1" - dependencies: - "@csstools/postcss-progressive-custom-properties": ^1.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: d66b789060b37ed810450d9a7d8319a0ae14e913c091f3e0ee482b3471538762e801d5eae3d62fda2f1eb1e88c76786d2c2b06c1172166eba1cca5e2a0dc95f2 - languageName: node - linkType: hard - -"@csstools/postcss-progressive-custom-properties@npm:^1.1.0, @csstools/postcss-progressive-custom-properties@npm:^1.3.0": - version: 1.3.0 - resolution: "@csstools/postcss-progressive-custom-properties@npm:1.3.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.3 - checksum: e281845fde5b8a80d06ec20147bd74e96a9351bebbec5e5c3a6fb37ea30a597ff84172601786a8a270662f58f708b4a3bf8d822d6318023def9773d2f6589962 - languageName: node - linkType: hard - -"@csstools/postcss-stepped-value-functions@npm:^1.0.1": - version: 1.0.1 - resolution: "@csstools/postcss-stepped-value-functions@npm:1.0.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 2fc88713a0d49d142010652be8139b00719e407df1173e46047284f1befd0647e1fff67f259f9f55ac3b46bba6462b21f0aa192bd10a2989c51a8ce0d25fc495 - languageName: node - linkType: hard - -"@csstools/postcss-text-decoration-shorthand@npm:^1.0.0": - version: 1.0.0 - resolution: "@csstools/postcss-text-decoration-shorthand@npm:1.0.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: d27aaf97872c42bec9f6fde4d8bf924e89f7886f0aca8e4fc5aaf2f9083b09bb43dbbfa29124fa36fcdeb2d4d3e0459a095acf62188260cd1577e9811bb1276e - languageName: node - linkType: hard - -"@csstools/postcss-trigonometric-functions@npm:^1.0.2": - version: 1.0.2 - resolution: "@csstools/postcss-trigonometric-functions@npm:1.0.2" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: f7f5b5f2492606b79a56f09e814ae8f10a2ae9e9c5fb8019f0e347a4a6c07953b2cc663fd4fa43a60e6994dfd958958f39df8ec760e2a646cfe71fe2bb119382 - languageName: node - linkType: hard - -"@csstools/postcss-unset-value@npm:^1.0.2": - version: 1.0.2 - resolution: "@csstools/postcss-unset-value@npm:1.0.2" - peerDependencies: - postcss: ^8.2 - checksum: 3facdae154d6516ffd964f7582696f406465f11cf8dead503e0afdfecc99ebc25638ab2830affce4516131aa2db004458a235e439f575b04e9ef72ad82f55835 - languageName: node - linkType: hard - -"@csstools/selector-specificity@npm:^2.0.0, @csstools/selector-specificity@npm:^2.0.2": - version: 2.2.0 - resolution: "@csstools/selector-specificity@npm:2.2.0" - peerDependencies: - postcss-selector-parser: ^6.0.10 - checksum: 97c89f23b3b527d7bd51ed299969ed2b9fbb219a367948b44aefec228b8eda6ae0ad74fe8a82f9aac8ff32cfd00bb6d0c98d1daeab2e8fc6d5c4af25e5be5673 - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.2.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" - dependencies: - eslint-visitor-keys: ^3.3.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.6.1": - version: 4.8.1 - resolution: "@eslint-community/regexpp@npm:4.8.1" - checksum: 82d62c845ef42b810f268cfdc84d803a2da01735fb52e902fd34bdc09f92464a094fd8e4802839874b000b2f73f67c972859e813ba705233515d3e954f234bf2 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.1.2": - version: 2.1.2 - resolution: "@eslint/eslintrc@npm:2.1.2" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.6.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 - languageName: node - linkType: hard - -"@eslint/js@npm:8.50.0": - version: 8.50.0 - resolution: "@eslint/js@npm:8.50.0" - checksum: 302478f2acaaa7228729ec6a04f56641590185e1d8cd1c836a6db8a6b8009f80a57349341be9fbb9aa1721a7a569d1be3ffc598a33300d22816f11832095386c - languageName: node - linkType: hard - -"@humanwhocodes/config-array@npm:^0.11.11": - version: 0.11.11 - resolution: "@humanwhocodes/config-array@npm:0.11.11" - dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: db84507375ab77b8ffdd24f498a5b49ad6b64391d30dd2ac56885501d03964d29637e05b1ed5aefa09d57ac667e28028bc22d2da872bfcd619652fbdb5f4ca19 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 - languageName: node - linkType: hard - -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 - languageName: node - linkType: hard - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: ^5.1.2 - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: ^7.0.1 - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: ^8.1.0 - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb - languageName: node - linkType: hard - -"@istanbuljs/load-nyc-config@npm:^1.0.0": - version: 1.1.0 - resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" - dependencies: - camelcase: ^5.3.1 - find-up: ^4.1.0 - get-package-type: ^0.1.0 - js-yaml: ^3.13.1 - resolve-from: ^5.0.0 - checksum: d578da5e2e804d5c93228450a1380e1a3c691de4953acc162f387b717258512a3e07b83510a936d9fab03eac90817473917e24f5d16297af3867f59328d58568 - languageName: node - linkType: hard - -"@istanbuljs/schema@npm:^0.1.2": - version: 0.1.3 - resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 - languageName: node - linkType: hard - -"@jest/console@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/console@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - jest-message-util: ^27.5.1 - jest-util: ^27.5.1 - slash: ^3.0.0 - checksum: 7cb20f06a34b09734c0342685ec53aa4c401fe3757c13a9c58fce76b971a322eb884f6de1068ef96f746e5398e067371b89515a07c268d4440a867c87748a706 - languageName: node - linkType: hard - -"@jest/console@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/console@npm:28.1.3" - dependencies: - "@jest/types": ^28.1.3 - "@types/node": "*" - chalk: ^4.0.0 - jest-message-util: ^28.1.3 - jest-util: ^28.1.3 - slash: ^3.0.0 - checksum: fe50d98d26d02ce2901c76dff4bd5429a33c13affb692c9ebf8a578ca2f38a5dd854363d40d6c394f215150791fd1f692afd8e730a4178dda24107c8dfd9750a - languageName: node - linkType: hard - -"@jest/core@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/core@npm:27.5.1" - dependencies: - "@jest/console": ^27.5.1 - "@jest/reporters": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - emittery: ^0.8.1 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - jest-changed-files: ^27.5.1 - jest-config: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-message-util: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-resolve-dependencies: ^27.5.1 - jest-runner: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 - jest-watcher: ^27.5.1 - micromatch: ^4.0.4 - rimraf: ^3.0.0 - slash: ^3.0.0 - strip-ansi: ^6.0.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 904a94ad8f1b43cd6b48de3b0226659bff3696150ff8cf7680fc2faffdc8a115203bb9ab6e817c1f79f9d6a81f67953053cbc64d8a4604f2e0c42a04c28cf126 - languageName: node - linkType: hard - -"@jest/environment@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/environment@npm:27.5.1" - dependencies: - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - jest-mock: ^27.5.1 - checksum: 2a9e18c35a015508dbec5b90b21c150230fa6c1c8cb8fabe029d46ee2ca4c40eb832fb636157da14c66590d0a4c8a2c053226b041f54a44507d6f6a89abefd66 - languageName: node - linkType: hard - -"@jest/expect-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "@jest/expect-utils@npm:29.7.0" - dependencies: - jest-get-type: ^29.6.3 - checksum: 75eb177f3d00b6331bcaa057e07c0ccb0733a1d0a1943e1d8db346779039cb7f103789f16e502f888a3096fb58c2300c38d1f3748b36a7fa762eb6f6d1b160ed - languageName: node - linkType: hard - -"@jest/fake-timers@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/fake-timers@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - "@sinonjs/fake-timers": ^8.0.1 - "@types/node": "*" - jest-message-util: ^27.5.1 - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - checksum: 02a0561ed2f4586093facd4ae500b74694f187ac24d4a00e949a39a1c5325bca8932b4fcb0388a2c5ed0656506fc1cf51fd3e32cdd48cea7497ad9c6e028aba8 - languageName: node - linkType: hard - -"@jest/globals@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/globals@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/types": ^27.5.1 - expect: ^27.5.1 - checksum: 087f97047e9dcf555f76fe2ce54aee681e005eaa837a0c0c2d251df6b6412c892c9df54cb871b180342114389a5ff895a4e52e6e6d3d0015bf83c02a54f64c3c - languageName: node - linkType: hard - -"@jest/reporters@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/reporters@npm:27.5.1" - dependencies: - "@bcoe/v8-coverage": ^0.2.3 - "@jest/console": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - collect-v8-coverage: ^1.0.0 - exit: ^0.1.2 - glob: ^7.1.2 - graceful-fs: ^4.2.9 - istanbul-lib-coverage: ^3.0.0 - istanbul-lib-instrument: ^5.1.0 - istanbul-lib-report: ^3.0.0 - istanbul-lib-source-maps: ^4.0.0 - istanbul-reports: ^3.1.3 - jest-haste-map: ^27.5.1 - jest-resolve: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 - slash: ^3.0.0 - source-map: ^0.6.0 - string-length: ^4.0.1 - terminal-link: ^2.0.0 - v8-to-istanbul: ^8.1.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: faba5eafb86e62b62e152cafc8812d56308f9d1e8b77f3a7dcae4a8803a20a60a0909cc43ed73363ef649bf558e4fb181c7a336d144c89f7998279d1882bb69e - languageName: node - linkType: hard - -"@jest/schemas@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/schemas@npm:28.1.3" - dependencies: - "@sinclair/typebox": ^0.24.1 - checksum: 3cf1d4b66c9c4ffda58b246de1ddcba8e6ad085af63dccdf07922511f13b68c0cc480a7bc620cb4f3099a6f134801c747e1df7bfc7a4ef4dceefbdea3e31e1de - languageName: node - linkType: hard - -"@jest/schemas@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/schemas@npm:29.6.3" - dependencies: - "@sinclair/typebox": ^0.27.8 - checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 - languageName: node - linkType: hard - -"@jest/source-map@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/source-map@npm:27.5.1" - dependencies: - callsites: ^3.0.0 - graceful-fs: ^4.2.9 - source-map: ^0.6.0 - checksum: 4fb1e743b602841babf7e22bd84eca34676cb05d4eb3b604cae57fc59e406099f5ac759ac1a0d04d901237d143f0f4f234417306e823bde732a1d19982230862 - languageName: node - linkType: hard - -"@jest/test-result@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/test-result@npm:27.5.1" - dependencies: - "@jest/console": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/istanbul-lib-coverage": ^2.0.0 - collect-v8-coverage: ^1.0.0 - checksum: 338f7c509d6a3bc6d7dd7388c8f6f548b87638e171dc1fddfedcacb4e8950583288832223ba688058cbcf874b937d22bdc0fa88f79f5fc666f77957e465c06a5 - languageName: node - linkType: hard - -"@jest/test-result@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/test-result@npm:28.1.3" - dependencies: - "@jest/console": ^28.1.3 - "@jest/types": ^28.1.3 - "@types/istanbul-lib-coverage": ^2.0.0 - collect-v8-coverage: ^1.0.0 - checksum: 957a5dd2fd2e84aabe86698f93c0825e96128ccaa23abf548b159a9b08ac74e4bde7acf4bec48479243dbdb27e4ea1b68c171846d21fb64855c6b55cead9ef27 - languageName: node - linkType: hard - -"@jest/test-sequencer@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/test-sequencer@npm:27.5.1" - dependencies: - "@jest/test-result": ^27.5.1 - graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-runtime: ^27.5.1 - checksum: f21f9c8bb746847f7f89accfd29d6046eec1446f0b54e4694444feaa4df379791f76ef0f5a4360aafcbc73b50bc979f68b8a7620de404019d3de166be6720cb0 - languageName: node - linkType: hard - -"@jest/transform@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/transform@npm:27.5.1" - dependencies: - "@babel/core": ^7.1.0 - "@jest/types": ^27.5.1 - babel-plugin-istanbul: ^6.1.1 - chalk: ^4.0.0 - convert-source-map: ^1.4.0 - fast-json-stable-stringify: ^2.0.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-util: ^27.5.1 - micromatch: ^4.0.4 - pirates: ^4.0.4 - slash: ^3.0.0 - source-map: ^0.6.1 - write-file-atomic: ^3.0.0 - checksum: a22079121aedea0f20a03a9c026be971f7b92adbfb4d5fd1fb67be315741deac4f056936d7c72a53b24aa5a1071bc942c003925fd453bf3f6a0ae5da6384e137 - languageName: node - linkType: hard - -"@jest/types@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/types@npm:27.5.1" - dependencies: - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^16.0.0 - chalk: ^4.0.0 - checksum: d1f43cc946d87543ddd79d49547aab2399481d34025d5c5f2025d3d99c573e1d9832fa83cef25e9d9b07a8583500229d15bbb07b8e233d127d911d133e2f14b1 - languageName: node - linkType: hard - -"@jest/types@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/types@npm:28.1.3" - dependencies: - "@jest/schemas": ^28.1.3 - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^17.0.8 - chalk: ^4.0.0 - checksum: 1e258d9c063fcf59ebc91e46d5ea5984674ac7ae6cae3e50aa780d22b4405bf2c925f40350bf30013839eb5d4b5e521d956ddf8f3b7c78debef0e75a07f57350 - languageName: node - linkType: hard - -"@jest/types@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/types@npm:29.6.3" - dependencies: - "@jest/schemas": ^29.6.3 - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^17.0.8 - chalk: ^4.0.0 - checksum: a0bcf15dbb0eca6bdd8ce61a3fb055349d40268622a7670a3b2eb3c3dbafe9eb26af59938366d520b86907b9505b0f9b29b85cec11579a9e580694b87cd90fcc - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.3 - resolution: "@jridgewell/gen-mapping@npm:0.3.3" - dependencies: - "@jridgewell/set-array": ^1.0.1 - "@jridgewell/sourcemap-codec": ^1.4.10 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 - languageName: node - linkType: hard - -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e - languageName: node - linkType: hard - -"@jridgewell/source-map@npm:^0.3.3": - version: 0.3.5 - resolution: "@jridgewell/source-map@npm:0.3.5" - dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 1ad4dec0bdafbade57920a50acec6634f88a0eb735851e0dda906fa9894e7f0549c492678aad1a10f8e144bfe87f238307bf2a914a1bc85b7781d345417e9f6f - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": - version: 1.4.15 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.19 - resolution: "@jridgewell/trace-mapping@npm:0.3.19" - dependencies: - "@jridgewell/resolve-uri": ^3.1.0 - "@jridgewell/sourcemap-codec": ^1.4.14 - checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 - languageName: node - linkType: hard - -"@leichtgewicht/ip-codec@npm:^2.0.1": - version: 2.0.4 - resolution: "@leichtgewicht/ip-codec@npm:2.0.4" - checksum: 468de1f04d33de6d300892683d7c8aecbf96d1e2c5fe084f95f816e50a054d45b7c1ebfb141a1447d844b86a948733f6eebd92234da8581c84a1ad4de2946a2d - languageName: node - linkType: hard - -"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": - version: 5.1.1-v1 - resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" - dependencies: - eslint-scope: 5.1.1 - checksum: f2e3b2d6a6e2d9f163ca22105910c9f850dc4897af0aea3ef0a5886b63d8e1ba6505b71c99cb78a3bba24a09557d601eb21c8dede3f3213753fcfef364eb0e57 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: ^1.1.9 - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: ^1.6.0 - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.0 - resolution: "@npmcli/fs@npm:3.1.0" - dependencies: - semver: ^7.3.5 - checksum: a50a6818de5fc557d0b0e6f50ec780a7a02ab8ad07e5ac8b16bf519e0ad60a144ac64f97d05c443c3367235d337182e1d012bbac0eb8dbae8dc7b40b193efd0e - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f - languageName: node - linkType: hard - -"@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.3": - version: 0.5.11 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.11" - dependencies: - ansi-html-community: ^0.0.8 - common-path-prefix: ^3.0.0 - core-js-pure: ^3.23.3 - error-stack-parser: ^2.0.6 - find-up: ^5.0.0 - html-entities: ^2.1.0 - loader-utils: ^2.0.4 - schema-utils: ^3.0.0 - source-map: ^0.7.3 - peerDependencies: - "@types/webpack": 4.x || 5.x - react-refresh: ">=0.10.0 <1.0.0" - sockjs-client: ^1.4.0 - type-fest: ">=0.17.0 <5.0.0" - webpack: ">=4.43.0 <6.0.0" - webpack-dev-server: 3.x || 4.x - webpack-hot-middleware: 2.x - webpack-plugin-serve: 0.x || 1.x - peerDependenciesMeta: - "@types/webpack": - optional: true - sockjs-client: - optional: true - type-fest: - optional: true - webpack-dev-server: - optional: true - webpack-hot-middleware: - optional: true - webpack-plugin-serve: - optional: true - checksum: a82eced9519f4dcac424acae719f819ab4150bfcf2874ac7daaf25a4f1c409e3d8b9d693fea0c686c24d520a5473756df32da90d8b89739670f8f8084c600bb4 - languageName: node - linkType: hard - -"@remix-run/router@npm:1.9.0": - version: 1.9.0 - resolution: "@remix-run/router@npm:1.9.0" - checksum: 0537b0ff29879ac85077cb4c42eaca4a295b9efd71477848984c2f2dfa5741c9b83d3106a7bb72994a51a9adfeeab3b0f5a40f2dee8be3f0750feeeca2a6d513 - languageName: node - linkType: hard - -"@rollup/plugin-babel@npm:^5.2.0": - version: 5.3.1 - resolution: "@rollup/plugin-babel@npm:5.3.1" - dependencies: - "@babel/helper-module-imports": ^7.10.4 - "@rollup/pluginutils": ^3.1.0 - peerDependencies: - "@babel/core": ^7.0.0 - "@types/babel__core": ^7.1.9 - rollup: ^1.20.0||^2.0.0 - peerDependenciesMeta: - "@types/babel__core": - optional: true - checksum: 220d71e4647330f252ef33d5f29700aef2e8284a0b61acfcceb47617a7f96208aa1ed16eae75619424bf08811ede5241e271a6d031f07026dee6b3a2bdcdc638 - languageName: node - linkType: hard - -"@rollup/plugin-node-resolve@npm:^11.2.1": - version: 11.2.1 - resolution: "@rollup/plugin-node-resolve@npm:11.2.1" - dependencies: - "@rollup/pluginutils": ^3.1.0 - "@types/resolve": 1.17.1 - builtin-modules: ^3.1.0 - deepmerge: ^4.2.2 - is-module: ^1.0.0 - resolve: ^1.19.0 - peerDependencies: - rollup: ^1.20.0||^2.0.0 - checksum: 6f3b3ecf9a0596a5db4212984bdeb13bb7612693602407e9457ada075dea5a5f2e4e124c592352cf27066a88b194de9b9a95390149b52cf335d5b5e17b4e265b - languageName: node - linkType: hard - -"@rollup/plugin-replace@npm:^2.4.1": - version: 2.4.2 - resolution: "@rollup/plugin-replace@npm:2.4.2" - dependencies: - "@rollup/pluginutils": ^3.1.0 - magic-string: ^0.25.7 - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - checksum: b2f1618ee5526d288e2f8ae328dcb326e20e8dc8bd1f60d3e14d6708a5832e4aa44811f7d493f4aed2deeadca86e3b6b0503cd39bf50cfb4b595bb9da027fad0 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^3.1.0": - version: 3.1.0 - resolution: "@rollup/pluginutils@npm:3.1.0" - dependencies: - "@types/estree": 0.0.39 - estree-walker: ^1.0.1 - picomatch: ^2.2.2 - peerDependencies: - rollup: ^1.20.0||^2.0.0 - checksum: 8be16e27863c219edbb25a4e6ec2fe0e1e451d9e917b6a43cf2ae5bc025a6b8faaa40f82a6e53b66d0de37b58ff472c6c3d57a83037ae635041f8df959d6d9aa - languageName: node - linkType: hard - -"@rushstack/eslint-patch@npm:^1.1.0": - version: 1.4.0 - resolution: "@rushstack/eslint-patch@npm:1.4.0" - checksum: 29b216288deda3dee69dfb49adb1d809217d67331775a854de18771905268a65c11be5325313d47fb1c62ea0b477733e17310bc9708ccb7f3fb6f0a3816b82d9 - languageName: node - linkType: hard - -"@sinclair/typebox@npm:^0.24.1": - version: 0.24.51 - resolution: "@sinclair/typebox@npm:0.24.51" - checksum: fd0d855e748ef767eb19da1a60ed0ab928e91e0f358c1dd198d600762c0015440b15755e96d1176e2a0db7e09c6a64ed487828ee10dd0c3e22f61eb09c478cd0 - languageName: node - linkType: hard - -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 - languageName: node - linkType: hard - -"@sinonjs/commons@npm:^1.7.0": - version: 1.8.6 - resolution: "@sinonjs/commons@npm:1.8.6" - dependencies: - type-detect: 4.0.8 - checksum: 7d3f8c1e85f30cd4e83594fc19b7a657f14d49eb8d95a30095631ce15e906c869e0eff96c5b93dffea7490c00418b07f54582ba49c6560feb2a8c34c0b16832d - languageName: node - linkType: hard - -"@sinonjs/fake-timers@npm:^8.0.1": - version: 8.1.0 - resolution: "@sinonjs/fake-timers@npm:8.1.0" - dependencies: - "@sinonjs/commons": ^1.7.0 - checksum: 09b5a158ce013a6c37613258bad79ca4efeb99b1f59c41c73cca36cac00b258aefcf46eeea970fccf06b989414d86fe9f54c1102272c0c3bdd51a313cea80949 - languageName: node - linkType: hard - -"@surma/rollup-plugin-off-main-thread@npm:^2.2.3": - version: 2.2.3 - resolution: "@surma/rollup-plugin-off-main-thread@npm:2.2.3" - dependencies: - ejs: ^3.1.6 - json5: ^2.2.0 - magic-string: ^0.25.0 - string.prototype.matchall: ^4.0.6 - checksum: 2c021349442e2e2cec96bb50fd82ec8bf8514d909bc73594f6cfc89b3b68f2feed909a8161d7d307d9455585c97e6b66853ce334db432626c7596836d4549c0c - languageName: node - linkType: hard - -"@svgr/babel-plugin-add-jsx-attribute@npm:^5.4.0": - version: 5.4.0 - resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:5.4.0" - checksum: 1c538cf312b486598c6aea17f9b72d7fc308eb5dd32effd804630206a185493b8a828ff980ceb29d57d8319c085614c7cea967be709c71ae77702a4c30037011 - languageName: node - linkType: hard - -"@svgr/babel-plugin-remove-jsx-attribute@npm:^5.4.0": - version: 5.4.0 - resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:5.4.0" - checksum: ad2231bfcb14daa944201df66236c222cde05a07c4cffaecab1d36d33f606b6caf17bda21844fc435780c1a27195e49beb8397536fe5e7545dfffcfbbcecb7f8 - languageName: node - linkType: hard - -"@svgr/babel-plugin-remove-jsx-empty-expression@npm:^5.0.1": - version: 5.0.1 - resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:5.0.1" - checksum: 175c8f13ddcb0744f7c3910ebed3799cfb961a75bff130e1ed2071c87ca8b8df8964825c988e511b2e3c5dbf48ad3d4fbbb6989edc53294253df40cf2a24375e - languageName: node - linkType: hard - -"@svgr/babel-plugin-replace-jsx-attribute-value@npm:^5.0.1": - version: 5.0.1 - resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:5.0.1" - checksum: 68f4e2a5b95eca44e22fce485dc2ddd10adabe2b38f6db3ef9071b35e84bf379685f7acab6c05b7a82f722328c02f6424f8252c6dd5c2c4ed2f00104072b1dfe - languageName: node - linkType: hard - -"@svgr/babel-plugin-svg-dynamic-title@npm:^5.4.0": - version: 5.4.0 - resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:5.4.0" - checksum: c46feb52454acea32031d1d881a81334f2e5f838ed25a2d9014acb5e9541d404405911e86dbee8bee9f1e43c9e07118123a07dc297962dbed0c4c5a86bdc4be9 - languageName: node - linkType: hard - -"@svgr/babel-plugin-svg-em-dimensions@npm:^5.4.0": - version: 5.4.0 - resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:5.4.0" - checksum: 0d19b26147bbba932bd973258dab4a80a7ea6b9d674713186f0e10fa21a9e3aa4327326b2bf1892e8051712bce0ea30561eb187ca27bb241d33c350cea51ac88 - languageName: node - linkType: hard - -"@svgr/babel-plugin-transform-react-native-svg@npm:^5.4.0": - version: 5.4.0 - resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:5.4.0" - checksum: 8ac5dc9fb2dee24addc74dbcb169860c95a69247606f986eabb0618fb300dd08e8f220891b758e62c051428ba04d8dd50f2c2bf877e15fa190e6d384d1ccd2ad - languageName: node - linkType: hard - -"@svgr/babel-plugin-transform-svg-component@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/babel-plugin-transform-svg-component@npm:5.5.0" - checksum: 94c3fed490deb8544af4ea32a5d78a840334cdcc8a5a33fe8ea9f1c220a4d714d57c9e10934492de99b7e1acc17963b1749a49927e27b1e839a4dc3c893605c7 - languageName: node - linkType: hard - -"@svgr/babel-preset@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/babel-preset@npm:5.5.0" - dependencies: - "@svgr/babel-plugin-add-jsx-attribute": ^5.4.0 - "@svgr/babel-plugin-remove-jsx-attribute": ^5.4.0 - "@svgr/babel-plugin-remove-jsx-empty-expression": ^5.0.1 - "@svgr/babel-plugin-replace-jsx-attribute-value": ^5.0.1 - "@svgr/babel-plugin-svg-dynamic-title": ^5.4.0 - "@svgr/babel-plugin-svg-em-dimensions": ^5.4.0 - "@svgr/babel-plugin-transform-react-native-svg": ^5.4.0 - "@svgr/babel-plugin-transform-svg-component": ^5.5.0 - checksum: 5d396c4499c9ff2df9db6d08a160d10386b9f459cb9c2bb5ee183ab03b2f46c8ef3c9a070f1eee93f4e4433a5f00704e7632b1386078eb697ad8a2b38edb8522 - languageName: node - linkType: hard - -"@svgr/core@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/core@npm:5.5.0" - dependencies: - "@svgr/plugin-jsx": ^5.5.0 - camelcase: ^6.2.0 - cosmiconfig: ^7.0.0 - checksum: 39b230151e30b9ca8551d10674e50efb821d1a49ce10969b09587af130780eba581baa1e321b0922f48331943096f05590aa6ae92d88d011d58093a89dd34158 - languageName: node - linkType: hard - -"@svgr/hast-util-to-babel-ast@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/hast-util-to-babel-ast@npm:5.5.0" - dependencies: - "@babel/types": ^7.12.6 - checksum: a03c1c7ab92b1a6dbd7671b0b78df4c07e8d808ff092671554a78752ec0c0425c03b6c82569a5f33903d191c73379eedf631f23aeb30b7a70185f5f2fc67fae6 - languageName: node - linkType: hard - -"@svgr/plugin-jsx@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/plugin-jsx@npm:5.5.0" - dependencies: - "@babel/core": ^7.12.3 - "@svgr/babel-preset": ^5.5.0 - "@svgr/hast-util-to-babel-ast": ^5.5.0 - svg-parser: ^2.0.2 - checksum: e053f8dd6bfcd72377b432dd5b1db3c89d503d29839639a87f85b597a680d0b69e33a4db376f5a1074a89615f7157cd36f63f94bdb4083a0fd5bbe918c7fcb9b - languageName: node - linkType: hard - -"@svgr/plugin-svgo@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/plugin-svgo@npm:5.5.0" - dependencies: - cosmiconfig: ^7.0.0 - deepmerge: ^4.2.2 - svgo: ^1.2.2 - checksum: bef5d09581349afdf654209f82199670649cc749b81ff5f310ce4a3bbad749cde877c9b1a711dd9ced51224e2b5b5a720d242bdf183fa0f83e08e8d5e069b0b6 - languageName: node - linkType: hard - -"@svgr/webpack@npm:^5.5.0": - version: 5.5.0 - resolution: "@svgr/webpack@npm:5.5.0" - dependencies: - "@babel/core": ^7.12.3 - "@babel/plugin-transform-react-constant-elements": ^7.12.1 - "@babel/preset-env": ^7.12.1 - "@babel/preset-react": ^7.12.5 - "@svgr/core": ^5.5.0 - "@svgr/plugin-jsx": ^5.5.0 - "@svgr/plugin-svgo": ^5.5.0 - loader-utils: ^2.0.0 - checksum: 540391bd63791625d26d6b5e0dd3c716ef51176bfba53bf0979a1ac4781afd2672f4bef2d76cf3d9cdc8e9ee61bda6863ed405a237b10406633ede4cd524f1cc - languageName: node - linkType: hard - -"@testing-library/dom@npm:^8.5.0": - version: 8.20.1 - resolution: "@testing-library/dom@npm:8.20.1" - dependencies: - "@babel/code-frame": ^7.10.4 - "@babel/runtime": ^7.12.5 - "@types/aria-query": ^5.0.1 - aria-query: 5.1.3 - chalk: ^4.1.0 - dom-accessibility-api: ^0.5.9 - lz-string: ^1.5.0 - pretty-format: ^27.0.2 - checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 - languageName: node - linkType: hard - -"@testing-library/jest-dom@npm:^5.17.0": - version: 5.17.0 - resolution: "@testing-library/jest-dom@npm:5.17.0" - dependencies: - "@adobe/css-tools": ^4.0.1 - "@babel/runtime": ^7.9.2 - "@types/testing-library__jest-dom": ^5.9.1 - aria-query: ^5.0.0 - chalk: ^3.0.0 - css.escape: ^1.5.1 - dom-accessibility-api: ^0.5.6 - lodash: ^4.17.15 - redent: ^3.0.0 - checksum: 9f28dbca8b50d7c306aae40c3aa8e06f0e115f740360004bd87d57f95acf7ab4b4f4122a7399a76dbf2bdaaafb15c99cc137fdcb0ae457a92e2de0f3fbf9b03b - languageName: node - linkType: hard - -"@testing-library/react@npm:^13.4.0": - version: 13.4.0 - resolution: "@testing-library/react@npm:13.4.0" - dependencies: - "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.5.0 - "@types/react-dom": ^18.0.0 - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - checksum: 51ec548c1fdb1271089a5c63e0908f0166f2c7fcd9cacd3108ebbe0ce64cb4351812d885892020dc37608418cfb15698514856502b3cab0e5cc58d6cc1bd4a3e - languageName: node - linkType: hard - -"@testing-library/user-event@npm:^13.5.0": - version: 13.5.0 - resolution: "@testing-library/user-event@npm:13.5.0" - dependencies: - "@babel/runtime": ^7.12.5 - peerDependencies: - "@testing-library/dom": ">=7.21.4" - checksum: 16319de685fbb7008f1ba667928f458b2d08196918002daca56996de80ef35e6d9de26e9e1ece7d00a004692b95a597cf9142fff0dc53f2f51606a776584f549 - languageName: node - linkType: hard - -"@tootallnate/once@npm:1": - version: 1.1.2 - resolution: "@tootallnate/once@npm:1.1.2" - checksum: e1fb1bbbc12089a0cb9433dc290f97bddd062deadb6178ce9bcb93bb7c1aecde5e60184bc7065aec42fe1663622a213493c48bbd4972d931aae48315f18e1be9 - languageName: node - linkType: hard - -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 - languageName: node - linkType: hard - -"@trysound/sax@npm:0.2.0": - version: 0.2.0 - resolution: "@trysound/sax@npm:0.2.0" - checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c - languageName: node - linkType: hard - -"@types/aria-query@npm:^5.0.1": - version: 5.0.2 - resolution: "@types/aria-query@npm:5.0.2" - checksum: 19394fea016e72da39dd5ef1cf1643e3252b7ee99d8f0b3a8740d3b72f874443fc1e00a41935b36fdfaf92cd735d4ae10dc5d6ab8f1192527d4c0471bb8ff8e4 - languageName: node - linkType: hard - -"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14": - version: 7.20.2 - resolution: "@types/babel__core@npm:7.20.2" - dependencies: - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - "@types/babel__generator": "*" - "@types/babel__template": "*" - "@types/babel__traverse": "*" - checksum: 564fbaa8ff1305d50807ada0ec227c3e7528bebb2f8fe6b2ed88db0735a31511a74ad18729679c43eeed8025ed29d408f53059289719e95ab1352ed559a100bd - languageName: node - linkType: hard - -"@types/babel__generator@npm:*": - version: 7.6.5 - resolution: "@types/babel__generator@npm:7.6.5" - dependencies: - "@babel/types": ^7.0.0 - checksum: c7459f5025c4c800eaf58f4db3b24e9d736331fe7df40961d9bc49f31b46e2a3be83dc9276e8688f10a5ed752ae153ad5f1bdd45e2245bac95273730b9115ec2 - languageName: node - linkType: hard - -"@types/babel__template@npm:*": - version: 7.4.2 - resolution: "@types/babel__template@npm:7.4.2" - dependencies: - "@babel/parser": ^7.1.0 - "@babel/types": ^7.0.0 - checksum: 0fe977b45a3269336c77f3ae4641a6c48abf0fa35ab1a23fb571690786af02d6cec08255a43499b0b25c5633800f7ae882ace450cce905e3060fa9e6995047ae - languageName: node - linkType: hard - -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.4, @types/babel__traverse@npm:^7.0.6": - version: 7.20.2 - resolution: "@types/babel__traverse@npm:7.20.2" - dependencies: - "@babel/types": ^7.20.7 - checksum: 981340286479524436348d32373eaa3bf993c635cbf70307b4b69463eee83406a959ac4844f683911e0db8ab8d9f0025ab630dc7a8c170fee9ee74144c2a528f - languageName: node - linkType: hard - -"@types/body-parser@npm:*": - version: 1.19.3 - resolution: "@types/body-parser@npm:1.19.3" - dependencies: - "@types/connect": "*" - "@types/node": "*" - checksum: 932fa71437c275023799123680ef26ffd90efd37f51a1abe405e6ae6e5b4ad9511b7a3a8f5a12877ed1444a02b6286c0a137a98e914b3c61932390c83643cc2c - languageName: node - linkType: hard - -"@types/bonjour@npm:^3.5.9": - version: 3.5.11 - resolution: "@types/bonjour@npm:3.5.11" - dependencies: - "@types/node": "*" - checksum: 12fb86a1bb4a610f16ef6d7d68f85e7c31070029f02b6622073794a271e75abcf58230ed205a2ae23c53be2c08b9e507d3b91fa0dc9dfe76c4b1f5e19e9370cb - languageName: node - linkType: hard - -"@types/connect-history-api-fallback@npm:^1.3.5": - version: 1.5.1 - resolution: "@types/connect-history-api-fallback@npm:1.5.1" - dependencies: - "@types/express-serve-static-core": "*" - "@types/node": "*" - checksum: bc5e46663300eba56eaf8ef242156256e2bdadc52bb7d6543f4b37f2945b6a810901c245711f8321fce7d94c7b588b308a86519f3e1f87a80eb87841d808dbdc - languageName: node - linkType: hard - -"@types/connect@npm:*": - version: 3.4.36 - resolution: "@types/connect@npm:3.4.36" - dependencies: - "@types/node": "*" - checksum: 4dee3d966fb527b98f0cbbdcf6977c9193fc3204ed539b7522fe5e64dfa45f9017bdda4ffb1f760062262fce7701a0ee1c2f6ce2e50af36c74d4e37052303172 - languageName: node - linkType: hard - -"@types/cookie@npm:^0.3.3": - version: 0.3.3 - resolution: "@types/cookie@npm:0.3.3" - checksum: 450c930d792a4fd5a93645b4123f02596368f904dbb1fe6fbb5043bce8f6ecf877a08511c6ba11c8e28168f62bc278e68d214f002fab927c9056c0bc69f21370 - languageName: node - linkType: hard - -"@types/eslint-scope@npm:^3.7.3": - version: 3.7.5 - resolution: "@types/eslint-scope@npm:3.7.5" - dependencies: - "@types/eslint": "*" - "@types/estree": "*" - checksum: e91ce335c3791c2cf6084caa0073f90d5b7ae3fcf27785ade8422b7d896159fa14a5a3f1efd31ef03e9ebc1ff04983288280dfe8c9a5579a958539f59df8cc9f - languageName: node - linkType: hard - -"@types/eslint@npm:*, @types/eslint@npm:^7.29.0 || ^8.4.1": - version: 8.44.3 - resolution: "@types/eslint@npm:8.44.3" - dependencies: - "@types/estree": "*" - "@types/json-schema": "*" - checksum: 3a0d152785400cb83a887a646d9c8877468e686b6fb439635c64856b70dbe91019e588d2b32bc923cd60642bf5dca7f70b2cf61eb431cf25fbdf2932f6e13dd3 - languageName: node - linkType: hard - -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.2 - resolution: "@types/estree@npm:1.0.2" - checksum: aeedb1b2fe20cbe06f44b99b562bf9703e360bfcdf5bb3d61d248182ee1dd63500f2474e12f098ffe1f5ac3202b43b3e18ec99902d9328d5374f5512fa077e45 - languageName: node - linkType: hard - -"@types/estree@npm:0.0.39": - version: 0.0.39 - resolution: "@types/estree@npm:0.0.39" - checksum: 412fb5b9868f2c418126451821833414189b75cc6bf84361156feed733e3d92ec220b9d74a89e52722e03d5e241b2932732711b7497374a404fad49087adc248 - languageName: node - linkType: hard - -"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": - version: 4.17.37 - resolution: "@types/express-serve-static-core@npm:4.17.37" - dependencies: - "@types/node": "*" - "@types/qs": "*" - "@types/range-parser": "*" - "@types/send": "*" - checksum: 2dab1380e45eb44e56ecc1be1c42c4b897364d2f2a08e03ca28fbcb1e6866e390217385435813711c046f9acd684424d088855dc32825d5cbecf72c60ecd037f - languageName: node - linkType: hard - -"@types/express@npm:*, @types/express@npm:^4.17.13": - version: 4.17.18 - resolution: "@types/express@npm:4.17.18" - dependencies: - "@types/body-parser": "*" - "@types/express-serve-static-core": ^4.17.33 - "@types/qs": "*" - "@types/serve-static": "*" - checksum: 8c178da4f0edff1f006d871fbdc3f849620986ff10bad252f3dfd45b57554e26aaa28c602285df028930d5216e257a06fbaf795070f8bb42f7d87e3b689cba50 - languageName: node - linkType: hard - -"@types/graceful-fs@npm:^4.1.2": - version: 4.1.7 - resolution: "@types/graceful-fs@npm:4.1.7" - dependencies: - "@types/node": "*" - checksum: 8b97e208f85c9efd02a6003a582c77646dd87be0af13aec9419a720771560a8a87a979eaca73ae193d7c73127f34d0a958403a9b5d6246e450289fd8c79adf09 - languageName: node - linkType: hard - -"@types/hoist-non-react-statics@npm:^3.3.1": - version: 3.3.2 - resolution: "@types/hoist-non-react-statics@npm:3.3.2" - dependencies: - "@types/react": "*" - hoist-non-react-statics: ^3.3.0 - checksum: fe5d4b751e13f56010811fd6c4e49e53e2ccbcbbdc54bb8d86a413fbd08c5a83311bca9ef75a1a88d3ba62806711b5dea3f323c0e0f932b3a283dcebc3240238 - languageName: node - linkType: hard - -"@types/html-minifier-terser@npm:^6.0.0": - version: 6.1.0 - resolution: "@types/html-minifier-terser@npm:6.1.0" - checksum: eb843f6a8d662d44fb18ec61041117734c6aae77aa38df1be3b4712e8e50ffaa35f1e1c92fdd0fde14a5675fecf457abcd0d15a01fae7506c91926176967f452 - languageName: node - linkType: hard - -"@types/http-errors@npm:*": - version: 2.0.2 - resolution: "@types/http-errors@npm:2.0.2" - checksum: d7f14045240ac4b563725130942b8e5c8080bfabc724c8ff3f166ea928ff7ae02c5194763bc8f6aaf21897e8a44049b0492493b9de3e058247e58fdfe0f86692 - languageName: node - linkType: hard - -"@types/http-proxy@npm:^1.17.8": - version: 1.17.12 - resolution: "@types/http-proxy@npm:1.17.12" - dependencies: - "@types/node": "*" - checksum: 89700c8e3c8f2c59c87c8db8e7a070c97a3b30a4a38223aca6b8b817e6f2ca931f5a500e16ecadc1ebcfed2676cc60e073d8f887e621d84420298728ec6fd000 - languageName: node - linkType: hard - -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.4 - resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 - languageName: node - linkType: hard - -"@types/istanbul-lib-report@npm:*": - version: 3.0.0 - resolution: "@types/istanbul-lib-report@npm:3.0.0" - dependencies: - "@types/istanbul-lib-coverage": "*" - checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 - languageName: node - linkType: hard - -"@types/istanbul-reports@npm:^3.0.0": - version: 3.0.1 - resolution: "@types/istanbul-reports@npm:3.0.1" - dependencies: - "@types/istanbul-lib-report": "*" - checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903 - languageName: node - linkType: hard - -"@types/jest@npm:*": - version: 29.5.5 - resolution: "@types/jest@npm:29.5.5" - dependencies: - expect: ^29.0.0 - pretty-format: ^29.0.0 - checksum: 56e55cde9949bcc0ee2fa34ce5b7c32c2bfb20e53424aa4ff3a210859eeaaa3fdf6f42f81a3f655238039cdaaaf108b054b7a8602f394e6c52b903659338d8c6 - languageName: node - linkType: hard - -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.13 - resolution: "@types/json-schema@npm:7.0.13" - checksum: 345df21a678fa72fb389f35f33de77833d09d4a142bb2bcb27c18690efa4cf70fc2876e43843cefb3fbdb9fcb12cd3e970a90936df30f53bbee899865ff605ab - languageName: node - linkType: hard - -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac - languageName: node - linkType: hard - -"@types/mime@npm:*": - version: 3.0.1 - resolution: "@types/mime@npm:3.0.1" - checksum: 4040fac73fd0cea2460e29b348c1a6173da747f3a87da0dbce80dd7a9355a3d0e51d6d9a401654f3e5550620e3718b5a899b2ec1debf18424e298a2c605346e7 - languageName: node - linkType: hard - -"@types/mime@npm:^1": - version: 1.3.2 - resolution: "@types/mime@npm:1.3.2" - checksum: 0493368244cced1a69cb791b485a260a422e6fcc857782e1178d1e6f219f1b161793e9f87f5fae1b219af0f50bee24fcbe733a18b4be8fdd07a38a8fb91146fd - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 20.6.5 - resolution: "@types/node@npm:20.6.5" - checksum: b849e849cf7631458a65c5019c81962028e306d8c4455a48422277b240f5a7eb8a1f1dafa60306bd4c773b77263bb8b05c074b1026e868bd137bb2022cf63ea2 - languageName: node - linkType: hard - -"@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b - languageName: node - linkType: hard - -"@types/prettier@npm:^2.1.5": - version: 2.7.3 - resolution: "@types/prettier@npm:2.7.3" - checksum: 705384209cea6d1433ff6c187c80dcc0b95d99d5c5ce21a46a9a58060c527973506822e428789d842761e0280d25e3359300f017fbe77b9755bc772ab3dc2f83 - languageName: node - linkType: hard - -"@types/prop-types@npm:*": - version: 15.7.7 - resolution: "@types/prop-types@npm:15.7.7" - checksum: 023b95f7dd82e1c594f51dcb93ec4c382600cef6eeee29a2ac7b782b92c0882eab8da16d4cbd6e18b39e85ac8d94ebf4ca02c6e248ce5b5fb4b16dbab5d82861 - languageName: node - linkType: hard - -"@types/q@npm:^1.5.1": - version: 1.5.6 - resolution: "@types/q@npm:1.5.6" - checksum: e60d191fd2b2b60666548b475b552f8ed219e4aaacf4ccd9555361474ae294e1f139603390b16ac688912e1438c3dab97fc6ef9b96dee749a96351bc9288fd41 - languageName: node - linkType: hard - -"@types/qs@npm:*": - version: 6.9.8 - resolution: "@types/qs@npm:6.9.8" - checksum: c28e07d00d07970e5134c6eed184a0189b8a4649e28fdf36d9117fe671c067a44820890de6bdecef18217647a95e9c6aebdaaae69f5fe4b0bec9345db885f77e - languageName: node - linkType: hard - -"@types/range-parser@npm:*": - version: 1.2.4 - resolution: "@types/range-parser@npm:1.2.4" - checksum: b7c0dfd5080a989d6c8bb0b6750fc0933d9acabeb476da6fe71d8bdf1ab65e37c136169d84148034802f48378ab94e3c37bb4ef7656b2bec2cb9c0f8d4146a95 - languageName: node - linkType: hard - -"@types/react-dom@npm:^18.0.0": - version: 18.2.7 - resolution: "@types/react-dom@npm:18.2.7" - dependencies: - "@types/react": "*" - checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f - languageName: node - linkType: hard - -"@types/react@npm:*": - version: 18.2.22 - resolution: "@types/react@npm:18.2.22" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: 44289523dabaadcd3fd85689abb98f9ebcc8492d7e978348d1c986138acef4801030b279e89a19e38a6319e294bcea77559e37e0c803e4bacf2b8ae3a56ba587 - languageName: node - linkType: hard - -"@types/resolve@npm:1.17.1": - version: 1.17.1 - resolution: "@types/resolve@npm:1.17.1" - dependencies: - "@types/node": "*" - checksum: dc6a6df507656004e242dcb02c784479deca516d5f4b58a1707e708022b269ae147e1da0521f3e8ad0d63638869d87e0adc023f0bd5454aa6f72ac66c7525cf5 - languageName: node - linkType: hard - -"@types/retry@npm:0.12.0": - version: 0.12.0 - resolution: "@types/retry@npm:0.12.0" - checksum: 61a072c7639f6e8126588bf1eb1ce8835f2cb9c2aba795c4491cf6310e013267b0c8488039857c261c387e9728c1b43205099223f160bb6a76b4374f741b5603 - languageName: node - linkType: hard - -"@types/scheduler@npm:*": - version: 0.16.3 - resolution: "@types/scheduler@npm:0.16.3" - checksum: 2b0aec39c24268e3ce938c5db2f2e77f5c3dd280e05c262d9c2fe7d890929e4632a6b8e94334017b66b45e4f92a5aa42ba3356640c2a1175fa37bef2f5200767 - languageName: node - linkType: hard - -"@types/semver@npm:^7.3.12": - version: 7.5.2 - resolution: "@types/semver@npm:7.5.2" - checksum: 743aa8a2b58e20b329c19bd2459152cb049d12fafab7279b90ac11e0f268c97efbcb606ea0c681cca03f79015381b40d9b1244349b354270bec3f939ed49f6e9 - languageName: node - linkType: hard - -"@types/send@npm:*": - version: 0.17.1 - resolution: "@types/send@npm:0.17.1" - dependencies: - "@types/mime": ^1 - "@types/node": "*" - checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793 - languageName: node - linkType: hard - -"@types/serve-index@npm:^1.9.1": - version: 1.9.1 - resolution: "@types/serve-index@npm:1.9.1" - dependencies: - "@types/express": "*" - checksum: 026f3995fb500f6df7c3fe5009e53bad6d739e20b84089f58ebfafb2f404bbbb6162bbe33f72d2f2af32d5b8d3799c8e179793f90d9ed5871fb8591190bb6056 - languageName: node - linkType: hard - -"@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10": - version: 1.15.2 - resolution: "@types/serve-static@npm:1.15.2" - dependencies: - "@types/http-errors": "*" - "@types/mime": "*" - "@types/node": "*" - checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e - languageName: node - linkType: hard - -"@types/sockjs@npm:^0.3.33": - version: 0.3.33 - resolution: "@types/sockjs@npm:0.3.33" - dependencies: - "@types/node": "*" - checksum: b9bbb2b5c5ead2fb884bb019f61a014e37410bddd295de28184e1b2e71ee6b04120c5ba7b9954617f0bdf962c13d06249ce65004490889c747c80d3f628ea842 - languageName: node - linkType: hard - -"@types/stack-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/stack-utils@npm:2.0.1" - checksum: 205fdbe3326b7046d7eaf5e494d8084f2659086a266f3f9cf00bccc549c8e36e407f88168ad4383c8b07099957ad669f75f2532ed4bc70be2b037330f7bae019 - languageName: node - linkType: hard - -"@types/testing-library__jest-dom@npm:^5.9.1": - version: 5.14.9 - resolution: "@types/testing-library__jest-dom@npm:5.14.9" - dependencies: - "@types/jest": "*" - checksum: d364494fc2545316292e88861146146af1e3818792ca63b62a63758b2f737669b687f4aaddfcfbcb7d0e1ed7890a9bd05de23ff97f277d5e68de574497a9ee72 - languageName: node - linkType: hard - -"@types/trusted-types@npm:^2.0.2": - version: 2.0.4 - resolution: "@types/trusted-types@npm:2.0.4" - checksum: 5256c4576cd1c90d33ddd9cc9cbd4f202b39c98cbe8b7f74963298f9eb2159c285ea5c25a6181b4c594d8d75641765bff85d72c2d251ad076e6529ce0eeedd1c - languageName: node - linkType: hard - -"@types/ws@npm:^8.5.5": - version: 8.5.5 - resolution: "@types/ws@npm:8.5.5" - dependencies: - "@types/node": "*" - checksum: d00bf8070e6938e3ccf933010921c6ce78ac3606696ce37a393b27a9a603f7bd93ea64f3c5fa295a2f743575ba9c9a9fdb904af0f5fe2229bf2adf0630386e4a - languageName: node - linkType: hard - -"@types/yargs-parser@npm:*": - version: 21.0.1 - resolution: "@types/yargs-parser@npm:21.0.1" - checksum: 64e6316c2045e2d460c4fb79572f872f9d2f98fddc6d9d3949c71f0b6ad0ef8a2706cf49db26dfb02a9cb81433abb8f340f015e1d20a9692279abe9477b72c8e - languageName: node - linkType: hard - -"@types/yargs@npm:^16.0.0": - version: 16.0.6 - resolution: "@types/yargs@npm:16.0.6" - dependencies: - "@types/yargs-parser": "*" - checksum: 3531be5c8fc804405dffbba6f4f5486610e13a321e8c87a97c6e70f681bbdcb594d3259a0d3fdbeba2c38a8ef23dc5609dfffeb58fde0bdda95ce27e8c0ef265 - languageName: node - linkType: hard - -"@types/yargs@npm:^17.0.8": - version: 17.0.25 - resolution: "@types/yargs@npm:17.0.25" - dependencies: - "@types/yargs-parser": "*" - checksum: ef57926de514f5eb0a182167a63930bd7d2eb33d89b6041760f690d50b2019d7901b30c33ab7d03b3fa66a5004f0f81e36186d8f9e5e583a27b9ce331d2a5276 - languageName: node - linkType: hard - -"@typescript-eslint/eslint-plugin@npm:^5.5.0": - version: 5.62.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" - dependencies: - "@eslint-community/regexpp": ^4.4.0 - "@typescript-eslint/scope-manager": 5.62.0 - "@typescript-eslint/type-utils": 5.62.0 - "@typescript-eslint/utils": 5.62.0 - debug: ^4.3.4 - graphemer: ^1.4.0 - ignore: ^5.2.0 - natural-compare-lite: ^1.4.0 - semver: ^7.3.7 - tsutils: ^3.21.0 - peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: fc104b389c768f9fa7d45a48c86d5c1ad522c1d0512943e782a56b1e3096b2cbcc1eea3fcc590647bf0658eef61aac35120a9c6daf979bf629ad2956deb516a1 - languageName: node - linkType: hard - -"@typescript-eslint/experimental-utils@npm:^5.0.0": - version: 5.62.0 - resolution: "@typescript-eslint/experimental-utils@npm:5.62.0" - dependencies: - "@typescript-eslint/utils": 5.62.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: ce55d9f74eac5cb94d66d5db9ead9a5d734f4301519fb5956a57f4b405a5318a115b0316195a3c039e0111489138680411709cb769085d71e1e1db1376ea0949 - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:^5.5.0": - version: 5.62.0 - resolution: "@typescript-eslint/parser@npm:5.62.0" - dependencies: - "@typescript-eslint/scope-manager": 5.62.0 - "@typescript-eslint/types": 5.62.0 - "@typescript-eslint/typescript-estree": 5.62.0 - debug: ^4.3.4 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: d168f4c7f21a7a63f47002e2d319bcbb6173597af5c60c1cf2de046b46c76b4930a093619e69faf2d30214c29ab27b54dcf1efc7046a6a6bd6f37f59a990e752 - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/scope-manager@npm:5.62.0" - dependencies: - "@typescript-eslint/types": 5.62.0 - "@typescript-eslint/visitor-keys": 5.62.0 - checksum: 6062d6b797fe1ce4d275bb0d17204c827494af59b5eaf09d8a78cdd39dadddb31074dded4297aaf5d0f839016d601032857698b0e4516c86a41207de606e9573 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/type-utils@npm:5.62.0" - dependencies: - "@typescript-eslint/typescript-estree": 5.62.0 - "@typescript-eslint/utils": 5.62.0 - debug: ^4.3.4 - tsutils: ^3.21.0 - peerDependencies: - eslint: "*" - peerDependenciesMeta: - typescript: - optional: true - checksum: fc41eece5f315dfda14320be0da78d3a971d650ea41300be7196934b9715f3fe1120a80207551eb71d39568275dbbcf359bde540d1ca1439d8be15e9885d2739 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/types@npm:5.62.0" - checksum: 48c87117383d1864766486f24de34086155532b070f6264e09d0e6139449270f8a9559cfef3c56d16e3bcfb52d83d42105d61b36743626399c7c2b5e0ac3b670 - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" - dependencies: - "@typescript-eslint/types": 5.62.0 - "@typescript-eslint/visitor-keys": 5.62.0 - debug: ^4.3.4 - globby: ^11.1.0 - is-glob: ^4.0.3 - semver: ^7.3.7 - tsutils: ^3.21.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 3624520abb5807ed8f57b1197e61c7b1ed770c56dfcaca66372d584ff50175225798bccb701f7ef129d62c5989070e1ee3a0aa2d84e56d9524dcf011a2bb1a52 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.58.0": - version: 5.62.0 - resolution: "@typescript-eslint/utils@npm:5.62.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@types/json-schema": ^7.0.9 - "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.62.0 - "@typescript-eslint/types": 5.62.0 - "@typescript-eslint/typescript-estree": 5.62.0 - eslint-scope: ^5.1.1 - semver: ^7.3.7 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: ee9398c8c5db6d1da09463ca7bf36ed134361e20131ea354b2da16a5fdb6df9ba70c62a388d19f6eebb421af1786dbbd79ba95ddd6ab287324fc171c3e28d931 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" - dependencies: - "@typescript-eslint/types": 5.62.0 - eslint-visitor-keys: ^3.3.0 - checksum: 976b05d103fe8335bef5c93ad3f76d781e3ce50329c0243ee0f00c0fcfb186c81df50e64bfdd34970148113f8ade90887f53e3c4938183afba830b4ba8e30a35 - languageName: node - linkType: hard - -"@webassemblyjs/ast@npm:1.11.6, @webassemblyjs/ast@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/ast@npm:1.11.6" - dependencies: - "@webassemblyjs/helper-numbers": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - checksum: 38ef1b526ca47c210f30975b06df2faf1a8170b1636ce239fc5738fc231ce28389dd61ecedd1bacfc03cbe95b16d1af848c805652080cb60982836eb4ed2c6cf - languageName: node - linkType: hard - -"@webassemblyjs/floating-point-hex-parser@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.6" - checksum: 29b08758841fd8b299c7152eda36b9eb4921e9c584eb4594437b5cd90ed6b920523606eae7316175f89c20628da14326801090167cc7fbffc77af448ac84b7e2 - languageName: node - linkType: hard - -"@webassemblyjs/helper-api-error@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-api-error@npm:1.11.6" - checksum: e8563df85161096343008f9161adb138a6e8f3c2cc338d6a36011aa55eabb32f2fd138ffe63bc278d009ada001cc41d263dadd1c0be01be6c2ed99076103689f - languageName: node - linkType: hard - -"@webassemblyjs/helper-buffer@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-buffer@npm:1.11.6" - checksum: b14d0573bf680d22b2522e8a341ec451fddd645d1f9c6bd9012ccb7e587a2973b86ab7b89fe91e1c79939ba96095f503af04369a3b356c8023c13a5893221644 - languageName: node - linkType: hard - -"@webassemblyjs/helper-numbers@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-numbers@npm:1.11.6" - dependencies: - "@webassemblyjs/floating-point-hex-parser": 1.11.6 - "@webassemblyjs/helper-api-error": 1.11.6 - "@xtuc/long": 4.2.2 - checksum: f4b562fa219f84368528339e0f8d273ad44e047a07641ffcaaec6f93e5b76fd86490a009aa91a294584e1436d74b0a01fa9fde45e333a4c657b58168b04da424 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-bytecode@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.6" - checksum: 3535ef4f1fba38de3475e383b3980f4bbf3de72bbb631c2b6584c7df45be4eccd62c6ff48b5edd3f1bcff275cfd605a37679ec199fc91fd0a7705d7f1e3972dc - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-section@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - checksum: b2cf751bf4552b5b9999d27bbb7692d0aca75260140195cb58ea6374d7b9c2dc69b61e10b211a0e773f66209c3ddd612137ed66097e3684d7816f854997682e9 - languageName: node - linkType: hard - -"@webassemblyjs/ieee754@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/ieee754@npm:1.11.6" - dependencies: - "@xtuc/ieee754": ^1.2.0 - checksum: 13574b8e41f6ca39b700e292d7edf102577db5650fe8add7066a320aa4b7a7c09a5056feccac7a74eb68c10dea9546d4461412af351f13f6b24b5f32379b49de - languageName: node - linkType: hard - -"@webassemblyjs/leb128@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/leb128@npm:1.11.6" - dependencies: - "@xtuc/long": 4.2.2 - checksum: 7ea942dc9777d4b18a5ebfa3a937b30ae9e1d2ce1fee637583ed7f376334dd1d4274f813d2e250056cca803e0952def4b954913f1a3c9068bcd4ab4ee5143bf0 - languageName: node - linkType: hard - -"@webassemblyjs/utf8@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/utf8@npm:1.11.6" - checksum: 807fe5b5ce10c390cfdd93e0fb92abda8aebabb5199980681e7c3743ee3306a75729bcd1e56a3903980e96c885ee53ef901fcbaac8efdfa480f9c0dae1d08713 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-edit@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-edit@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/helper-wasm-section": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - "@webassemblyjs/wasm-opt": 1.11.6 - "@webassemblyjs/wasm-parser": 1.11.6 - "@webassemblyjs/wast-printer": 1.11.6 - checksum: 29ce75870496d6fad864d815ebb072395a8a3a04dc9c3f4e1ffdc63fc5fa58b1f34304a1117296d8240054cfdbc38aca88e71fb51483cf29ffab0a61ef27b481 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-gen@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-gen@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/ieee754": 1.11.6 - "@webassemblyjs/leb128": 1.11.6 - "@webassemblyjs/utf8": 1.11.6 - checksum: a645a2eecbea24833c3260a249704a7f554ef4a94c6000984728e94bb2bc9140a68dfd6fd21d5e0bbb09f6dfc98e083a45760a83ae0417b41a0196ff6d45a23a - languageName: node - linkType: hard - -"@webassemblyjs/wasm-opt@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-opt@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - "@webassemblyjs/wasm-parser": 1.11.6 - checksum: b4557f195487f8e97336ddf79f7bef40d788239169aac707f6eaa2fa5fe243557c2d74e550a8e57f2788e70c7ae4e7d32f7be16101afe183d597b747a3bdd528 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-parser@npm:1.11.6, @webassemblyjs/wasm-parser@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-parser@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-api-error": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/ieee754": 1.11.6 - "@webassemblyjs/leb128": 1.11.6 - "@webassemblyjs/utf8": 1.11.6 - checksum: 8200a8d77c15621724a23fdabe58d5571415cda98a7058f542e670ea965dd75499f5e34a48675184947c66f3df23adf55df060312e6d72d57908e3f049620d8a - languageName: node - linkType: hard - -"@webassemblyjs/wast-printer@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wast-printer@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@xtuc/long": 4.2.2 - checksum: d2fa6a4c427325ec81463e9c809aa6572af6d47f619f3091bf4c4a6fc34f1da3df7caddaac50b8e7a457f8784c62cd58c6311b6cb69b0162ccd8d4c072f79cf8 - languageName: node - linkType: hard - -"@xtuc/ieee754@npm:^1.2.0": - version: 1.2.0 - resolution: "@xtuc/ieee754@npm:1.2.0" - checksum: ac56d4ca6e17790f1b1677f978c0c6808b1900a5b138885d3da21732f62e30e8f0d9120fcf8f6edfff5100ca902b46f8dd7c1e3f903728634523981e80e2885a - languageName: node - linkType: hard - -"@xtuc/long@npm:4.2.2": - version: 4.2.2 - resolution: "@xtuc/long@npm:4.2.2" - checksum: 8ed0d477ce3bc9c6fe2bf6a6a2cc316bb9c4127c5a7827bae947fa8ec34c7092395c5a283cc300c05b5fa01cbbfa1f938f410a7bf75db7c7846fea41949989ec - languageName: node - linkType: hard - -"abab@npm:^2.0.3, abab@npm:^2.0.5": - version: 2.0.6 - resolution: "abab@npm:2.0.6" - checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e - languageName: node - linkType: hard - -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 - languageName: node - linkType: hard - -"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": - version: 1.3.8 - resolution: "accepts@npm:1.3.8" - dependencies: - mime-types: ~2.1.34 - negotiator: 0.6.3 - checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 - languageName: node - linkType: hard - -"acorn-globals@npm:^6.0.0": - version: 6.0.0 - resolution: "acorn-globals@npm:6.0.0" - dependencies: - acorn: ^7.1.1 - acorn-walk: ^7.1.1 - checksum: 72d95e5b5e585f9acd019b993ab8bbba68bb3cbc9d9b5c1ebb3c2f1fe5981f11deababfb4949f48e6262f9c57878837f5958c0cca396f81023814680ca878042 - languageName: node - linkType: hard - -"acorn-import-assertions@npm:^1.9.0": - version: 1.9.0 - resolution: "acorn-import-assertions@npm:1.9.0" - peerDependencies: - acorn: ^8 - checksum: 944fb2659d0845c467066bdcda2e20c05abe3aaf11972116df457ce2627628a81764d800dd55031ba19de513ee0d43bb771bc679cc0eda66dc8b4fade143bc0c - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 - languageName: node - linkType: hard - -"acorn-walk@npm:^7.1.1": - version: 7.2.0 - resolution: "acorn-walk@npm:7.2.0" - checksum: 9252158a79b9d92f1bc0dd6acc0fcfb87a67339e84bcc301bb33d6078936d27e35d606b4d35626d2962cd43c256d6f27717e70cbe15c04fff999ab0b2260b21f - languageName: node - linkType: hard - -"acorn@npm:^7.1.1": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" - bin: - acorn: bin/acorn - checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407 - languageName: node - linkType: hard - -"acorn@npm:^8.2.4, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" - bin: - acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d - languageName: node - linkType: hard - -"address@npm:^1.0.1, address@npm:^1.1.2": - version: 1.2.2 - resolution: "address@npm:1.2.2" - checksum: ace439960c1e3564d8f523aff23a841904bf33a2a7c2e064f7f60a064194075758b9690e65bd9785692a4ef698a998c57eb74d145881a1cecab8ba658ddb1607 - languageName: node - linkType: hard - -"adjust-sourcemap-loader@npm:^4.0.0": - version: 4.0.0 - resolution: "adjust-sourcemap-loader@npm:4.0.0" - dependencies: - loader-utils: ^2.0.0 - regex-parser: ^2.2.11 - checksum: d524ae23582f41e2275af5d88faab7a9dc09770ed588244e0a76d3196d0d6a90bf02760c71bc6213dbfef3aef4a86232ac9521bfd629752c32b7af37bc74c660 - languageName: node - linkType: hard - -"agent-base@npm:6, agent-base@npm:^6.0.2": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: 4 - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.2.1": - version: 4.5.0 - resolution: "agentkeepalive@npm:4.5.0" - dependencies: - humanize-ms: ^1.2.1 - checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ajv-formats@npm:^2.1.1": - version: 2.1.1 - resolution: "ajv-formats@npm:2.1.1" - dependencies: - ajv: ^8.0.0 - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - checksum: 4a287d937f1ebaad4683249a4c40c0fa3beed30d9ddc0adba04859026a622da0d317851316ea64b3680dc60f5c3c708105ddd5d5db8fe595d9d0207fd19f90b7 - languageName: node - linkType: hard - -"ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2": - version: 3.5.2 - resolution: "ajv-keywords@npm:3.5.2" - peerDependencies: - ajv: ^6.9.1 - checksum: 7dc5e5931677a680589050f79dcbe1fefbb8fea38a955af03724229139175b433c63c68f7ae5f86cf8f65d55eb7c25f75a046723e2e58296707617ca690feae9 - languageName: node - linkType: hard - -"ajv-keywords@npm:^5.1.0": - version: 5.1.0 - resolution: "ajv-keywords@npm:5.1.0" - dependencies: - fast-deep-equal: ^3.1.3 - peerDependencies: - ajv: ^8.8.2 - checksum: c35193940b853119242c6757787f09ecf89a2c19bcd36d03ed1a615e710d19d450cb448bfda407b939aba54b002368c8bff30529cc50a0536a8e10bcce300421 - languageName: node - linkType: hard - -"ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: ^3.1.1 - fast-json-stable-stringify: ^2.0.0 - json-schema-traverse: ^0.4.1 - uri-js: ^4.2.2 - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 - languageName: node - linkType: hard - -"ajv@npm:^8.0.0, ajv@npm:^8.6.0, ajv@npm:^8.9.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" - dependencies: - fast-deep-equal: ^3.1.1 - json-schema-traverse: ^1.0.0 - require-from-string: ^2.0.2 - uri-js: ^4.2.2 - checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 - languageName: node - linkType: hard - -"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.1": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: ^0.21.3 - checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 - languageName: node - linkType: hard - -"ansi-html-community@npm:^0.0.8": - version: 0.0.8 - resolution: "ansi-html-community@npm:0.0.8" - bin: - ansi-html: bin/ansi-html - checksum: 04c568e8348a636963f915e48eaa3e01218322e1169acafdd79c384f22e5558c003f79bbc480c1563865497482817c7eed025f0653ebc17642fededa5cb42089 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - languageName: node - linkType: hard - -"ansi-styles@npm:^3.2.1": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" - dependencies: - color-convert: ^1.9.0 - checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 - languageName: node - linkType: hard - -"ansi-styles@npm:^5.0.0": - version: 5.2.0 - resolution: "ansi-styles@npm:5.2.0" - checksum: d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 - languageName: node - linkType: hard - -"any-promise@npm:^1.0.0": - version: 1.3.0 - resolution: "any-promise@npm:1.3.0" - checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de - languageName: node - linkType: hard - -"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: ^3.0.0 - picomatch: ^2.0.4 - checksum: 3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 - languageName: node - linkType: hard - -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 - languageName: node - linkType: hard - -"arg@npm:^5.0.2": - version: 5.0.2 - resolution: "arg@npm:5.0.2" - checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 - languageName: node - linkType: hard - -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: ~1.0.2 - checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945 - languageName: node - linkType: hard - -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced - languageName: node - linkType: hard - -"aria-query@npm:5.1.3": - version: 5.1.3 - resolution: "aria-query@npm:5.1.3" - dependencies: - deep-equal: ^2.0.5 - checksum: 929ff95f02857b650fb4cbcd2f41072eee2f46159a6605ea03bf63aa572e35ffdff43d69e815ddc462e16e07de8faba3978afc2813650b4448ee18c9895d982b - languageName: node - linkType: hard - -"aria-query@npm:^5.0.0, aria-query@npm:^5.1.3": - version: 5.3.0 - resolution: "aria-query@npm:5.3.0" - dependencies: - dequal: ^2.0.3 - checksum: 305bd73c76756117b59aba121d08f413c7ff5e80fa1b98e217a3443fcddb9a232ee790e24e432b59ae7625aebcf4c47cb01c2cac872994f0b426f5bdfcd96ba9 - languageName: node - linkType: hard - -"array-buffer-byte-length@npm:^1.0.0": - version: 1.0.0 - resolution: "array-buffer-byte-length@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - is-array-buffer: ^3.0.1 - checksum: 044e101ce150f4804ad19c51d6c4d4cfa505c5b2577bd179256e4aa3f3f6a0a5e9874c78cd428ee566ac574c8a04d7ce21af9fe52e844abfdccb82b33035a7c3 - languageName: node - linkType: hard - -"array-flatten@npm:1.1.1": - version: 1.1.1 - resolution: "array-flatten@npm:1.1.1" - checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b - languageName: node - linkType: hard - -"array-flatten@npm:^2.1.2": - version: 2.1.2 - resolution: "array-flatten@npm:2.1.2" - checksum: e8988aac1fbfcdaae343d08c9a06a6fddd2c6141721eeeea45c3cf523bf4431d29a46602929455ed548c7a3e0769928cdc630405427297e7081bd118fdec9262 - languageName: node - linkType: hard - -"array-includes@npm:^3.1.6": - version: 3.1.7 - resolution: "array-includes@npm:3.1.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - get-intrinsic: ^1.2.1 - is-string: ^1.0.7 - checksum: 06f9e4598fac12a919f7c59a3f04f010ea07f0b7f0585465ed12ef528a60e45f374e79d1bddbb34cdd4338357d00023ddbd0ac18b0be36964f5e726e8965d7fc - languageName: node - linkType: hard - -"array-union@npm:^2.1.0": - version: 2.1.0 - resolution: "array-union@npm:2.1.0" - checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d - languageName: node - linkType: hard - -"array.prototype.findlastindex@npm:^1.2.2": - version: 1.2.3 - resolution: "array.prototype.findlastindex@npm:1.2.3" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - es-shim-unscopables: ^1.0.0 - get-intrinsic: ^1.2.1 - checksum: 31f35d7b370c84db56484618132041a9af401b338f51899c2e78ef7690fbba5909ee7ca3c59a7192085b328cc0c68c6fd1f6d1553db01a689a589ae510f3966e - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.1": - version: 1.3.2 - resolution: "array.prototype.flat@npm:1.3.2" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - es-shim-unscopables: ^1.0.0 - checksum: 5d6b4bf102065fb3f43764bfff6feb3295d372ce89591e6005df3d0ce388527a9f03c909af6f2a973969a4d178ab232ffc9236654149173e0e187ec3a1a6b87b - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.1": - version: 1.3.2 - resolution: "array.prototype.flatmap@npm:1.3.2" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - es-shim-unscopables: ^1.0.0 - checksum: ce09fe21dc0bcd4f30271f8144083aa8c13d4639074d6c8dc82054b847c7fc9a0c97f857491f4da19d4003e507172a78f4bcd12903098adac8b9cd374f734be3 - languageName: node - linkType: hard - -"array.prototype.reduce@npm:^1.0.6": - version: 1.0.6 - resolution: "array.prototype.reduce@npm:1.0.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - es-array-method-boxes-properly: ^1.0.0 - is-string: ^1.0.7 - checksum: c709c3f5caa2aac4fb10e0c6c1982cca50328a2a48658d53b1da8ee3a78069ad67cdac21296d6285521aa3a932a8178c0e192b5fc831fae2977b69a5a8a64ad7 - languageName: node - linkType: hard - -"array.prototype.tosorted@npm:^1.1.1": - version: 1.1.2 - resolution: "array.prototype.tosorted@npm:1.1.2" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - es-shim-unscopables: ^1.0.0 - get-intrinsic: ^1.2.1 - checksum: 3607a7d6b117f0ffa6f4012457b7af0d47d38cf05e01d50e09682fd2fb782a66093a5e5fbbdbad77c8c824794a9d892a51844041641f719ad41e3a974f0764de - languageName: node - linkType: hard - -"arraybuffer.prototype.slice@npm:^1.0.2": - version: 1.0.2 - resolution: "arraybuffer.prototype.slice@npm:1.0.2" - dependencies: - array-buffer-byte-length: ^1.0.0 - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - get-intrinsic: ^1.2.1 - is-array-buffer: ^3.0.2 - is-shared-array-buffer: ^1.0.2 - checksum: c200faf437786f5b2c80d4564ff5481c886a16dee642ef02abdc7306c7edd523d1f01d1dd12b769c7eb42ac9bc53874510db19a92a2c035c0f6696172aafa5d3 - languageName: node - linkType: hard - -"asap@npm:~2.0.6": - version: 2.0.6 - resolution: "asap@npm:2.0.6" - checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d - languageName: node - linkType: hard - -"ast-types-flow@npm:^0.0.7": - version: 0.0.7 - resolution: "ast-types-flow@npm:0.0.7" - checksum: a26dcc2182ffee111cad7c471759b0bda22d3b7ebacf27c348b22c55f16896b18ab0a4d03b85b4020dce7f3e634b8f00b593888f622915096ea1927fa51866c4 - languageName: node - linkType: hard - -"async@npm:^3.2.3": - version: 3.2.4 - resolution: "async@npm:3.2.4" - checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 - languageName: node - linkType: hard - -"asynciterator.prototype@npm:^1.0.0": - version: 1.0.0 - resolution: "asynciterator.prototype@npm:1.0.0" - dependencies: - has-symbols: ^1.0.3 - checksum: e8ebfd9493ac651cf9b4165e9d64030b3da1d17181bb1963627b59e240cdaf021d9b59d44b827dc1dde4e22387ec04c2d0f8720cf58a1c282e34e40cc12721b3 - languageName: node - linkType: hard - -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be - languageName: node - linkType: hard - -"at-least-node@npm:^1.0.0": - version: 1.0.0 - resolution: "at-least-node@npm:1.0.0" - checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e - languageName: node - linkType: hard - -"autoprefixer@npm:^10.4.13": - version: 10.4.16 - resolution: "autoprefixer@npm:10.4.16" - dependencies: - browserslist: ^4.21.10 - caniuse-lite: ^1.0.30001538 - fraction.js: ^4.3.6 - normalize-range: ^0.1.2 - picocolors: ^1.0.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: 45fad7086495048dacb14bb7b00313e70e135b5d8e8751dcc60548889400763705ab16fc2d99ea628b44c3472698fb0e39598f595ba28409c965ab159035afde - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.5": - version: 1.0.5 - resolution: "available-typed-arrays@npm:1.0.5" - checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a - languageName: node - linkType: hard - -"axe-core@npm:^4.6.2": - version: 4.8.2 - resolution: "axe-core@npm:4.8.2" - checksum: 8c19f507dabfcb8514e4280c7fc66e85143be303ddb57ec9f119338021228dc9b80560993938003837bda415fde7c07bba3a96560008ffa5f4145a248ed8f5fe - languageName: node - linkType: hard - -"axios@npm:^1.4.0": - version: 1.5.0 - resolution: "axios@npm:1.5.0" - dependencies: - follow-redirects: ^1.15.0 - form-data: ^4.0.0 - proxy-from-env: ^1.1.0 - checksum: e7405a5dbbea97760d0e6cd58fecba311b0401ddb4a8efbc4108f5537da9b3f278bde566deb777935a960beec4fa18e7b8353881f2f465e4f2c0e949fead35be - languageName: node - linkType: hard - -"axobject-query@npm:^3.1.1": - version: 3.2.1 - resolution: "axobject-query@npm:3.2.1" - dependencies: - dequal: ^2.0.3 - checksum: a94047e702b57c91680e6a952ec4a1aaa2cfd0d80ead76bc8c954202980d8c51968a6ea18b4d8010e8e2cf95676533d8022a8ebba9abc1dfe25686721df26fd2 - languageName: node - linkType: hard - -"babel-jest@npm:^27.4.2, babel-jest@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-jest@npm:27.5.1" - dependencies: - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/babel__core": ^7.1.14 - babel-plugin-istanbul: ^6.1.1 - babel-preset-jest: ^27.5.1 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - slash: ^3.0.0 - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 4e93e6e9fb996cc5f1505e924eb8e8cc7b25c294ba9629762a2715390f48af6a4c14dbb84cd9730013ac0e03267a5a9aa2fb6318c544489cda7f50f4e506def4 - languageName: node - linkType: hard - -"babel-loader@npm:^8.2.3": - version: 8.3.0 - resolution: "babel-loader@npm:8.3.0" - dependencies: - find-cache-dir: ^3.3.1 - loader-utils: ^2.0.0 - make-dir: ^3.1.0 - schema-utils: ^2.6.5 - peerDependencies: - "@babel/core": ^7.0.0 - webpack: ">=2" - checksum: d48bcf9e030e598656ad3ff5fb85967db2eaaf38af5b4a4b99d25618a2057f9f100e6b231af2a46c1913206db506115ca7a8cbdf52c9c73d767070dae4352ab5 - languageName: node - linkType: hard - -"babel-plugin-istanbul@npm:^6.1.1": - version: 6.1.1 - resolution: "babel-plugin-istanbul@npm:6.1.1" - dependencies: - "@babel/helper-plugin-utils": ^7.0.0 - "@istanbuljs/load-nyc-config": ^1.0.0 - "@istanbuljs/schema": ^0.1.2 - istanbul-lib-instrument: ^5.0.4 - test-exclude: ^6.0.0 - checksum: cb4fd95738219f232f0aece1116628cccff16db891713c4ccb501cddbbf9272951a5df81f2f2658dfdf4b3e7b236a9d5cbcf04d5d8c07dd5077297339598061a - languageName: node - linkType: hard - -"babel-plugin-jest-hoist@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-plugin-jest-hoist@npm:27.5.1" - dependencies: - "@babel/template": ^7.3.3 - "@babel/types": ^7.3.3 - "@types/babel__core": ^7.0.0 - "@types/babel__traverse": ^7.0.6 - checksum: 709c17727aa8fd3be755d256fb514bf945a5c2ea6017f037d80280fc44ae5fe7dfeebf63d8412df53796455c2c216119d628d8cc90b099434fd819005943d058 - languageName: node - linkType: hard - -"babel-plugin-macros@npm:^3.1.0": - version: 3.1.0 - resolution: "babel-plugin-macros@npm:3.1.0" - dependencies: - "@babel/runtime": ^7.12.5 - cosmiconfig: ^7.0.0 - resolve: ^1.19.0 - checksum: 765de4abebd3e4688ebdfbff8571ddc8cd8061f839bb6c3e550b0344a4027b04c60491f843296ce3f3379fb356cc873d57a9ee6694262547eb822c14a25be9a6 - languageName: node - linkType: hard - -"babel-plugin-named-asset-import@npm:^0.3.8": - version: 0.3.8 - resolution: "babel-plugin-named-asset-import@npm:0.3.8" - peerDependencies: - "@babel/core": ^7.1.0 - checksum: d1e58df8cb75d91d070feea31087bc989906d3465144bde7e9f3c3690b514a90a55d3aebf3e65e76c5d4c743ecedde5f640f09f43a21fa60f1a5d413cb3f7a67 - languageName: node - linkType: hard - -"babel-plugin-polyfill-corejs2@npm:^0.4.5": - version: 0.4.5 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.5" - dependencies: - "@babel/compat-data": ^7.22.6 - "@babel/helper-define-polyfill-provider": ^0.4.2 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 33a8e06aa54e2858d211c743d179f0487b03222f9ca1bfd7c4865bca243fca942a3358cb75f6bb894ed476cbddede834811fbd6903ff589f055821146f053e1a - languageName: node - linkType: hard - -"babel-plugin-polyfill-corejs3@npm:^0.8.3": - version: 0.8.4 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.4" - dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.2 - core-js-compat: ^3.32.2 - peerDependencies: - "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 7243241a5b978b1335d51bcbd1248d6c4df88f6b3726706e71e0392f111c59bbf01118c85bb0ed42dce65e90e8fc768d19eda0a81a321cbe54abd3df9a285dc8 - languageName: node - linkType: hard - -"babel-plugin-polyfill-regenerator@npm:^0.5.2": - version: 0.5.2 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.2" - dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.2 - peerDependencies: - "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: d962200f604016a9a09bc9b4aaf60a3db7af876bb65bcefaeac04d44ac9d9ec4037cf24ce117760cc141d7046b6394c7eb0320ba9665cb4a2ee64df2be187c93 - languageName: node - linkType: hard - -"babel-plugin-transform-react-remove-prop-types@npm:^0.4.24": - version: 0.4.24 - resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.24" - checksum: 54afe56d67f0d118c9da23996f39948e502a152b3f582eb6e8f163fcb76c2c1ea4e0cdd4f9fac5c0ef050eab4fe0a950b0b74aae6237bcc0d31d8fc4cc808d1a - languageName: node - linkType: hard - -"babel-preset-current-node-syntax@npm:^1.0.0": - version: 1.0.1 - resolution: "babel-preset-current-node-syntax@npm:1.0.1" - dependencies: - "@babel/plugin-syntax-async-generators": ^7.8.4 - "@babel/plugin-syntax-bigint": ^7.8.3 - "@babel/plugin-syntax-class-properties": ^7.8.3 - "@babel/plugin-syntax-import-meta": ^7.8.3 - "@babel/plugin-syntax-json-strings": ^7.8.3 - "@babel/plugin-syntax-logical-assignment-operators": ^7.8.3 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - "@babel/plugin-syntax-numeric-separator": ^7.8.3 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - "@babel/plugin-syntax-top-level-await": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: d118c2742498c5492c095bc8541f4076b253e705b5f1ad9a2e7d302d81a84866f0070346662355c8e25fc02caa28dc2da8d69bcd67794a0d60c4d6fab6913cc8 - languageName: node - linkType: hard - -"babel-preset-jest@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-preset-jest@npm:27.5.1" - dependencies: - babel-plugin-jest-hoist: ^27.5.1 - babel-preset-current-node-syntax: ^1.0.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 251bcea11c18fd9672fec104eadb45b43f117ceeb326fa7345ced778d4c1feab29343cd7a87a1dcfae4997d6c851a8b386d7f7213792da6e23b74f4443a8976d - languageName: node - linkType: hard - -"babel-preset-react-app@npm:^10.0.1": - version: 10.0.1 - resolution: "babel-preset-react-app@npm:10.0.1" - dependencies: - "@babel/core": ^7.16.0 - "@babel/plugin-proposal-class-properties": ^7.16.0 - "@babel/plugin-proposal-decorators": ^7.16.4 - "@babel/plugin-proposal-nullish-coalescing-operator": ^7.16.0 - "@babel/plugin-proposal-numeric-separator": ^7.16.0 - "@babel/plugin-proposal-optional-chaining": ^7.16.0 - "@babel/plugin-proposal-private-methods": ^7.16.0 - "@babel/plugin-transform-flow-strip-types": ^7.16.0 - "@babel/plugin-transform-react-display-name": ^7.16.0 - "@babel/plugin-transform-runtime": ^7.16.4 - "@babel/preset-env": ^7.16.4 - "@babel/preset-react": ^7.16.0 - "@babel/preset-typescript": ^7.16.0 - "@babel/runtime": ^7.16.3 - babel-plugin-macros: ^3.1.0 - babel-plugin-transform-react-remove-prop-types: ^0.4.24 - checksum: ee66043484e67b8aef2541976388299691478ea00834f3bb14b6b3d5edcd316a5ac95351f6ec084b41ee555cad820d4194280ad38ce51884fedc7e8946a57b74 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"batch@npm:0.6.1": - version: 0.6.1 - resolution: "batch@npm:0.6.1" - checksum: 61f9934c7378a51dce61b915586191078ef7f1c3eca707fdd58b96ff2ff56d9e0af2bdab66b1462301a73c73374239e6542d9821c0af787f3209a23365d07e7f - languageName: node - linkType: hard - -"bfj@npm:^7.0.2": - version: 7.1.0 - resolution: "bfj@npm:7.1.0" - dependencies: - bluebird: ^3.7.2 - check-types: ^11.2.3 - hoopy: ^0.1.4 - jsonpath: ^1.1.1 - tryer: ^1.0.1 - checksum: 36da9ed36c60f377a3f43bb0433092af7dc40442914b8155a1330ae86b1905640baf57e9c195ab83b36d6518b27cf8ed880adff663aa444c193be149e027d722 - languageName: node - linkType: hard - -"big.js@npm:^5.2.2": - version: 5.2.2 - resolution: "big.js@npm:5.2.2" - checksum: b89b6e8419b097a8fb4ed2399a1931a68c612bce3cfd5ca8c214b2d017531191070f990598de2fc6f3f993d91c0f08aa82697717f6b3b8732c9731866d233c9e - languageName: node - linkType: hard - -"binary-extensions@npm:^2.0.0": - version: 2.2.0 - resolution: "binary-extensions@npm:2.2.0" - checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 - languageName: node - linkType: hard - -"bluebird@npm:^3.7.2": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef - languageName: node - linkType: hard - -"body-parser@npm:1.20.1": - version: 1.20.1 - resolution: "body-parser@npm:1.20.1" - dependencies: - bytes: 3.1.2 - content-type: ~1.0.4 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: ~1.6.18 - unpipe: 1.0.0 - checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 - languageName: node - linkType: hard - -"bonjour-service@npm:^1.0.11": - version: 1.1.1 - resolution: "bonjour-service@npm:1.1.1" - dependencies: - array-flatten: ^2.1.2 - dns-equal: ^1.0.0 - fast-deep-equal: ^3.1.3 - multicast-dns: ^7.2.5 - checksum: 832d0cf78b91368fac8bb11fd7a714e46f4c4fb1bb14d7283bce614a6fb3aae2f3fe209aba5b4fa051811c1cab6921d073a83db8432fb23292f27dd4161fb0f1 - languageName: node - linkType: hard - -"boolbase@npm:^1.0.0, boolbase@npm:~1.0.0": - version: 1.0.0 - resolution: "boolbase@npm:1.0.0" - checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: ^1.0.0 - checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"braces@npm:^3.0.2, braces@npm:~3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" - dependencies: - fill-range: ^7.0.1 - checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 - languageName: node - linkType: hard - -"browser-process-hrtime@npm:^1.0.0": - version: 1.0.0 - resolution: "browser-process-hrtime@npm:1.0.0" - checksum: e30f868cdb770b1201afb714ad1575dd86366b6e861900884665fb627109b3cc757c40067d3bfee1ff2a29c835257ea30725a8018a9afd02ac1c24b408b1e45f - languageName: node - linkType: hard - -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9": - version: 4.21.11 - resolution: "browserslist@npm:4.21.11" - dependencies: - caniuse-lite: ^1.0.30001538 - electron-to-chromium: ^1.4.526 - node-releases: ^2.0.13 - update-browserslist-db: ^1.0.13 - bin: - browserslist: cli.js - checksum: 89377745428d32c7bbec37055bc4b9e48aa859418ea3886b13218d825f8ea3053640f90d8652844ae855941fec0bffd2d69cf933035d6f9224b427d48d31eddf - languageName: node - linkType: hard - -"bser@npm:2.1.1": - version: 2.1.1 - resolution: "bser@npm:2.1.1" - dependencies: - node-int64: ^0.4.0 - checksum: 9ba4dc58ce86300c862bffc3ae91f00b2a03b01ee07f3564beeeaf82aa243b8b03ba53f123b0b842c190d4399b94697970c8e7cf7b1ea44b61aa28c3526a4449 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb - languageName: node - linkType: hard - -"builtin-modules@npm:^3.1.0": - version: 3.3.0 - resolution: "builtin-modules@npm:3.3.0" - checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d - languageName: node - linkType: hard - -"bytes@npm:3.0.0": - version: 3.0.0 - resolution: "bytes@npm:3.0.0" - checksum: a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 - languageName: node - linkType: hard - -"bytes@npm:3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: e4bcd3948d289c5127591fbedf10c0b639ccbf00243504e4e127374a15c3bc8eed0d28d4aaab08ff6f1cf2abc0cce6ba3085ed32f4f90e82a5683ce0014e1b6e - languageName: node - linkType: hard - -"cacache@npm:^17.0.0": - version: 17.1.4 - resolution: "cacache@npm:17.1.4" - dependencies: - "@npmcli/fs": ^3.1.0 - fs-minipass: ^3.0.0 - glob: ^10.2.2 - lru-cache: ^7.7.1 - minipass: ^7.0.3 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - p-map: ^4.0.0 - ssri: ^10.0.0 - tar: ^6.1.11 - unique-filename: ^3.0.0 - checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" - dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 - languageName: node - linkType: hard - -"camel-case@npm:^4.1.2": - version: 4.1.2 - resolution: "camel-case@npm:4.1.2" - dependencies: - pascal-case: ^3.1.2 - tslib: ^2.0.3 - checksum: bcbd25cd253b3cbc69be3f535750137dbf2beb70f093bdc575f73f800acc8443d34fd52ab8f0a2413c34f1e8203139ffc88428d8863e4dfe530cfb257a379ad6 - languageName: node - linkType: hard - -"camelcase-css@npm:^2.0.1": - version: 2.0.1 - resolution: "camelcase-css@npm:2.0.1" - checksum: 1cec2b3b3dcb5026688a470b00299a8db7d904c4802845c353dbd12d9d248d3346949a814d83bfd988d4d2e5b9904c07efe76fecd195a1d4f05b543e7c0b56b1 - languageName: node - linkType: hard - -"camelcase@npm:^5.3.1": - version: 5.3.1 - resolution: "camelcase@npm:5.3.1" - checksum: e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b - languageName: node - linkType: hard - -"camelcase@npm:^6.2.0, camelcase@npm:^6.2.1": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d - languageName: node - linkType: hard - -"caniuse-api@npm:^3.0.0": - version: 3.0.0 - resolution: "caniuse-api@npm:3.0.0" - dependencies: - browserslist: ^4.0.0 - caniuse-lite: ^1.0.0 - lodash.memoize: ^4.1.2 - lodash.uniq: ^4.5.0 - checksum: db2a229383b20d0529b6b589dde99d7b6cb56ba371366f58cbbfa2929c9f42c01f873e2b6ef641d4eda9f0b4118de77dbb2805814670bdad4234bf08e720b0b4 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538": - version: 1.0.30001539 - resolution: "caniuse-lite@npm:1.0.30001539" - checksum: 8595905d6c7234173a4915439fdd69fa2c06b0272d56af63aee0df6114e1ee4727758af160c0db9844055f778e0ea27ed4714facf2e472a2e74d9f567f111f41 - languageName: node - linkType: hard - -"case-sensitive-paths-webpack-plugin@npm:^2.4.0": - version: 2.4.0 - resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0" - checksum: bcf469446eeee9ac0046e30860074ebb9aa4803aab9140e6bb72b600b23b1d70635690754be4504ce35cd99cdf05226bee8d894ba362a3f5485d5f6310fc6d02 - languageName: node - linkType: hard - -"chalk@npm:^2.4.1, chalk@npm:^2.4.2": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: ^3.2.1 - escape-string-regexp: ^1.0.5 - supports-color: ^5.3.0 - checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 - languageName: node - linkType: hard - -"chalk@npm:^3.0.0": - version: 3.0.0 - resolution: "chalk@npm:3.0.0" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: 8e3ddf3981c4da405ddbd7d9c8d91944ddf6e33d6837756979f7840a29272a69a5189ecae0ff84006750d6d1e92368d413335eab4db5476db6e6703a1d1e0505 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.2": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - -"char-regex@npm:^1.0.2": - version: 1.0.2 - resolution: "char-regex@npm:1.0.2" - checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 - languageName: node - linkType: hard - -"char-regex@npm:^2.0.0": - version: 2.0.1 - resolution: "char-regex@npm:2.0.1" - checksum: 8524c03fd7e58381dccf33babe885fe62731ae20755528b19c39945b8203479184f35247210dc9eeeef279cdbdd6511cd3182e0e1db8e4549bf2586470b7c204 - languageName: node - linkType: hard - -"check-types@npm:^11.2.3": - version: 11.2.3 - resolution: "check-types@npm:11.2.3" - checksum: f99ff09ae65e63cfcfa40a1275c0a70d8c43ffbf9ac35095f3bf030cc70361c92e075a9975a1144329e50b4fe4620be6bedb4568c18abc96071a3e23aed3ed8e - languageName: node - linkType: hard - -"chokidar@npm:^3.4.2, chokidar@npm:^3.5.3": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" - dependencies: - anymatch: ~3.1.2 - braces: ~3.0.2 - fsevents: ~2.3.2 - glob-parent: ~5.1.2 - is-binary-path: ~2.1.0 - is-glob: ~4.0.1 - normalize-path: ~3.0.0 - readdirp: ~3.6.0 - dependenciesMeta: - fsevents: - optional: true - checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"chrome-trace-event@npm:^1.0.2": - version: 1.0.3 - resolution: "chrome-trace-event@npm:1.0.3" - checksum: cb8b1fc7e881aaef973bd0c4a43cd353c2ad8323fb471a041e64f7c2dd849cde4aad15f8b753331a32dda45c973f032c8a03b8177fc85d60eaa75e91e08bfb97 - languageName: node - linkType: hard - -"ci-info@npm:^3.2.0": - version: 3.8.0 - resolution: "ci-info@npm:3.8.0" - checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 - languageName: node - linkType: hard - -"cjs-module-lexer@npm:^1.0.0": - version: 1.2.3 - resolution: "cjs-module-lexer@npm:1.2.3" - checksum: 5ea3cb867a9bb609b6d476cd86590d105f3cfd6514db38ff71f63992ab40939c2feb68967faa15a6d2b1f90daa6416b79ea2de486e9e2485a6f8b66a21b4fb0a - languageName: node - linkType: hard - -"clean-css@npm:^5.2.2": - version: 5.3.2 - resolution: "clean-css@npm:5.3.2" - dependencies: - source-map: ~0.6.0 - checksum: 8787b281acc9878f309b5f835d410085deedfd4e126472666773040a6a8a72f472a1d24185947d23b87b1c419bf2c5ed429395d5c5ff8279c98b05d8011e9758 - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"client@workspace:.": - version: 0.0.0-use.local - resolution: "client@workspace:." - dependencies: - "@testing-library/jest-dom": ^5.17.0 - "@testing-library/react": ^13.4.0 - "@testing-library/user-event": ^13.5.0 - axios: ^1.4.0 - react: ^18.2.0 - react-cookie: ^5.0.0 - react-dom: ^18.2.0 - react-router-dom: ^6.15.0 - react-scripts: 5.0.1 - web-vitals: ^2.1.4 - languageName: unknown - linkType: soft - -"cliui@npm:^7.0.2": - version: 7.0.4 - resolution: "cliui@npm:7.0.4" - dependencies: - string-width: ^4.2.0 - strip-ansi: ^6.0.0 - wrap-ansi: ^7.0.0 - checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f - languageName: node - linkType: hard - -"co@npm:^4.6.0": - version: 4.6.0 - resolution: "co@npm:4.6.0" - checksum: 5210d9223010eb95b29df06a91116f2cf7c8e0748a9013ed853b53f362ea0e822f1e5bb054fb3cefc645239a4cf966af1f6133a3b43f40d591f3b68ed6cf0510 - languageName: node - linkType: hard - -"coa@npm:^2.0.2": - version: 2.0.2 - resolution: "coa@npm:2.0.2" - dependencies: - "@types/q": ^1.5.1 - chalk: ^2.4.1 - q: ^1.1.2 - checksum: 44736914aac2160d3d840ed64432a90a3bb72285a0cd6a688eb5cabdf15d15a85eee0915b3f6f2a4659d5075817b1cb577340d3c9cbb47d636d59ab69f819552 - languageName: node - linkType: hard - -"collect-v8-coverage@npm:^1.0.0": - version: 1.0.2 - resolution: "collect-v8-coverage@npm:1.0.2" - checksum: c10f41c39ab84629d16f9f6137bc8a63d332244383fc368caf2d2052b5e04c20cd1fd70f66fcf4e2422b84c8226598b776d39d5f2d2a51867cc1ed5d1982b4da - languageName: node - linkType: hard - -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: 1.1.3 - checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: ~1.1.4 - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 - languageName: node - linkType: hard - -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b - languageName: node - linkType: hard - -"colord@npm:^2.9.1": - version: 2.9.3 - resolution: "colord@npm:2.9.3" - checksum: 95d909bfbcfd8d5605cbb5af56f2d1ce2b323990258fd7c0d2eb0e6d3bb177254d7fb8213758db56bb4ede708964f78c6b992b326615f81a18a6aaf11d64c650 - languageName: node - linkType: hard - -"colorette@npm:^2.0.10": - version: 2.0.20 - resolution: "colorette@npm:2.0.20" - checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d - languageName: node - linkType: hard - -"combined-stream@npm:^1.0.8": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: ~1.0.0 - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c - languageName: node - linkType: hard - -"commander@npm:^2.20.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e - languageName: node - linkType: hard - -"commander@npm:^4.0.0": - version: 4.1.1 - resolution: "commander@npm:4.1.1" - checksum: d7b9913ff92cae20cb577a4ac6fcc121bd6223319e54a40f51a14740a681ad5c574fd29a57da478a5f234a6fa6c52cbf0b7c641353e03c648b1ae85ba670b977 - languageName: node - linkType: hard - -"commander@npm:^7.2.0": - version: 7.2.0 - resolution: "commander@npm:7.2.0" - checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc - languageName: node - linkType: hard - -"commander@npm:^8.3.0": - version: 8.3.0 - resolution: "commander@npm:8.3.0" - checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 - languageName: node - linkType: hard - -"common-path-prefix@npm:^3.0.0": - version: 3.0.0 - resolution: "common-path-prefix@npm:3.0.0" - checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 - languageName: node - linkType: hard - -"common-tags@npm:^1.8.0": - version: 1.8.2 - resolution: "common-tags@npm:1.8.2" - checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff - languageName: node - linkType: hard - -"commondir@npm:^1.0.1": - version: 1.0.1 - resolution: "commondir@npm:1.0.1" - checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb - languageName: node - linkType: hard - -"compressible@npm:~2.0.16": - version: 2.0.18 - resolution: "compressible@npm:2.0.18" - dependencies: - mime-db: ">= 1.43.0 < 2" - checksum: 58321a85b375d39230405654721353f709d0c1442129e9a17081771b816302a012471a9b8f4864c7dbe02eef7f2aaac3c614795197092262e94b409c9be108f0 - languageName: node - linkType: hard - -"compression@npm:^1.7.4": - version: 1.7.4 - resolution: "compression@npm:1.7.4" - dependencies: - accepts: ~1.3.5 - bytes: 3.0.0 - compressible: ~2.0.16 - debug: 2.6.9 - on-headers: ~1.0.2 - safe-buffer: 5.1.2 - vary: ~1.1.2 - checksum: 35c0f2eb1f28418978615dc1bc02075b34b1568f7f56c62d60f4214d4b7cc00d0f6d282b5f8a954f59872396bd770b6b15ffd8aa94c67d4bce9b8887b906999b - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af - languageName: node - linkType: hard - -"confusing-browser-globals@npm:^1.0.11": - version: 1.0.11 - resolution: "confusing-browser-globals@npm:1.0.11" - checksum: 3afc635abd37e566477f610e7978b15753f0e84025c25d49236f1f14d480117185516bdd40d2a2167e6bed8048641a9854964b9c067e3dcdfa6b5d0ad3c3a5ef - languageName: node - linkType: hard - -"connect-history-api-fallback@npm:^2.0.0": - version: 2.0.0 - resolution: "connect-history-api-fallback@npm:2.0.0" - checksum: dc5368690f4a5c413889792f8df70d5941ca9da44523cde3f87af0745faee5ee16afb8195434550f0504726642734f2683d6c07f8b460f828a12c45fbd4c9a68 - languageName: node - linkType: hard - -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed - languageName: node - linkType: hard - -"content-disposition@npm:0.5.4": - version: 0.5.4 - resolution: "content-disposition@npm:0.5.4" - dependencies: - safe-buffer: 5.2.1 - checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 - languageName: node - linkType: hard - -"content-type@npm:~1.0.4": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 - languageName: node - linkType: hard - -"convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 - languageName: node - linkType: hard - -"cookie-signature@npm:1.0.6": - version: 1.0.6 - resolution: "cookie-signature@npm:1.0.6" - checksum: f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a - languageName: node - linkType: hard - -"cookie@npm:0.5.0": - version: 0.5.0 - resolution: "cookie@npm:0.5.0" - checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 - languageName: node - linkType: hard - -"cookie@npm:^0.4.0": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: a00833c998bedf8e787b4c342defe5fa419abd96b32f4464f718b91022586b8f1bafbddd499288e75c037642493c83083da426c6a9080d309e3bd90fd11baa9b - languageName: node - linkType: hard - -"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.32.2": - version: 3.32.2 - resolution: "core-js-compat@npm:3.32.2" - dependencies: - browserslist: ^4.21.10 - checksum: efca146ad71a542e6f196db5ba5aed617e48c615bdf1fbb065471b3267f833ac545bd5fc5ad0642c3d3974b955f0684ff0863d7471d7050ee0284e0a1313942e - languageName: node - linkType: hard - -"core-js-pure@npm:^3.23.3": - version: 3.32.2 - resolution: "core-js-pure@npm:3.32.2" - checksum: 19e781c624aee4003f8980f3c4fc441c16ef671473151affe114dc37cfe18958acdb42241b14827f62277f2d6eea73658f6c2e09131be20619e2859426bd03b4 - languageName: node - linkType: hard - -"core-js@npm:^3.19.2": - version: 3.32.2 - resolution: "core-js@npm:3.32.2" - checksum: d6fac7e8eb054eefc211c76cd0a0ff07447a917122757d085f469f046ec888d122409c7db1a9601c3eb5fa767608ed380bcd219eace02bdf973da155680edeec - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 - languageName: node - linkType: hard - -"cosmiconfig@npm:^6.0.0": - version: 6.0.0 - resolution: "cosmiconfig@npm:6.0.0" - dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.1.0 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.7.2 - checksum: 8eed7c854b91643ecb820767d0deb038b50780ecc3d53b0b19e03ed8aabed4ae77271198d1ae3d49c3b110867edf679f5faad924820a8d1774144a87cb6f98fc - languageName: node - linkType: hard - -"cosmiconfig@npm:^7.0.0": - version: 7.1.0 - resolution: "cosmiconfig@npm:7.1.0" - dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.2.1 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.10.0 - checksum: c53bf7befc1591b2651a22414a5e786cd5f2eeaa87f3678a3d49d6069835a9d8d1aef223728e98aa8fec9a95bf831120d245096db12abe019fecb51f5696c96f - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: ^3.1.0 - shebang-command: ^2.0.0 - which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 - languageName: node - linkType: hard - -"crypto-random-string@npm:^2.0.0": - version: 2.0.0 - resolution: "crypto-random-string@npm:2.0.0" - checksum: 0283879f55e7c16fdceacc181f87a0a65c53bc16ffe1d58b9d19a6277adcd71900d02bb2c4843dd55e78c51e30e89b0fec618a7f170ebcc95b33182c28f05fd6 - languageName: node - linkType: hard - -"css-blank-pseudo@npm:^3.0.3": - version: 3.0.3 - resolution: "css-blank-pseudo@npm:3.0.3" - dependencies: - postcss-selector-parser: ^6.0.9 - peerDependencies: - postcss: ^8.4 - bin: - css-blank-pseudo: dist/cli.cjs - checksum: 9be0a13885a99d8ba9e1f45ea66e801d4da75b58c1c3c516a40772fa3a93ef9952b15dcac0418acbb6c89daaae0572819647701b8e553a02972826e33d4cd67f - languageName: node - linkType: hard - -"css-declaration-sorter@npm:^6.3.1": - version: 6.4.1 - resolution: "css-declaration-sorter@npm:6.4.1" - peerDependencies: - postcss: ^8.0.9 - checksum: cbdc9e0d481011b1a28fd5b60d4eb55fe204391d31a0b1b490b2cecf4baa85810f9b8c48adab4df644f4718104ed3ed72c64a9745e3216173767bf4aeca7f9b8 - languageName: node - linkType: hard - -"css-has-pseudo@npm:^3.0.4": - version: 3.0.4 - resolution: "css-has-pseudo@npm:3.0.4" - dependencies: - postcss-selector-parser: ^6.0.9 - peerDependencies: - postcss: ^8.4 - bin: - css-has-pseudo: dist/cli.cjs - checksum: 8f165d68f6621891d9fa1d874794916a52ed8847dfbec591523ad68774650cc1eae062ba08f59514666e04aeba27be72c9b211892f3a187c5ba6e287bd4260e7 - languageName: node - linkType: hard - -"css-loader@npm:^6.5.1": - version: 6.8.1 - resolution: "css-loader@npm:6.8.1" - dependencies: - icss-utils: ^5.1.0 - postcss: ^8.4.21 - postcss-modules-extract-imports: ^3.0.0 - postcss-modules-local-by-default: ^4.0.3 - postcss-modules-scope: ^3.0.0 - postcss-modules-values: ^4.0.0 - postcss-value-parser: ^4.2.0 - semver: ^7.3.8 - peerDependencies: - webpack: ^5.0.0 - checksum: 7c1784247bdbe76dc5c55fb1ac84f1d4177a74c47259942c9cfdb7a8e6baef11967a0bc85ac285f26bd26d5059decb848af8154a03fdb4f4894f41212f45eef3 - languageName: node - linkType: hard - -"css-minimizer-webpack-plugin@npm:^3.2.0": - version: 3.4.1 - resolution: "css-minimizer-webpack-plugin@npm:3.4.1" - dependencies: - cssnano: ^5.0.6 - jest-worker: ^27.0.2 - postcss: ^8.3.5 - schema-utils: ^4.0.0 - serialize-javascript: ^6.0.0 - source-map: ^0.6.1 - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - "@parcel/css": - optional: true - clean-css: - optional: true - csso: - optional: true - esbuild: - optional: true - checksum: 065c6c1eadb7c99267db5d04d6f3909e9968b73c4cb79ab9e4502a5fbf1a3d564cfe6f8e0bff8e4ab00d4ed233e9c3c76a4ebe0ee89150b3d9ecb064ddf1e5e9 - languageName: node - linkType: hard - -"css-prefers-color-scheme@npm:^6.0.3": - version: 6.0.3 - resolution: "css-prefers-color-scheme@npm:6.0.3" - peerDependencies: - postcss: ^8.4 - bin: - css-prefers-color-scheme: dist/cli.cjs - checksum: 3a2b02f0454adda68861cdcaf6a0d11f462eadf165301cba61c5ec7c5f229ac261c5baa54c377d9b811ec5f21b30d72a02bc032cdad2415b3a566f08a0c47b3a - languageName: node - linkType: hard - -"css-select-base-adapter@npm:^0.1.1": - version: 0.1.1 - resolution: "css-select-base-adapter@npm:0.1.1" - checksum: c107e9cfa53a23427e4537451a67358375e656baa3322345a982d3c2751fb3904002aae7e5d72386c59f766fe6b109d1ffb43eeab1c16f069f7a3828eb17851c - languageName: node - linkType: hard - -"css-select@npm:^2.0.0": - version: 2.1.0 - resolution: "css-select@npm:2.1.0" - dependencies: - boolbase: ^1.0.0 - css-what: ^3.2.1 - domutils: ^1.7.0 - nth-check: ^1.0.2 - checksum: 0c4099910f2411e2a9103cf92ea6a4ad738b57da75bcf73d39ef2c14a00ef36e5f16cb863211c901320618b24ace74da6333442d82995cafd5040077307de462 - languageName: node - linkType: hard - -"css-select@npm:^4.1.3": - version: 4.3.0 - resolution: "css-select@npm:4.3.0" - dependencies: - boolbase: ^1.0.0 - css-what: ^6.0.1 - domhandler: ^4.3.1 - domutils: ^2.8.0 - nth-check: ^2.0.1 - checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 - languageName: node - linkType: hard - -"css-tree@npm:1.0.0-alpha.37": - version: 1.0.0-alpha.37 - resolution: "css-tree@npm:1.0.0-alpha.37" - dependencies: - mdn-data: 2.0.4 - source-map: ^0.6.1 - checksum: 0e419a1388ec0fbbe92885fba4a557f9fb0e077a2a1fad629b7245bbf7b4ef5df49e6877401b952b09b9057ffe1a3dba74f6fdfbf7b2223a5a35bce27ff2307d - languageName: node - linkType: hard - -"css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": - version: 1.1.3 - resolution: "css-tree@npm:1.1.3" - dependencies: - mdn-data: 2.0.14 - source-map: ^0.6.1 - checksum: 79f9b81803991b6977b7fcb1588799270438274d89066ce08f117f5cdb5e20019b446d766c61506dd772c839df84caa16042d6076f20c97187f5abe3b50e7d1f - languageName: node - linkType: hard - -"css-what@npm:^3.2.1": - version: 3.4.2 - resolution: "css-what@npm:3.4.2" - checksum: 26bb5ec3ae718393d418016365c849fa14bd0de408c735dea3ddf58146b6cc54f3b336fb4afd31d95c06ca79583acbcdfec7ee93d31ff5c1a697df135b38dfeb - languageName: node - linkType: hard - -"css-what@npm:^6.0.1": - version: 6.1.0 - resolution: "css-what@npm:6.1.0" - checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe - languageName: node - linkType: hard - -"css.escape@npm:^1.5.1": - version: 1.5.1 - resolution: "css.escape@npm:1.5.1" - checksum: f6d38088d870a961794a2580b2b2af1027731bb43261cfdce14f19238a88664b351cc8978abc20f06cc6bbde725699dec8deb6fe9816b139fc3f2af28719e774 - languageName: node - linkType: hard - -"cssdb@npm:^7.1.0": - version: 7.7.2 - resolution: "cssdb@npm:7.7.2" - checksum: 74a8b46fc694b8576686dde6acbf0a28b07a1a1ff01b24c0c3de12e4680f2124d4beb3367b97ec309938d32306e1806fe5e209f8c899f120349cdfb5d327b727 - languageName: node - linkType: hard - -"cssesc@npm:^3.0.0": - version: 3.0.0 - resolution: "cssesc@npm:3.0.0" - bin: - cssesc: bin/cssesc - checksum: f8c4ababffbc5e2ddf2fa9957dda1ee4af6048e22aeda1869d0d00843223c1b13ad3f5d88b51caa46c994225eacb636b764eb807a8883e2fb6f99b4f4e8c48b2 - languageName: node - linkType: hard - -"cssnano-preset-default@npm:^5.2.14": - version: 5.2.14 - resolution: "cssnano-preset-default@npm:5.2.14" - dependencies: - css-declaration-sorter: ^6.3.1 - cssnano-utils: ^3.1.0 - postcss-calc: ^8.2.3 - postcss-colormin: ^5.3.1 - postcss-convert-values: ^5.1.3 - postcss-discard-comments: ^5.1.2 - postcss-discard-duplicates: ^5.1.0 - postcss-discard-empty: ^5.1.1 - postcss-discard-overridden: ^5.1.0 - postcss-merge-longhand: ^5.1.7 - postcss-merge-rules: ^5.1.4 - postcss-minify-font-values: ^5.1.0 - postcss-minify-gradients: ^5.1.1 - postcss-minify-params: ^5.1.4 - postcss-minify-selectors: ^5.2.1 - postcss-normalize-charset: ^5.1.0 - postcss-normalize-display-values: ^5.1.0 - postcss-normalize-positions: ^5.1.1 - postcss-normalize-repeat-style: ^5.1.1 - postcss-normalize-string: ^5.1.0 - postcss-normalize-timing-functions: ^5.1.0 - postcss-normalize-unicode: ^5.1.1 - postcss-normalize-url: ^5.1.0 - postcss-normalize-whitespace: ^5.1.1 - postcss-ordered-values: ^5.1.3 - postcss-reduce-initial: ^5.1.2 - postcss-reduce-transforms: ^5.1.0 - postcss-svgo: ^5.1.0 - postcss-unique-selectors: ^5.1.1 - peerDependencies: - postcss: ^8.2.15 - checksum: d3bbbe3d50c6174afb28d0bdb65b511fdab33952ec84810aef58b87189f3891c34aaa8b6a6101acd5314f8acded839b43513e39a75f91a698ddc985a1b1d9e95 - languageName: node - linkType: hard - -"cssnano-utils@npm:^3.1.0": - version: 3.1.0 - resolution: "cssnano-utils@npm:3.1.0" - peerDependencies: - postcss: ^8.2.15 - checksum: 975c84ce9174cf23bb1da1e9faed8421954607e9ea76440cd3bb0c1bea7e17e490d800fca5ae2812d1d9e9d5524eef23ede0a3f52497d7ccc628e5d7321536f2 - languageName: node - linkType: hard - -"cssnano@npm:^5.0.6": - version: 5.1.15 - resolution: "cssnano@npm:5.1.15" - dependencies: - cssnano-preset-default: ^5.2.14 - lilconfig: ^2.0.3 - yaml: ^1.10.2 - peerDependencies: - postcss: ^8.2.15 - checksum: ca9e1922178617c66c2f1548824b2c7af2ecf69cc3a187fc96bf8d29251c2e84d9e4966c69cf64a2a6a057a37dff7d6d057bc8a2a0957e6ea382e452ae9d0bbb - languageName: node - linkType: hard - -"csso@npm:^4.0.2, csso@npm:^4.2.0": - version: 4.2.0 - resolution: "csso@npm:4.2.0" - dependencies: - css-tree: ^1.1.2 - checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 - languageName: node - linkType: hard - -"cssom@npm:^0.4.4": - version: 0.4.4 - resolution: "cssom@npm:0.4.4" - checksum: e3bc1076e7ee4213d4fef05e7ae03bfa83dc05f32611d8edc341f4ecc3d9647b89c8245474c7dd2cdcdb797a27c462e99da7ad00a34399694559f763478ff53f - languageName: node - linkType: hard - -"cssom@npm:~0.3.6": - version: 0.3.8 - resolution: "cssom@npm:0.3.8" - checksum: 24beb3087c76c0d52dd458be9ee1fbc80ac771478a9baef35dd258cdeb527c68eb43204dd439692bb2b1ae5272fa5f2946d10946edab0d04f1078f85e06bc7f6 - languageName: node - linkType: hard - -"cssstyle@npm:^2.3.0": - version: 2.3.0 - resolution: "cssstyle@npm:2.3.0" - dependencies: - cssom: ~0.3.6 - checksum: 5f05e6fd2e3df0b44695c2f08b9ef38b011862b274e320665176467c0725e44a53e341bc4959a41176e83b66064ab786262e7380fd1cabeae6efee0d255bb4e3 - languageName: node - linkType: hard - -"csstype@npm:^3.0.2": - version: 3.1.2 - resolution: "csstype@npm:3.1.2" - checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5 - languageName: node - linkType: hard - -"damerau-levenshtein@npm:^1.0.8": - version: 1.0.8 - resolution: "damerau-levenshtein@npm:1.0.8" - checksum: d240b7757544460ae0586a341a53110ab0a61126570ef2d8c731e3eab3f0cb6e488e2609e6a69b46727635de49be20b071688698744417ff1b6c1d7ccd03e0de - languageName: node - linkType: hard - -"data-urls@npm:^2.0.0": - version: 2.0.0 - resolution: "data-urls@npm:2.0.0" - dependencies: - abab: ^2.0.3 - whatwg-mimetype: ^2.3.0 - whatwg-url: ^8.0.0 - checksum: 97caf828aac25e25e04ba6869db0f99c75e6859bb5b424ada28d3e7841941ebf08ddff3c1b1bb4585986bd507a5d54c2a716853ea6cb98af877400e637393e71 - languageName: node - linkType: hard - -"debug@npm:2.6.9, debug@npm:^2.6.0": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: 2.0.0 - checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": - version: 4.3.4 - resolution: "debug@npm:4.3.4" - dependencies: - ms: 2.1.2 - peerDependenciesMeta: - supports-color: - optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 - languageName: node - linkType: hard - -"debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: ^2.1.1 - checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c - languageName: node - linkType: hard - -"decimal.js@npm:^10.2.1": - version: 10.4.3 - resolution: "decimal.js@npm:10.4.3" - checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae - languageName: node - linkType: hard - -"dedent@npm:^0.7.0": - version: 0.7.0 - resolution: "dedent@npm:0.7.0" - checksum: 87de191050d9a40dd70cad01159a0bcf05ecb59750951242070b6abf9569088684880d00ba92a955b4058804f16eeaf91d604f283929b4f614d181cd7ae633d2 - languageName: node - linkType: hard - -"deep-equal@npm:^2.0.5": - version: 2.2.2 - resolution: "deep-equal@npm:2.2.2" - dependencies: - array-buffer-byte-length: ^1.0.0 - call-bind: ^1.0.2 - es-get-iterator: ^1.1.3 - get-intrinsic: ^1.2.1 - is-arguments: ^1.1.1 - is-array-buffer: ^3.0.2 - is-date-object: ^1.0.5 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - isarray: ^2.0.5 - object-is: ^1.1.5 - object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.0 - side-channel: ^1.0.4 - which-boxed-primitive: ^1.0.2 - which-collection: ^1.0.1 - which-typed-array: ^1.1.9 - checksum: eb61c35157b6ecb96a5359b507b083fbff8ddb4c86a78a781ee38485f77a667465e45d63ee2ebd8a00e86d94c80e499906900cd82c2debb400237e1662cd5397 - languageName: node - linkType: hard - -"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 - languageName: node - linkType: hard - -"deepmerge@npm:^4.2.2": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 - languageName: node - linkType: hard - -"default-gateway@npm:^6.0.3": - version: 6.0.3 - resolution: "default-gateway@npm:6.0.3" - dependencies: - execa: ^5.0.0 - checksum: 126f8273ecac8ee9ff91ea778e8784f6cd732d77c3157e8c5bdd6ed03651b5291f71446d05bc02d04073b1e67583604db5394ea3cf992ede0088c70ea15b7378 - languageName: node - linkType: hard - -"define-data-property@npm:^1.0.1": - version: 1.1.0 - resolution: "define-data-property@npm:1.1.0" - dependencies: - get-intrinsic: ^1.2.1 - gopd: ^1.0.1 - has-property-descriptors: ^1.0.0 - checksum: 7ad4ee84cca8ad427a4831f5693526804b62ce9dfd4efac77214e95a4382aed930072251d4075dc8dc9fc949a353ed51f19f5285a84a788ba9216cc51472a093 - languageName: node - linkType: hard - -"define-lazy-prop@npm:^2.0.0": - version: 2.0.0 - resolution: "define-lazy-prop@npm:2.0.0" - checksum: 0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 - languageName: node - linkType: hard - -"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: ^1.0.1 - has-property-descriptors: ^1.0.0 - object-keys: ^1.1.1 - checksum: b4ccd00597dd46cb2d4a379398f5b19fca84a16f3374e2249201992f36b30f6835949a9429669ee6b41b6e837205a163eadd745e472069e70dfc10f03e5fcc12 - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd - languageName: node - linkType: hard - -"depd@npm:2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a - languageName: node - linkType: hard - -"depd@npm:~1.1.2": - version: 1.1.2 - resolution: "depd@npm:1.1.2" - checksum: 6b406620d269619852885ce15965272b829df6f409724415e0002c8632ab6a8c0a08ec1f0bd2add05dc7bd7507606f7e2cc034fa24224ab829580040b835ecd9 - languageName: node - linkType: hard - -"dequal@npm:^2.0.3": - version: 2.0.3 - resolution: "dequal@npm:2.0.3" - checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 - languageName: node - linkType: hard - -"destroy@npm:1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 - languageName: node - linkType: hard - -"detect-newline@npm:^3.0.0": - version: 3.1.0 - resolution: "detect-newline@npm:3.1.0" - checksum: ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 - languageName: node - linkType: hard - -"detect-node@npm:^2.0.4": - version: 2.1.0 - resolution: "detect-node@npm:2.1.0" - checksum: 832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e - languageName: node - linkType: hard - -"detect-port-alt@npm:^1.1.6": - version: 1.1.6 - resolution: "detect-port-alt@npm:1.1.6" - dependencies: - address: ^1.0.1 - debug: ^2.6.0 - bin: - detect: ./bin/detect-port - detect-port: ./bin/detect-port - checksum: 9dc37b1fa4a9dd6d4889e1045849b8d841232b598d1ca888bf712f4035b07a17cf6d537465a0d7323250048d3a5a0540e3b7cf89457efc222f96f77e2c40d16a - languageName: node - linkType: hard - -"didyoumean@npm:^1.2.2": - version: 1.2.2 - resolution: "didyoumean@npm:1.2.2" - checksum: d5d98719d58b3c2fa59663c4c42ba9716f1fd01245c31d5fce31915bd3aa26e6aac149788e007358f778ebbd68a2256eb5973e8ca6f221df221ba060115acf2e - languageName: node - linkType: hard - -"diff-sequences@npm:^27.5.1": - version: 27.5.1 - resolution: "diff-sequences@npm:27.5.1" - checksum: a00db5554c9da7da225db2d2638d85f8e41124eccbd56cbaefb3b276dcbb1c1c2ad851c32defe2055a54a4806f030656cbf6638105fd6ce97bb87b90b32a33ca - languageName: node - linkType: hard - -"diff-sequences@npm:^29.6.3": - version: 29.6.3 - resolution: "diff-sequences@npm:29.6.3" - checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa - languageName: node - linkType: hard - -"dir-glob@npm:^3.0.1": - version: 3.0.1 - resolution: "dir-glob@npm:3.0.1" - dependencies: - path-type: ^4.0.0 - checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 - languageName: node - linkType: hard - -"dlv@npm:^1.1.3": - version: 1.1.3 - resolution: "dlv@npm:1.1.3" - checksum: d7381bca22ed11933a1ccf376db7a94bee2c57aa61e490f680124fa2d1cd27e94eba641d9f45be57caab4f9a6579de0983466f620a2cd6230d7ec93312105ae7 - languageName: node - linkType: hard - -"dns-equal@npm:^1.0.0": - version: 1.0.0 - resolution: "dns-equal@npm:1.0.0" - checksum: a8471ac849c7c13824f053babea1bc26e2f359394dd5a460f8340d8abd13434be01e3327a5c59d212f8c8997817450efd3f3ac77bec709b21979cf0235644524 - languageName: node - linkType: hard - -"dns-packet@npm:^5.2.2": - version: 5.6.1 - resolution: "dns-packet@npm:5.6.1" - dependencies: - "@leichtgewicht/ip-codec": ^2.0.1 - checksum: 64c06457f0c6e143f7a0946e0aeb8de1c5f752217cfa143ef527467c00a6d78db1835cfdb6bb68333d9f9a4963cf23f410439b5262a8935cce1236f45e344b81 - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: ^2.0.2 - checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 - languageName: node - linkType: hard - -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: ^2.0.2 - checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce - languageName: node - linkType: hard - -"dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9": - version: 0.5.16 - resolution: "dom-accessibility-api@npm:0.5.16" - checksum: 005eb283caef57fc1adec4d5df4dd49189b628f2f575af45decb210e04d634459e3f1ee64f18b41e2dcf200c844bc1d9279d80807e686a30d69a4756151ad248 - languageName: node - linkType: hard - -"dom-converter@npm:^0.2.0": - version: 0.2.0 - resolution: "dom-converter@npm:0.2.0" - dependencies: - utila: ~0.4 - checksum: ea52fe303f5392e48dea563abef0e6fb3a478b8dbe3c599e99bb5d53981c6c38fc4944e56bb92a8ead6bb989d10b7914722ae11febbd2fd0910e33b9fc4aaa77 - languageName: node - linkType: hard - -"dom-serializer@npm:0": - version: 0.2.2 - resolution: "dom-serializer@npm:0.2.2" - dependencies: - domelementtype: ^2.0.1 - entities: ^2.0.0 - checksum: 376344893e4feccab649a14ca1a46473e9961f40fe62479ea692d4fee4d9df1c00ca8654811a79c1ca7b020096987e1ca4fb4d7f8bae32c1db800a680a0e5d5e - languageName: node - linkType: hard - -"dom-serializer@npm:^1.0.1": - version: 1.4.1 - resolution: "dom-serializer@npm:1.4.1" - dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.2.0 - entities: ^2.0.0 - checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 - languageName: node - linkType: hard - -"domelementtype@npm:1": - version: 1.3.1 - resolution: "domelementtype@npm:1.3.1" - checksum: 7893da40218ae2106ec6ffc146b17f203487a52f5228b032ea7aa470e41dfe03e1bd762d0ee0139e792195efda765434b04b43cddcf63207b098f6ae44b36ad6 - languageName: node - linkType: hard - -"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": - version: 2.3.0 - resolution: "domelementtype@npm:2.3.0" - checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 - languageName: node - linkType: hard - -"domexception@npm:^2.0.1": - version: 2.0.1 - resolution: "domexception@npm:2.0.1" - dependencies: - webidl-conversions: ^5.0.0 - checksum: d638e9cb05c52999f1b2eb87c374b03311ea5b1d69c2f875bc92da73e17db60c12142b45c950228642ff7f845c536b65305483350d080df59003a653da80b691 - languageName: node - linkType: hard - -"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": - version: 4.3.1 - resolution: "domhandler@npm:4.3.1" - dependencies: - domelementtype: ^2.2.0 - checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa - languageName: node - linkType: hard - -"domutils@npm:^1.7.0": - version: 1.7.0 - resolution: "domutils@npm:1.7.0" - dependencies: - dom-serializer: 0 - domelementtype: 1 - checksum: f60a725b1f73c1ae82f4894b691601ecc6ecb68320d87923ac3633137627c7865725af813ae5d188ad3954283853bcf46779eb50304ec5d5354044569fcefd2b - languageName: node - linkType: hard - -"domutils@npm:^2.5.2, domutils@npm:^2.8.0": - version: 2.8.0 - resolution: "domutils@npm:2.8.0" - dependencies: - dom-serializer: ^1.0.1 - domelementtype: ^2.2.0 - domhandler: ^4.2.0 - checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 - languageName: node - linkType: hard - -"dot-case@npm:^3.0.4": - version: 3.0.4 - resolution: "dot-case@npm:3.0.4" - dependencies: - no-case: ^3.0.4 - tslib: ^2.0.3 - checksum: a65e3519414856df0228b9f645332f974f2bf5433370f544a681122eab59e66038fc3349b4be1cdc47152779dac71a5864f1ccda2f745e767c46e9c6543b1169 - languageName: node - linkType: hard - -"dotenv-expand@npm:^5.1.0": - version: 5.1.0 - resolution: "dotenv-expand@npm:5.1.0" - checksum: 8017675b7f254384915d55f9eb6388e577cf0a1231a28d54b0ca03b782be9501b0ac90ac57338636d395fa59051e6209e9b44b8ddf169ce6076dffb5dea227d3 - languageName: node - linkType: hard - -"dotenv@npm:^10.0.0": - version: 10.0.0 - resolution: "dotenv@npm:10.0.0" - checksum: f412c5fe8c24fbe313d302d2500e247ba8a1946492db405a4de4d30dd0eb186a88a43f13c958c5a7de303938949c4231c56994f97d05c4bc1f22478d631b4005 - languageName: node - linkType: hard - -"duplexer@npm:^0.1.2": - version: 0.1.2 - resolution: "duplexer@npm:0.1.2" - checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f - languageName: node - linkType: hard - -"ejs@npm:^3.1.6": - version: 3.1.9 - resolution: "ejs@npm:3.1.9" - dependencies: - jake: ^10.8.5 - bin: - ejs: bin/cli.js - checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.526": - version: 1.4.528 - resolution: "electron-to-chromium@npm:1.4.528" - checksum: e9b249929e012ce6c25f8d1e1965e7fb19a426cc72fdf72026a0ce010846ec1b0efe2730b1a1f3d1c98bd11200b94b73431bc5279211a9f4a28f2389e690c39c - languageName: node - linkType: hard - -"emittery@npm:^0.10.2": - version: 0.10.2 - resolution: "emittery@npm:0.10.2" - checksum: ee3e21788b043b90885b18ea756ec3105c1cedc50b29709c92b01e239c7e55345d4bb6d3aef4ddbaf528eef448a40b3bb831bad9ee0fc9c25cbf1367ab1ab5ac - languageName: node - linkType: hard - -"emittery@npm:^0.8.1": - version: 0.8.1 - resolution: "emittery@npm:0.8.1" - checksum: 2457e8c7b0688bb006126f2c025b2655abe682f66b184954122a8a065b5277f9813d49d627896a10b076b81c513ec5f491fd9c14fbd42c04b95ca3c9f3c365ee - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 - languageName: node - linkType: hard - -"emojis-list@npm:^3.0.0": - version: 3.0.0 - resolution: "emojis-list@npm:3.0.0" - checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 - languageName: node - linkType: hard - -"encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: ^0.6.2 - checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"enhanced-resolve@npm:^5.15.0": - version: 5.15.0 - resolution: "enhanced-resolve@npm:5.15.0" - dependencies: - graceful-fs: ^4.2.4 - tapable: ^2.2.0 - checksum: fbd8cdc9263be71cc737aa8a7d6c57b43d6aa38f6cc75dde6fcd3598a130cc465f979d2f4d01bb3bf475acb43817749c79f8eef9be048683602ca91ab52e4f11 - languageName: node - linkType: hard - -"entities@npm:^2.0.0": - version: 2.2.0 - resolution: "entities@npm:2.2.0" - checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 - languageName: node - linkType: hard - -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: ^0.2.1 - checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 - languageName: node - linkType: hard - -"error-stack-parser@npm:^2.0.6": - version: 2.1.4 - resolution: "error-stack-parser@npm:2.1.4" - dependencies: - stackframe: ^1.3.4 - checksum: 3b916d2d14c6682f287c8bfa28e14672f47eafe832701080e420e7cdbaebb2c50293868256a95706ac2330fe078cf5664713158b49bc30d7a5f2ac229ded0e18 - languageName: node - linkType: hard - -"es-abstract@npm:^1.17.2, es-abstract@npm:^1.22.1": - version: 1.22.2 - resolution: "es-abstract@npm:1.22.2" - dependencies: - array-buffer-byte-length: ^1.0.0 - arraybuffer.prototype.slice: ^1.0.2 - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - es-set-tostringtag: ^2.0.1 - es-to-primitive: ^1.2.1 - function.prototype.name: ^1.1.6 - get-intrinsic: ^1.2.1 - get-symbol-description: ^1.0.0 - globalthis: ^1.0.3 - gopd: ^1.0.1 - has: ^1.0.3 - has-property-descriptors: ^1.0.0 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - internal-slot: ^1.0.5 - is-array-buffer: ^3.0.2 - is-callable: ^1.2.7 - is-negative-zero: ^2.0.2 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - is-string: ^1.0.7 - is-typed-array: ^1.1.12 - is-weakref: ^1.0.2 - object-inspect: ^1.12.3 - object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.1 - safe-array-concat: ^1.0.1 - safe-regex-test: ^1.0.0 - string.prototype.trim: ^1.2.8 - string.prototype.trimend: ^1.0.7 - string.prototype.trimstart: ^1.0.7 - typed-array-buffer: ^1.0.0 - typed-array-byte-length: ^1.0.0 - typed-array-byte-offset: ^1.0.0 - typed-array-length: ^1.0.4 - unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.11 - checksum: cc70e592d360d7d729859013dee7a610c6b27ed8630df0547c16b0d16d9fe6505a70ee14d1af08d970fdd132b3f88c9ca7815ce72c9011608abf8ab0e55fc515 - languageName: node - linkType: hard - -"es-array-method-boxes-properly@npm:^1.0.0": - version: 1.0.0 - resolution: "es-array-method-boxes-properly@npm:1.0.0" - checksum: 2537fcd1cecf187083890bc6f5236d3a26bf39237433587e5bf63392e88faae929dbba78ff0120681a3f6f81c23fe3816122982c160d63b38c95c830b633b826 - languageName: node - linkType: hard - -"es-get-iterator@npm:^1.1.3": - version: 1.1.3 - resolution: "es-get-iterator@npm:1.1.3" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - has-symbols: ^1.0.3 - is-arguments: ^1.1.1 - is-map: ^2.0.2 - is-set: ^2.0.2 - is-string: ^1.0.7 - isarray: ^2.0.5 - stop-iteration-iterator: ^1.0.0 - checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d - languageName: node - linkType: hard - -"es-iterator-helpers@npm:^1.0.12": - version: 1.0.15 - resolution: "es-iterator-helpers@npm:1.0.15" - dependencies: - asynciterator.prototype: ^1.0.0 - call-bind: ^1.0.2 - define-properties: ^1.2.1 - es-abstract: ^1.22.1 - es-set-tostringtag: ^2.0.1 - function-bind: ^1.1.1 - get-intrinsic: ^1.2.1 - globalthis: ^1.0.3 - has-property-descriptors: ^1.0.0 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - internal-slot: ^1.0.5 - iterator.prototype: ^1.1.2 - safe-array-concat: ^1.0.1 - checksum: 50081ae5c549efe62e5c1d244df0194b40b075f7897fc2116b7e1aa437eb3c41f946d2afda18c33f9b31266ec544765932542765af839f76fa6d7b7855d1e0e1 - languageName: node - linkType: hard - -"es-module-lexer@npm:^1.2.1": - version: 1.3.1 - resolution: "es-module-lexer@npm:1.3.1" - checksum: 3beafa7e171eb1e8cc45695edf8d51638488dddf65294d7911f8d6a96249da6a9838c87529262cc6ea53988d8272cec0f4bff93f476ed031a54ba3afb51a0ed3 - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.0.1": - version: 2.0.1 - resolution: "es-set-tostringtag@npm:2.0.1" - dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 - has-tostringtag: ^1.0.0 - checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.0": - version: 1.0.0 - resolution: "es-shim-unscopables@npm:1.0.0" - dependencies: - has: ^1.0.3 - checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.2.1": - version: 1.2.1 - resolution: "es-to-primitive@npm:1.2.1" - dependencies: - is-callable: ^1.1.4 - is-date-object: ^1.0.1 - is-symbol: ^1.0.2 - checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed - languageName: node - linkType: hard - -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 - languageName: node - linkType: hard - -"escape-html@npm:~1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 - languageName: node - linkType: hard - -"escodegen@npm:^1.8.1": - version: 1.14.3 - resolution: "escodegen@npm:1.14.3" - dependencies: - esprima: ^4.0.1 - estraverse: ^4.2.0 - esutils: ^2.0.2 - optionator: ^0.8.1 - source-map: ~0.6.1 - dependenciesMeta: - source-map: - optional: true - bin: - escodegen: bin/escodegen.js - esgenerate: bin/esgenerate.js - checksum: 381cdc4767ecdb221206bbbab021b467bbc2a6f5c9a99c9e6353040080bdd3dfe73d7604ad89a47aca6ea7d58bc635f6bd3fbc8da9a1998e9ddfa8372362ccd0 - languageName: node - linkType: hard - -"escodegen@npm:^2.0.0": - version: 2.1.0 - resolution: "escodegen@npm:2.1.0" - dependencies: - esprima: ^4.0.1 - estraverse: ^5.2.0 - esutils: ^2.0.2 - source-map: ~0.6.1 - dependenciesMeta: - source-map: - optional: true - bin: - escodegen: bin/escodegen.js - esgenerate: bin/esgenerate.js - checksum: 096696407e161305cd05aebb95134ad176708bc5cb13d0dcc89a5fcbb959b8ed757e7f2591a5f8036f8f4952d4a724de0df14cd419e29212729fa6df5ce16bf6 - languageName: node - linkType: hard - -"eslint-config-react-app@npm:^7.0.1": - version: 7.0.1 - resolution: "eslint-config-react-app@npm:7.0.1" - dependencies: - "@babel/core": ^7.16.0 - "@babel/eslint-parser": ^7.16.3 - "@rushstack/eslint-patch": ^1.1.0 - "@typescript-eslint/eslint-plugin": ^5.5.0 - "@typescript-eslint/parser": ^5.5.0 - babel-preset-react-app: ^10.0.1 - confusing-browser-globals: ^1.0.11 - eslint-plugin-flowtype: ^8.0.3 - eslint-plugin-import: ^2.25.3 - eslint-plugin-jest: ^25.3.0 - eslint-plugin-jsx-a11y: ^6.5.1 - eslint-plugin-react: ^7.27.1 - eslint-plugin-react-hooks: ^4.3.0 - eslint-plugin-testing-library: ^5.0.1 - peerDependencies: - eslint: ^8.0.0 - checksum: a67e0821809e62308d6e419753fa2acfc7cd353659fab08cf34735f59c6c66910c0b6fda0471c4ec0d712ce762d65efc6431b39569f8d575e2d9bdfc384e0824 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.7": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: ^3.2.7 - is-core-module: ^2.13.0 - resolve: ^1.22.4 - checksum: 439b91271236b452d478d0522a44482e8c8540bf9df9bd744062ebb89ab45727a3acd03366a6ba2bdbcde8f9f718bab7fe8db64688aca75acf37e04eafd25e22 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.8.0": - version: 2.8.0 - resolution: "eslint-module-utils@npm:2.8.0" - dependencies: - debug: ^3.2.7 - peerDependenciesMeta: - eslint: - optional: true - checksum: 74c6dfea7641ebcfe174be61168541a11a14aa8d72e515f5f09af55cd0d0862686104b0524aa4b8e0ce66418a44aa38a94d2588743db5fd07a6b49ffd16921d2 - languageName: node - linkType: hard - -"eslint-plugin-flowtype@npm:^8.0.3": - version: 8.0.3 - resolution: "eslint-plugin-flowtype@npm:8.0.3" - dependencies: - lodash: ^4.17.21 - string-natural-compare: ^3.0.1 - peerDependencies: - "@babel/plugin-syntax-flow": ^7.14.5 - "@babel/plugin-transform-react-jsx": ^7.14.9 - eslint: ^8.1.0 - checksum: 30e63c5357b0b5571f39afed51e59c140084f4aa53c106b1fd04f26da42b268908466daa6020b92943e71409bdaee1c67202515ed9012404d027cc92cb03cefa - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.25.3": - version: 2.28.1 - resolution: "eslint-plugin-import@npm:2.28.1" - dependencies: - array-includes: ^3.1.6 - array.prototype.findlastindex: ^1.2.2 - array.prototype.flat: ^1.3.1 - array.prototype.flatmap: ^1.3.1 - debug: ^3.2.7 - doctrine: ^2.1.0 - eslint-import-resolver-node: ^0.3.7 - eslint-module-utils: ^2.8.0 - has: ^1.0.3 - is-core-module: ^2.13.0 - is-glob: ^4.0.3 - minimatch: ^3.1.2 - object.fromentries: ^2.0.6 - object.groupby: ^1.0.0 - object.values: ^1.1.6 - semver: ^6.3.1 - tsconfig-paths: ^3.14.2 - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: e8ae6dd8f06d8adf685f9c1cfd46ac9e053e344a05c4090767e83b63a85c8421ada389807a39e73c643b9bff156715c122e89778169110ed68d6428e12607edf - languageName: node - linkType: hard - -"eslint-plugin-jest@npm:^25.3.0": - version: 25.7.0 - resolution: "eslint-plugin-jest@npm:25.7.0" - dependencies: - "@typescript-eslint/experimental-utils": ^5.0.0 - peerDependencies: - "@typescript-eslint/eslint-plugin": ^4.0.0 || ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - "@typescript-eslint/eslint-plugin": - optional: true - jest: - optional: true - checksum: fc6da96131f4cbf33d15ef911ec8e600ccd71deb97d73c0ca340427cef7b01ff41a797e2e7d1e351abf97321a46ed0c0acff5ee8eeedac94961dd6dad1f718a9 - languageName: node - linkType: hard - -"eslint-plugin-jsx-a11y@npm:^6.5.1": - version: 6.7.1 - resolution: "eslint-plugin-jsx-a11y@npm:6.7.1" - dependencies: - "@babel/runtime": ^7.20.7 - aria-query: ^5.1.3 - array-includes: ^3.1.6 - array.prototype.flatmap: ^1.3.1 - ast-types-flow: ^0.0.7 - axe-core: ^4.6.2 - axobject-query: ^3.1.1 - damerau-levenshtein: ^1.0.8 - emoji-regex: ^9.2.2 - has: ^1.0.3 - jsx-ast-utils: ^3.3.3 - language-tags: =1.0.5 - minimatch: ^3.1.2 - object.entries: ^1.1.6 - object.fromentries: ^2.0.6 - semver: ^6.3.0 - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: f166dd5fe7257c7b891c6692e6a3ede6f237a14043ae3d97581daf318fc5833ddc6b4871aa34ab7656187430170500f6d806895747ea17ecdf8231a666c3c2fd - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^4.3.0": - version: 4.6.0 - resolution: "eslint-plugin-react-hooks@npm:4.6.0" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 23001801f14c1d16bf0a837ca7970d9dd94e7b560384b41db378b49b6e32dc43d6e2790de1bd737a652a86f81a08d6a91f402525061b47719328f586a57e86c3 - languageName: node - linkType: hard - -"eslint-plugin-react@npm:^7.27.1": - version: 7.33.2 - resolution: "eslint-plugin-react@npm:7.33.2" - dependencies: - array-includes: ^3.1.6 - array.prototype.flatmap: ^1.3.1 - array.prototype.tosorted: ^1.1.1 - doctrine: ^2.1.0 - es-iterator-helpers: ^1.0.12 - estraverse: ^5.3.0 - jsx-ast-utils: ^2.4.1 || ^3.0.0 - minimatch: ^3.1.2 - object.entries: ^1.1.6 - object.fromentries: ^2.0.6 - object.hasown: ^1.1.2 - object.values: ^1.1.6 - prop-types: ^15.8.1 - resolve: ^2.0.0-next.4 - semver: ^6.3.1 - string.prototype.matchall: ^4.0.8 - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: b4c3d76390b0ae6b6f9fed78170604cc2c04b48e6778a637db339e8e3911ec9ef22510b0ae77c429698151d0f1b245f282177f384105b6830e7b29b9c9b26610 - languageName: node - linkType: hard - -"eslint-plugin-testing-library@npm:^5.0.1": - version: 5.11.1 - resolution: "eslint-plugin-testing-library@npm:5.11.1" - dependencies: - "@typescript-eslint/utils": ^5.58.0 - peerDependencies: - eslint: ^7.5.0 || ^8.0.0 - checksum: 9f3fc68ef9f13016a4381b33ab5dbffcc189e5de3eaeba184bcf7d2771faa7f54e59c04b652162fb1c0f83fb52428dd909db5450a25508b94be59eba69fcc990 - languageName: node - linkType: hard - -"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^4.1.1 - checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb - languageName: node - linkType: hard - -"eslint-scope@npm:^7.2.2": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.1.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 - languageName: node - linkType: hard - -"eslint-webpack-plugin@npm:^3.1.1": - version: 3.2.0 - resolution: "eslint-webpack-plugin@npm:3.2.0" - dependencies: - "@types/eslint": ^7.29.0 || ^8.4.1 - jest-worker: ^28.0.2 - micromatch: ^4.0.5 - normalize-path: ^3.0.0 - schema-utils: ^4.0.0 - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - webpack: ^5.0.0 - checksum: 095034c35e773fdb21ec7e597ae1f8a6899679c290db29d8568ca94619e8c7f4971f0f9edccc8a965322ab8af9286c87205985a38f4fdcf17654aee7cd8bb7b5 - languageName: node - linkType: hard - -"eslint@npm:^8.3.0": - version: 8.50.0 - resolution: "eslint@npm:8.50.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@eslint-community/regexpp": ^4.6.1 - "@eslint/eslintrc": ^2.1.2 - "@eslint/js": 8.50.0 - "@humanwhocodes/config-array": ^0.11.11 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.12.4 - chalk: ^4.0.0 - cross-spawn: ^7.0.2 - debug: ^4.3.2 - doctrine: ^3.0.0 - escape-string-regexp: ^4.0.0 - eslint-scope: ^7.2.2 - eslint-visitor-keys: ^3.4.3 - espree: ^9.6.1 - esquery: ^1.4.2 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - graphemer: ^1.4.0 - ignore: ^5.2.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.3 - strip-ansi: ^6.0.1 - text-table: ^0.2.0 - bin: - eslint: bin/eslint.js - checksum: 9ebfe5615dc84700000d218e32ddfdcfc227ca600f65f18e5541ec34f8902a00356a9a8804d9468fd6c8637a5ef6a3897291dad91ba6579d5b32ffeae5e31768 - languageName: node - linkType: hard - -"espree@npm:^9.6.0, espree@npm:^9.6.1": - version: 9.6.1 - resolution: "espree@npm:9.6.1" - dependencies: - acorn: ^8.9.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.1 - checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 - languageName: node - linkType: hard - -"esprima@npm:1.2.2": - version: 1.2.2 - resolution: "esprima@npm:1.2.2" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: 4f10006f0e315f2f7d8cf6630e465f183512f1ab2e862b11785a133ce37ed1696573deefb5256e510eaa4368342b13b393334477f6ccdcdb8f10e782b0f5e6dc - languageName: node - linkType: hard - -"esprima@npm:^4.0.0, esprima@npm:^4.0.1": - version: 4.0.1 - resolution: "esprima@npm:4.0.1" - bin: - esparse: ./bin/esparse.js - esvalidate: ./bin/esvalidate.js - checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 - languageName: node - linkType: hard - -"esquery@npm:^1.4.2": - version: 1.5.0 - resolution: "esquery@npm:1.5.0" - dependencies: - estraverse: ^5.1.0 - checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: ^5.2.0 - checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 - languageName: node - linkType: hard - -"estraverse@npm:^4.1.1, estraverse@npm:^4.2.0": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b - languageName: node - linkType: hard - -"estree-walker@npm:^1.0.1": - version: 1.0.1 - resolution: "estree-walker@npm:1.0.1" - checksum: 7e70da539691f6db03a08e7ce94f394ce2eef4180e136d251af299d41f92fb2d28ebcd9a6e393e3728d7970aeb5358705ddf7209d52fbcb2dd4693f95dcf925f - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 - languageName: node - linkType: hard - -"etag@npm:~1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff - languageName: node - linkType: hard - -"eventemitter3@npm:^4.0.0": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 - languageName: node - linkType: hard - -"events@npm:^3.2.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780 - languageName: node - linkType: hard - -"execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: ^7.0.3 - get-stream: ^6.0.0 - human-signals: ^2.1.0 - is-stream: ^2.0.0 - merge-stream: ^2.0.0 - npm-run-path: ^4.0.1 - onetime: ^5.1.2 - signal-exit: ^3.0.3 - strip-final-newline: ^2.0.0 - checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 - languageName: node - linkType: hard - -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: abc407f07a875c3961e4781dfcb743b58d6c93de9ab263f4f8c9d23bb6da5f9b7764fc773f86b43dd88030444d5ab8abcb611cb680fba8ca075362b77114bba3 - languageName: node - linkType: hard - -"expect@npm:^27.5.1": - version: 27.5.1 - resolution: "expect@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - jest-get-type: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - checksum: b2c66beb52de53ef1872165aace40224e722bca3c2274c54cfa74b6d617d55cf0ccdbf36783ccd64dbea501b280098ed33fd0b207d4f15bc03cd3c7a24364a6a - languageName: node - linkType: hard - -"expect@npm:^29.0.0": - version: 29.7.0 - resolution: "expect@npm:29.7.0" - dependencies: - "@jest/expect-utils": ^29.7.0 - jest-get-type: ^29.6.3 - jest-matcher-utils: ^29.7.0 - jest-message-util: ^29.7.0 - jest-util: ^29.7.0 - checksum: 9257f10288e149b81254a0fda8ffe8d54a7061cd61d7515779998b012579d2b8c22354b0eb901daf0145f347403da582f75f359f4810c007182ad3fb318b5c0c - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 - languageName: node - linkType: hard - -"express@npm:^4.17.3": - version: 4.18.2 - resolution: "express@npm:4.18.2" - dependencies: - accepts: ~1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.1 - content-disposition: 0.5.4 - content-type: ~1.0.4 - cookie: 0.5.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - etag: ~1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: ~1.1.2 - on-finished: 2.4.1 - parseurl: ~1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: ~2.0.7 - qs: 6.11.0 - range-parser: ~1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: ~1.6.18 - utils-merge: 1.0.1 - vary: ~1.1.2 - checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d - languageName: node - linkType: hard - -"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9": - version: 3.3.1 - resolution: "fast-glob@npm:3.3.1" - dependencies: - "@nodelib/fs.stat": ^2.0.2 - "@nodelib/fs.walk": ^1.2.3 - glob-parent: ^5.1.2 - merge2: ^1.3.0 - micromatch: ^4.0.4 - checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5 - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" - dependencies: - reusify: ^1.0.4 - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a - languageName: node - linkType: hard - -"faye-websocket@npm:^0.11.3": - version: 0.11.4 - resolution: "faye-websocket@npm:0.11.4" - dependencies: - websocket-driver: ">=0.5.1" - checksum: d49a62caf027f871149fc2b3f3c7104dc6d62744277eb6f9f36e2d5714e847d846b9f7f0d0b7169b25a012e24a594cde11a93034b30732e4c683f20b8a5019fa - languageName: node - linkType: hard - -"fb-watchman@npm:^2.0.0": - version: 2.0.2 - resolution: "fb-watchman@npm:2.0.2" - dependencies: - bser: 2.1.1 - checksum: b15a124cef28916fe07b400eb87cbc73ca082c142abf7ca8e8de6af43eca79ca7bd13eb4d4d48240b3bd3136eaac40d16e42d6edf87a8e5d1dd8070626860c78 - languageName: node - linkType: hard - -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" - dependencies: - flat-cache: ^3.0.4 - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 - languageName: node - linkType: hard - -"file-loader@npm:^6.2.0": - version: 6.2.0 - resolution: "file-loader@npm:6.2.0" - dependencies: - loader-utils: ^2.0.0 - schema-utils: ^3.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: faf43eecf233f4897b0150aaa874eeeac214e4f9de49738a9e0ef734a30b5260059e85b7edadf852b98e415f875bd5f12587768a93fd52aaf2e479ecf95fab20 - languageName: node - linkType: hard - -"filelist@npm:^1.0.4": - version: 1.0.4 - resolution: "filelist@npm:1.0.4" - dependencies: - minimatch: ^5.0.1 - checksum: a303573b0821e17f2d5e9783688ab6fbfce5d52aaac842790ae85e704a6f5e4e3538660a63183d6453834dedf1e0f19a9dadcebfa3e926c72397694ea11f5160 - languageName: node - linkType: hard - -"filesize@npm:^8.0.6": - version: 8.0.7 - resolution: "filesize@npm:8.0.7" - checksum: 8603d27c5287b984cb100733640645e078f5f5ad65c6d913173e01fb99e09b0747828498fd86647685ccecb69be31f3587b9739ab1e50732116b2374aff4cbf9 - languageName: node - linkType: hard - -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" - dependencies: - to-regex-range: ^5.0.1 - checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 - languageName: node - linkType: hard - -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" - dependencies: - debug: 2.6.9 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - on-finished: 2.4.1 - parseurl: ~1.3.3 - statuses: 2.0.1 - unpipe: ~1.0.0 - checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 - languageName: node - linkType: hard - -"find-cache-dir@npm:^3.3.1": - version: 3.3.2 - resolution: "find-cache-dir@npm:3.3.2" - dependencies: - commondir: ^1.0.1 - make-dir: ^3.0.2 - pkg-dir: ^4.1.0 - checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 - languageName: node - linkType: hard - -"find-up@npm:^3.0.0": - version: 3.0.0 - resolution: "find-up@npm:3.0.0" - dependencies: - locate-path: ^3.0.0 - checksum: 38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 - languageName: node - linkType: hard - -"find-up@npm:^4.0.0, find-up@npm:^4.1.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" - dependencies: - locate-path: ^5.0.0 - path-exists: ^4.0.0 - checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: ^6.0.0 - path-exists: ^4.0.0 - checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 - languageName: node - linkType: hard - -"flat-cache@npm:^3.0.4": - version: 3.1.0 - resolution: "flat-cache@npm:3.1.0" - dependencies: - flatted: ^3.2.7 - keyv: ^4.5.3 - rimraf: ^3.0.2 - checksum: 99312601d5b90f44aef403f17f056dc09be7e437703740b166cdc9386d99e681f74e6b6e8bd7d010bda66904ea643c9527276b1b80308a2119741d94108a4d8f - languageName: node - linkType: hard - -"flatted@npm:^3.2.7": - version: 3.2.9 - resolution: "flatted@npm:3.2.9" - checksum: f14167fbe26a9d20f6fca8d998e8f1f41df72c8e81f9f2c9d61ed2bea058248f5e1cbd05e7f88c0e5087a6a0b822a1e5e2b446e879f3cfbe0b07ba2d7f80b026 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.0": - version: 1.15.3 - resolution: "follow-redirects@npm:1.15.3" - peerDependenciesMeta: - debug: - optional: true - checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231 - languageName: node - linkType: hard - -"for-each@npm:^0.3.3": - version: 0.3.3 - resolution: "for-each@npm:0.3.3" - dependencies: - is-callable: ^1.1.3 - checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.1.1 - resolution: "foreground-child@npm:3.1.1" - dependencies: - cross-spawn: ^7.0.0 - signal-exit: ^4.0.1 - checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 - languageName: node - linkType: hard - -"fork-ts-checker-webpack-plugin@npm:^6.5.0": - version: 6.5.3 - resolution: "fork-ts-checker-webpack-plugin@npm:6.5.3" - dependencies: - "@babel/code-frame": ^7.8.3 - "@types/json-schema": ^7.0.5 - chalk: ^4.1.0 - chokidar: ^3.4.2 - cosmiconfig: ^6.0.0 - deepmerge: ^4.2.2 - fs-extra: ^9.0.0 - glob: ^7.1.6 - memfs: ^3.1.2 - minimatch: ^3.0.4 - schema-utils: 2.7.0 - semver: ^7.3.2 - tapable: ^1.0.0 - peerDependencies: - eslint: ">= 6" - typescript: ">= 2.7" - vue-template-compiler: "*" - webpack: ">= 4" - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true - checksum: 9732a49bfeed8fc23e6e8a59795fa7c238edeba91040a9b520db54b4d316dda27f9f1893d360e296fd0ad8930627d364417d28a8c7007fba60cc730ebfce4956 - languageName: node - linkType: hard - -"form-data@npm:^3.0.0": - version: 3.0.1 - resolution: "form-data@npm:3.0.1" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d - languageName: node - linkType: hard - -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c - languageName: node - linkType: hard - -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 - languageName: node - linkType: hard - -"fraction.js@npm:^4.3.6": - version: 4.3.6 - resolution: "fraction.js@npm:4.3.6" - checksum: e96ae77e64ebfd442d3a5a01a3f0637b0663fc2440bcf2841b3ad9341ba24c81fb2e3e7142e43ef7d088558c6b3f8609df135b201adc7a1c674aea6a71384162 - languageName: node - linkType: hard - -"fresh@npm:0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" - checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 - languageName: node - linkType: hard - -"fs-extra@npm:^10.0.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: dc94ab37096f813cc3ca12f0f1b5ad6744dfed9ed21e953d72530d103cea193c2f81584a39e9dee1bea36de5ee66805678c0dddc048e8af1427ac19c00fffc50 - languageName: node - linkType: hard - -"fs-extra@npm:^9.0.0, fs-extra@npm:^9.0.1": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: ^3.0.0 - checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: ^7.0.3 - checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 - languageName: node - linkType: hard - -"fs-monkey@npm:^1.0.4": - version: 1.0.4 - resolution: "fs-monkey@npm:1.0.4" - checksum: 8b254c982905c0b7e028eab22b410dc35a5c0019c1c860456f5f54ae6a61666e1cb8c6b700d6c88cc873694c00953c935847b9959cc4dcf274aacb8673c1e8bf - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 - languageName: node - linkType: hard - -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: latest - checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=18f3a7" - dependencies: - node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a - languageName: node - linkType: hard - -"function.prototype.name@npm:^1.1.5, function.prototype.name@npm:^1.1.6": - version: 1.1.6 - resolution: "function.prototype.name@npm:1.1.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - functions-have-names: ^1.2.3 - checksum: 7a3f9bd98adab09a07f6e1f03da03d3f7c26abbdeaeee15223f6c04a9fb5674792bdf5e689dac19b97ac71de6aad2027ba3048a9b883aa1b3173eed6ab07f479 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 - languageName: node - linkType: hard - -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.2": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec - languageName: node - linkType: hard - -"get-caller-file@npm:^2.0.5": - version: 2.0.5 - resolution: "get-caller-file@npm:2.0.5" - checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1": - version: 1.2.1 - resolution: "get-intrinsic@npm:1.2.1" - dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f - languageName: node - linkType: hard - -"get-own-enumerable-property-symbols@npm:^3.0.0": - version: 3.0.2 - resolution: "get-own-enumerable-property-symbols@npm:3.0.2" - checksum: 8f0331f14159f939830884799f937343c8c0a2c330506094bc12cbee3665d88337fe97a4ea35c002cc2bdba0f5d9975ad7ec3abb925015cdf2a93e76d4759ede - languageName: node - linkType: hard - -"get-package-type@npm:^0.1.0": - version: 0.1.0 - resolution: "get-package-type@npm:0.1.0" - checksum: bba0811116d11e56d702682ddef7c73ba3481f114590e705fc549f4d868972263896af313c57a25c076e3c0d567e11d919a64ba1b30c879be985fc9d44f96148 - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad - languageName: node - linkType: hard - -"get-symbol-description@npm:^1.0.0": - version: 1.0.0 - resolution: "get-symbol-description@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: ^4.0.1 - checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: ^4.0.3 - checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 - languageName: node - linkType: hard - -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 - languageName: node - linkType: hard - -"glob@npm:7.1.6": - version: 7.1.6 - resolution: "glob@npm:7.1.6" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.0.4 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 351d549dd90553b87c2d3f90ce11aed9e1093c74130440e7ae0592e11bbcd2ce7f0ebb8ba6bfe63aaf9b62166a7f4c80cb84490ae5d78408bb2572bf7d4ee0a6 - languageName: node - linkType: hard - -"glob@npm:^10.2.2": - version: 10.3.7 - resolution: "glob@npm:10.3.7" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.0.3 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 - bin: - glob: dist/esm/bin.mjs - checksum: 9a27f1fa8774c3a8ab8f05c26a77276edaf5418aac29aff70c5d847ef75dabf536554cb113e945193323fb769fbe32edde12559d2d52266f38662595cbc7a031 - languageName: node - linkType: hard - -"glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - -"global-modules@npm:^2.0.0": - version: 2.0.0 - resolution: "global-modules@npm:2.0.0" - dependencies: - global-prefix: ^3.0.0 - checksum: d6197f25856c878c2fb5f038899f2dca7cbb2f7b7cf8999660c0104972d5cfa5c68b5a0a77fa8206bb536c3903a4615665acb9709b4d80846e1bb47eaef65430 - languageName: node - linkType: hard - -"global-prefix@npm:^3.0.0": - version: 3.0.0 - resolution: "global-prefix@npm:3.0.0" - dependencies: - ini: ^1.3.5 - kind-of: ^6.0.2 - which: ^1.3.1 - checksum: 8a82fc1d6f22c45484a4e34656cc91bf021a03e03213b0035098d605bfc612d7141f1e14a21097e8a0413b4884afd5b260df0b6a25605ce9d722e11f1df2881d - languageName: node - linkType: hard - -"globals@npm:^11.1.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e - languageName: node - linkType: hard - -"globals@npm:^13.19.0": - version: 13.22.0 - resolution: "globals@npm:13.22.0" - dependencies: - type-fest: ^0.20.2 - checksum: 64af5a09565341432770444085f7aa98b54331c3b69732e0de411003921fa2dd060222ae7b50bec0b98f29c4d00b4f49bf434049ba9f7c36ca4ee1773f60458c - languageName: node - linkType: hard - -"globalthis@npm:^1.0.3": - version: 1.0.3 - resolution: "globalthis@npm:1.0.3" - dependencies: - define-properties: ^1.1.3 - checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 - languageName: node - linkType: hard - -"globby@npm:^11.0.4, globby@npm:^11.1.0": - version: 11.1.0 - resolution: "globby@npm:11.1.0" - dependencies: - array-union: ^2.1.0 - dir-glob: ^3.0.1 - fast-glob: ^3.2.9 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^3.0.0 - checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 - languageName: node - linkType: hard - -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: ^1.1.3 - checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 - languageName: node - linkType: hard - -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673 - languageName: node - linkType: hard - -"gzip-size@npm:^6.0.0": - version: 6.0.0 - resolution: "gzip-size@npm:6.0.0" - dependencies: - duplexer: ^0.1.2 - checksum: 2df97f359696ad154fc171dcb55bc883fe6e833bca7a65e457b9358f3cb6312405ed70a8da24a77c1baac0639906cd52358dc0ce2ec1a937eaa631b934c94194 - languageName: node - linkType: hard - -"handle-thing@npm:^2.0.0": - version: 2.0.1 - resolution: "handle-thing@npm:2.0.1" - checksum: 68071f313062315cd9dce55710e9496873945f1dd425107007058fc1629f93002a7649fcc3e464281ce02c7e809a35f5925504ab8105d972cf649f1f47cb7d6c - languageName: node - linkType: hard - -"harmony-reflect@npm:^1.4.6": - version: 1.6.2 - resolution: "harmony-reflect@npm:1.6.2" - checksum: 2e5bae414cd2bfae5476147f9935dc69ee9b9a413206994dcb94c5b3208d4555da3d4313aff6fd14bd9991c1e3ef69cdda5c8fac1eb1d7afc064925839339b8c - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": - version: 1.0.2 - resolution: "has-bigints@npm:1.0.2" - checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b - languageName: node - linkType: hard - -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" - dependencies: - get-intrinsic: ^1.1.1 - checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb - languageName: node - linkType: hard - -"has-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "has-proto@npm:1.0.1" - checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.1, has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.0": - version: 1.0.0 - resolution: "has-tostringtag@npm:1.0.0" - dependencies: - has-symbols: ^1.0.2 - checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c - languageName: node - linkType: hard - -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: ^1.1.1 - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 - languageName: node - linkType: hard - -"he@npm:^1.2.0": - version: 1.2.0 - resolution: "he@npm:1.2.0" - bin: - he: bin/he - checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7 - languageName: node - linkType: hard - -"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2": - version: 3.3.2 - resolution: "hoist-non-react-statics@npm:3.3.2" - dependencies: - react-is: ^16.7.0 - checksum: b1538270429b13901ee586aa44f4cc3ecd8831c061d06cb8322e50ea17b3f5ce4d0e2e66394761e6c8e152cd8c34fb3b4b690116c6ce2bd45b18c746516cb9e8 - languageName: node - linkType: hard - -"hoopy@npm:^0.1.4": - version: 0.1.4 - resolution: "hoopy@npm:0.1.4" - checksum: cfa60c7684c5e1ee4efe26e167bc54b73f839ffb59d1d44a5c4bf891e26b4f5bcc666555219a98fec95508fea4eda3a79540c53c05cc79afc1f66f9a238f4d9e - languageName: node - linkType: hard - -"hpack.js@npm:^2.1.6": - version: 2.1.6 - resolution: "hpack.js@npm:2.1.6" - dependencies: - inherits: ^2.0.1 - obuf: ^1.0.0 - readable-stream: ^2.0.1 - wbuf: ^1.1.0 - checksum: 2de144115197967ad6eeee33faf41096c6ba87078703c5cb011632dcfbffeb45784569e0cf02c317bd79c48375597c8ec88c30fff5bb0b023e8f654fb6e9c06e - languageName: node - linkType: hard - -"html-encoding-sniffer@npm:^2.0.1": - version: 2.0.1 - resolution: "html-encoding-sniffer@npm:2.0.1" - dependencies: - whatwg-encoding: ^1.0.5 - checksum: bf30cce461015ed7e365736fcd6a3063c7bc016a91f74398ef6158886970a96333938f7c02417ab3c12aa82e3e53b40822145facccb9ddfbcdc15a879ae4d7ba - languageName: node - linkType: hard - -"html-entities@npm:^2.1.0, html-entities@npm:^2.3.2": - version: 2.4.0 - resolution: "html-entities@npm:2.4.0" - checksum: 25bea32642ce9ebd0eedc4d24381883ecb0335ccb8ac26379a0958b9b16652fdbaa725d70207ce54a51db24103436a698a8e454397d3ba8ad81460224751f1dc - languageName: node - linkType: hard - -"html-escaper@npm:^2.0.0": - version: 2.0.2 - resolution: "html-escaper@npm:2.0.2" - checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 - languageName: node - linkType: hard - -"html-minifier-terser@npm:^6.0.2": - version: 6.1.0 - resolution: "html-minifier-terser@npm:6.1.0" - dependencies: - camel-case: ^4.1.2 - clean-css: ^5.2.2 - commander: ^8.3.0 - he: ^1.2.0 - param-case: ^3.0.4 - relateurl: ^0.2.7 - terser: ^5.10.0 - bin: - html-minifier-terser: cli.js - checksum: ac52c14006476f773204c198b64838477859dc2879490040efab8979c0207424da55d59df7348153f412efa45a0840a1ca3c757bf14767d23a15e3e389d37a93 - languageName: node - linkType: hard - -"html-webpack-plugin@npm:^5.5.0": - version: 5.5.3 - resolution: "html-webpack-plugin@npm:5.5.3" - dependencies: - "@types/html-minifier-terser": ^6.0.0 - html-minifier-terser: ^6.0.2 - lodash: ^4.17.21 - pretty-error: ^4.0.0 - tapable: ^2.0.0 - peerDependencies: - webpack: ^5.20.0 - checksum: ccf685195739c372ad641bbd0c9100a847904f34eedc7aff3ece7856cd6c78fd3746d2d615af1bb71e5727993fe711b89e9b744f033ed3fde646540bf5d5e954 - languageName: node - linkType: hard - -"htmlparser2@npm:^6.1.0": - version: 6.1.0 - resolution: "htmlparser2@npm:6.1.0" - dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.0.0 - domutils: ^2.5.2 - entities: ^2.0.0 - checksum: 81a7b3d9c3bb9acb568a02fc9b1b81ffbfa55eae7f1c41ae0bf840006d1dbf54cb3aa245b2553e2c94db674840a9f0fdad7027c9a9d01a062065314039058c4e - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 - languageName: node - linkType: hard - -"http-deceiver@npm:^1.2.7": - version: 1.2.7 - resolution: "http-deceiver@npm:1.2.7" - checksum: 64d7d1ae3a6933eb0e9a94e6f27be4af45a53a96c3c34e84ff57113787105a89fff9d1c3df263ef63add823df019b0e8f52f7121e32393bb5ce9a713bf100b41 - languageName: node - linkType: hard - -"http-errors@npm:2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - checksum: 9b0a3782665c52ce9dc658a0d1560bcb0214ba5699e4ea15aefb2a496e2ca83db03ebc42e1cce4ac1f413e4e0d2d736a3fd755772c556a9a06853ba2a0b7d920 - languageName: node - linkType: hard - -"http-errors@npm:~1.6.2": - version: 1.6.3 - resolution: "http-errors@npm:1.6.3" - dependencies: - depd: ~1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 - statuses: ">= 1.4.0 < 2" - checksum: a9654ee027e3d5de305a56db1d1461f25709ac23267c6dc28cdab8323e3f96caa58a9a6a5e93ac15d7285cee0c2f019378c3ada9026e7fe19c872d695f27de7c - languageName: node - linkType: hard - -"http-parser-js@npm:>=0.5.1": - version: 0.5.8 - resolution: "http-parser-js@npm:0.5.8" - checksum: 6bbdf2429858e8cf13c62375b0bfb6dc3955ca0f32e58237488bc86cd2378f31d31785fd3ac4ce93f1c74e0189cf8823c91f5cb061696214fd368d2452dc871d - languageName: node - linkType: hard - -"http-proxy-agent@npm:^4.0.1": - version: 4.0.1 - resolution: "http-proxy-agent@npm:4.0.1" - dependencies: - "@tootallnate/once": 1 - agent-base: 6 - debug: 4 - checksum: c6a5da5a1929416b6bbdf77b1aca13888013fe7eb9d59fc292e25d18e041bb154a8dfada58e223fc7b76b9b2d155a87e92e608235201f77d34aa258707963a82 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" - dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 - languageName: node - linkType: hard - -"http-proxy-middleware@npm:^2.0.3": - version: 2.0.6 - resolution: "http-proxy-middleware@npm:2.0.6" - dependencies: - "@types/http-proxy": ^1.17.8 - http-proxy: ^1.18.1 - is-glob: ^4.0.1 - is-plain-obj: ^3.0.0 - micromatch: ^4.0.2 - peerDependencies: - "@types/express": ^4.17.13 - peerDependenciesMeta: - "@types/express": - optional: true - checksum: 2ee85bc878afa6cbf34491e972ece0f5be0a3e5c98a60850cf40d2a9a5356e1fc57aab6cff33c1fc37691b0121c3a42602d2b1956c52577e87a5b77b62ae1c3a - languageName: node - linkType: hard - -"http-proxy@npm:^1.18.1": - version: 1.18.1 - resolution: "http-proxy@npm:1.18.1" - dependencies: - eventemitter3: ^4.0.0 - follow-redirects: ^1.0.0 - requires-port: ^1.0.0 - checksum: f5bd96bf83e0b1e4226633dbb51f8b056c3e6321917df402deacec31dd7fe433914fc7a2c1831cf7ae21e69c90b3a669b8f434723e9e8b71fd68afe30737b6a5 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: 6 - debug: 4 - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 - languageName: node - linkType: hard - -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: b87fd89fce72391625271454e70f67fe405277415b48bcc0117ca73d31fa23a4241787afdc8d67f5a116cf37258c052f59ea82daffa72364d61351423848e3b8 - languageName: node - linkType: hard - -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - -"iconv-lite@npm:0.4.24": - version: 0.4.24 - resolution: "iconv-lite@npm:0.4.24" - dependencies: - safer-buffer: ">= 2.1.2 < 3" - checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: ">= 2.1.2 < 3.0.0" - checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf - languageName: node - linkType: hard - -"icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": - version: 5.1.0 - resolution: "icss-utils@npm:5.1.0" - peerDependencies: - postcss: ^8.1.0 - checksum: 5c324d283552b1269cfc13a503aaaa172a280f914e5b81544f3803bc6f06a3b585fb79f66f7c771a2c052db7982c18bf92d001e3b47282e3abbbb4c4cc488d68 - languageName: node - linkType: hard - -"idb@npm:^7.0.1": - version: 7.1.1 - resolution: "idb@npm:7.1.1" - checksum: 1973c28d53c784b177bdef9f527ec89ec239ec7cf5fcbd987dae75a16c03f5b7dfcc8c6d3285716fd0309dd57739805390bd9f98ce23b1b7d8849a3b52de8d56 - languageName: node - linkType: hard - -"identity-obj-proxy@npm:^3.0.0": - version: 3.0.0 - resolution: "identity-obj-proxy@npm:3.0.0" - dependencies: - harmony-reflect: ^1.4.6 - checksum: 97559f8ea2aeaa1a880d279d8c49550dce01148321e00a2102cda5ddf9ce622fa1d7f3efc7bed63458af78889de888fdaebaf31c816312298bb3fdd0ef8aaf2c - languageName: node - linkType: hard - -"ignore@npm:^5.2.0": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef - languageName: node - linkType: hard - -"immer@npm:^9.0.7": - version: 9.0.21 - resolution: "immer@npm:9.0.21" - checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 - languageName: node - linkType: hard - -"import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" - dependencies: - parent-module: ^1.0.0 - resolve-from: ^4.0.0 - checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa - languageName: node - linkType: hard - -"import-local@npm:^3.0.2": - version: 3.1.0 - resolution: "import-local@npm:3.1.0" - dependencies: - pkg-dir: ^4.2.0 - resolve-cwd: ^3.0.0 - bin: - import-local-fixture: fixtures/cli.js - checksum: bfcdb63b5e3c0e245e347f3107564035b128a414c4da1172a20dc67db2504e05ede4ac2eee1252359f78b0bfd7b19ef180aec427c2fce6493ae782d73a04cddd - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: ^1.3.0 - wrappy: 1 - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:~2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 - languageName: node - linkType: hard - -"inherits@npm:2.0.3": - version: 2.0.3 - resolution: "inherits@npm:2.0.3" - checksum: 78cb8d7d850d20a5e9a7f3620db31483aa00ad5f722ce03a55b110e5a723539b3716a3b463e2b96ce3fe286f33afc7c131fa2f91407528ba80cea98a7545d4c0 - languageName: node - linkType: hard - -"ini@npm:^1.3.5": - version: 1.3.8 - resolution: "ini@npm:1.3.8" - checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 - languageName: node - linkType: hard - -"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5": - version: 1.0.5 - resolution: "internal-slot@npm:1.0.5" - dependencies: - get-intrinsic: ^1.2.0 - has: ^1.0.3 - side-channel: ^1.0.4 - checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a - languageName: node - linkType: hard - -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 - languageName: node - linkType: hard - -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 - languageName: node - linkType: hard - -"ipaddr.js@npm:^2.0.1": - version: 2.1.0 - resolution: "ipaddr.js@npm:2.1.0" - checksum: 807a054f2bd720c4d97ee479d6c9e865c233bea21f139fb8dabd5a35c4226d2621c42e07b4ad94ff3f82add926a607d8d9d37c625ad0319f0e08f9f2bd1968e2 - languageName: node - linkType: hard - -"is-arguments@npm:^1.1.1": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": - version: 3.0.2 - resolution: "is-array-buffer@npm:3.0.2" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.0 - is-typed-array: ^1.1.10 - checksum: dcac9dda66ff17df9cabdc58214172bf41082f956eab30bb0d86bc0fab1e44b690fc8e1f855cf2481245caf4e8a5a006a982a71ddccec84032ed41f9d8da8c14 - languageName: node - linkType: hard - -"is-arrayish@npm:^0.2.1": - version: 0.2.1 - resolution: "is-arrayish@npm:0.2.1" - checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f - languageName: node - linkType: hard - -"is-async-function@npm:^2.0.0": - version: 2.0.0 - resolution: "is-async-function@npm:2.0.0" - dependencies: - has-tostringtag: ^1.0.0 - checksum: e3471d95e6c014bf37cad8a93f2f4b6aac962178e0a5041e8903147166964fdc1c5c1d2ef87e86d77322c370ca18f2ea004fa7420581fa747bcaf7c223069dbd - languageName: node - linkType: hard - -"is-bigint@npm:^1.0.1": - version: 1.0.4 - resolution: "is-bigint@npm:1.0.4" - dependencies: - has-bigints: ^1.0.1 - checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 - languageName: node - linkType: hard - -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: ^2.0.0 - checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.1.0": - version: 1.1.2 - resolution: "is-boolean-object@npm:1.1.2" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 - languageName: node - linkType: hard - -"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.9.0": - version: 2.13.0 - resolution: "is-core-module@npm:2.13.0" - dependencies: - has: ^1.0.3 - checksum: 053ab101fb390bfeb2333360fd131387bed54e476b26860dc7f5a700bbf34a0ec4454f7c8c4d43e8a0030957e4b3db6e16d35e1890ea6fb654c833095e040355 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": - version: 1.0.5 - resolution: "is-date-object@npm:1.0.5" - dependencies: - has-tostringtag: ^1.0.0 - checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - -"is-finalizationregistry@npm:^1.0.2": - version: 1.0.2 - resolution: "is-finalizationregistry@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - checksum: 4f243a8e06228cd45bdab8608d2cb7abfc20f6f0189c8ac21ea8d603f1f196eabd531ce0bb8e08cbab047e9845ef2c191a3761c9a17ad5cabf8b35499c4ad35d - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-generator-fn@npm:^2.0.0": - version: 2.1.0 - resolution: "is-generator-fn@npm:2.1.0" - checksum: a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 - languageName: node - linkType: hard - -"is-generator-function@npm:^1.0.10": - version: 1.0.10 - resolution: "is-generator-function@npm:1.0.10" - dependencies: - has-tostringtag: ^1.0.0 - checksum: d54644e7dbaccef15ceb1e5d91d680eb5068c9ee9f9eb0a9e04173eb5542c9b51b5ab52c5537f5703e48d5fddfd376817c1ca07a84a407b7115b769d4bdde72b - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: ^2.1.1 - checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"is-map@npm:^2.0.1, is-map@npm:^2.0.2": - version: 2.0.2 - resolution: "is-map@npm:2.0.2" - checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728 - languageName: node - linkType: hard - -"is-module@npm:^1.0.0": - version: 1.0.0 - resolution: "is-module@npm:1.0.0" - checksum: 8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.2": - version: 2.0.2 - resolution: "is-negative-zero@npm:2.0.2" - checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a - languageName: node - linkType: hard - -"is-number-object@npm:^1.0.4": - version: 1.0.7 - resolution: "is-number-object@npm:1.0.7" - dependencies: - has-tostringtag: ^1.0.0 - checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a - languageName: node - linkType: hard - -"is-obj@npm:^1.0.1": - version: 1.0.1 - resolution: "is-obj@npm:1.0.1" - checksum: 3ccf0efdea12951e0b9c784e2b00e77e87b2f8bd30b42a498548a8afcc11b3287342a2030c308e473e93a7a19c9ea7854c99a8832a476591c727df2a9c79796c - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.3": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 - languageName: node - linkType: hard - -"is-plain-obj@npm:^3.0.0": - version: 3.0.0 - resolution: "is-plain-obj@npm:3.0.0" - checksum: a6ebdf8e12ab73f33530641972a72a4b8aed6df04f762070d823808303e4f76d87d5ea5bd76f96a7bbe83d93f04ac7764429c29413bd9049853a69cb630fb21c - languageName: node - linkType: hard - -"is-potential-custom-element-name@npm:^1.0.1": - version: 1.0.1 - resolution: "is-potential-custom-element-name@npm:1.0.1" - checksum: ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab - languageName: node - linkType: hard - -"is-regex@npm:^1.1.4": - version: 1.1.4 - resolution: "is-regex@npm:1.1.4" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 - languageName: node - linkType: hard - -"is-regexp@npm:^1.0.0": - version: 1.0.0 - resolution: "is-regexp@npm:1.0.0" - checksum: be692828e24cba479ec33644326fa98959ec68ba77965e0291088c1a741feaea4919d79f8031708f85fd25e39de002b4520622b55460660b9c369e6f7187faef - languageName: node - linkType: hard - -"is-root@npm:^2.1.0": - version: 2.1.0 - resolution: "is-root@npm:2.1.0" - checksum: 37eea0822a2a9123feb58a9d101558ba276771a6d830f87005683349a9acff15958a9ca590a44e778c6b335660b83e85c744789080d734f6081a935a4880aee2 - languageName: node - linkType: hard - -"is-set@npm:^2.0.1, is-set@npm:^2.0.2": - version: 2.0.2 - resolution: "is-set@npm:2.0.2" - checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "is-shared-array-buffer@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - -"is-string@npm:^1.0.5, is-string@npm:^1.0.7": - version: 1.0.7 - resolution: "is-string@npm:1.0.7" - dependencies: - has-tostringtag: ^1.0.0 - checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": - version: 1.0.4 - resolution: "is-symbol@npm:1.0.4" - dependencies: - has-symbols: ^1.0.2 - checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.12, is-typed-array@npm:^1.1.9": - version: 1.1.12 - resolution: "is-typed-array@npm:1.1.12" - dependencies: - which-typed-array: ^1.1.11 - checksum: 4c89c4a3be07186caddadf92197b17fda663a9d259ea0d44a85f171558270d36059d1c386d34a12cba22dfade5aba497ce22778e866adc9406098c8fc4771796 - languageName: node - linkType: hard - -"is-typedarray@npm:^1.0.0": - version: 1.0.0 - resolution: "is-typedarray@npm:1.0.0" - checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.1": - version: 2.0.1 - resolution: "is-weakmap@npm:2.0.1" - checksum: 1222bb7e90c32bdb949226e66d26cb7bce12e1e28e3e1b40bfa6b390ba3e08192a8664a703dff2a00a84825f4e022f9cd58c4599ff9981ab72b1d69479f4f7f6 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2": - version: 1.0.2 - resolution: "is-weakref@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.1": - version: 2.0.2 - resolution: "is-weakset@npm:2.0.2" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: 5d8698d1fa599a0635d7ca85be9c26d547b317ed8fd83fc75f03efbe75d50001b5eececb1e9971de85fcde84f69ae6f8346bc92d20d55d46201d328e4c74a367 - languageName: node - linkType: hard - -"is-wsl@npm:^2.2.0": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: ^2.0.0 - checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 - languageName: node - linkType: hard - -"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.0 - resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 - languageName: node - linkType: hard - -"istanbul-lib-instrument@npm:^5.0.4, istanbul-lib-instrument@npm:^5.1.0": - version: 5.2.1 - resolution: "istanbul-lib-instrument@npm:5.2.1" - dependencies: - "@babel/core": ^7.12.3 - "@babel/parser": ^7.14.7 - "@istanbuljs/schema": ^0.1.2 - istanbul-lib-coverage: ^3.2.0 - semver: ^6.3.0 - checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 - languageName: node - linkType: hard - -"istanbul-lib-report@npm:^3.0.0": - version: 3.0.1 - resolution: "istanbul-lib-report@npm:3.0.1" - dependencies: - istanbul-lib-coverage: ^3.0.0 - make-dir: ^4.0.0 - supports-color: ^7.1.0 - checksum: fd17a1b879e7faf9bb1dc8f80b2a16e9f5b7b8498fe6ed580a618c34df0bfe53d2abd35bf8a0a00e628fb7405462576427c7df20bbe4148d19c14b431c974b21 - languageName: node - linkType: hard - -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" - dependencies: - debug: ^4.1.1 - istanbul-lib-coverage: ^3.0.0 - source-map: ^0.6.1 - checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 - languageName: node - linkType: hard - -"istanbul-reports@npm:^3.1.3": - version: 3.1.6 - resolution: "istanbul-reports@npm:3.1.6" - dependencies: - html-escaper: ^2.0.0 - istanbul-lib-report: ^3.0.0 - checksum: 44c4c0582f287f02341e9720997f9e82c071627e1e862895745d5f52ec72c9b9f38e1d12370015d2a71dcead794f34c7732aaef3fab80a24bc617a21c3d911d6 - languageName: node - linkType: hard - -"iterator.prototype@npm:^1.1.2": - version: 1.1.2 - resolution: "iterator.prototype@npm:1.1.2" - dependencies: - define-properties: ^1.2.1 - get-intrinsic: ^1.2.1 - has-symbols: ^1.0.3 - reflect.getprototypeof: ^1.0.4 - set-function-name: ^2.0.1 - checksum: d8a507e2ccdc2ce762e8a1d3f4438c5669160ac72b88b648e59a688eec6bc4e64b22338e74000518418d9e693faf2a092d2af21b9ec7dbf7763b037a54701168 - languageName: node - linkType: hard - -"jackspeak@npm:^2.0.3": - version: 2.3.3 - resolution: "jackspeak@npm:2.3.3" - dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 4313a7c0cc44c7753c4cb9869935f0b06f4cf96827515f63f58ff46b3d2f6e29aba6b3b5151778397c3f5ae67ef8bfc48871967bd10343c27e90cff198ec7808 - languageName: node - linkType: hard - -"jake@npm:^10.8.5": - version: 10.8.7 - resolution: "jake@npm:10.8.7" - dependencies: - async: ^3.2.3 - chalk: ^4.0.2 - filelist: ^1.0.4 - minimatch: ^3.1.2 - bin: - jake: bin/cli.js - checksum: a23fd2273fb13f0d0d845502d02c791fd55ef5c6a2d207df72f72d8e1eac6d2b8ffa6caf660bc8006b3242e0daaa88a3ecc600194d72b5c6016ad56e9cd43553 - languageName: node - linkType: hard - -"jest-changed-files@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-changed-files@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - execa: ^5.0.0 - throat: ^6.0.1 - checksum: 95e9dc74c3ca688ef85cfeab270f43f8902721a6c8ade6ac2459459a77890c85977f537d6fb809056deaa6d9c3f075fa7d2699ff5f3bf7d3fda17c3760b79b15 - languageName: node - linkType: hard - -"jest-circus@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-circus@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - co: ^4.6.0 - dedent: ^0.7.0 - expect: ^27.5.1 - is-generator-fn: ^2.0.0 - jest-each: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 - slash: ^3.0.0 - stack-utils: ^2.0.3 - throat: ^6.0.1 - checksum: 6192dccbccb3a6acfa361cbb97bdbabe94864ccf3d885932cfd41f19534329d40698078cf9be1489415e8234255d6ea9f9aff5396b79ad842a6fca6e6fc08fd0 - languageName: node - linkType: hard - -"jest-cli@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-cli@npm:27.5.1" - dependencies: - "@jest/core": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 - chalk: ^4.0.0 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - import-local: ^3.0.2 - jest-config: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 - prompts: ^2.0.1 - yargs: ^16.2.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 6c0a69fb48e500241409e09ff743ed72bc6578d7769e2c994724e7ef1e5587f6c1f85dc429e93b98ae38a365222993ee70f0acc2199358992120900984f349e5 - languageName: node - linkType: hard - -"jest-config@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-config@npm:27.5.1" - dependencies: - "@babel/core": ^7.8.0 - "@jest/test-sequencer": ^27.5.1 - "@jest/types": ^27.5.1 - babel-jest: ^27.5.1 - chalk: ^4.0.0 - ci-info: ^3.2.0 - deepmerge: ^4.2.2 - glob: ^7.1.1 - graceful-fs: ^4.2.9 - jest-circus: ^27.5.1 - jest-environment-jsdom: ^27.5.1 - jest-environment-node: ^27.5.1 - jest-get-type: ^27.5.1 - jest-jasmine2: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-runner: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 - micromatch: ^4.0.4 - parse-json: ^5.2.0 - pretty-format: ^27.5.1 - slash: ^3.0.0 - strip-json-comments: ^3.1.1 - peerDependencies: - ts-node: ">=9.0.0" - peerDependenciesMeta: - ts-node: - optional: true - checksum: 1188fd46c0ed78cbe3175eb9ad6712ccf74a74be33d9f0d748e147c107f0889f8b701fbff1567f31836ae18597dacdc43d6a8fc30dd34ade6c9229cc6c7cb82d - languageName: node - linkType: hard - -"jest-diff@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-diff@npm:27.5.1" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^27.5.1 - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: 8be27c1e1ee57b2bb2bef9c0b233c19621b4c43d53a3c26e2c00a4e805eb4ea11fe1694a06a9fb0e80ffdcfdc0d2b1cb0b85920b3f5c892327ecd1e7bd96b865 - languageName: node - linkType: hard - -"jest-diff@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-diff@npm:29.7.0" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^29.6.3 - jest-get-type: ^29.6.3 - pretty-format: ^29.7.0 - checksum: 08e24a9dd43bfba1ef07a6374e5af138f53137b79ec3d5cc71a2303515335898888fa5409959172e1e05de966c9e714368d15e8994b0af7441f0721ee8e1bb77 - languageName: node - linkType: hard - -"jest-docblock@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-docblock@npm:27.5.1" - dependencies: - detect-newline: ^3.0.0 - checksum: c0fed6d55b229d8bffdd8d03f121dd1a3be77c88f50552d374f9e1ea3bde57bf6bea017a0add04628d98abcb1bfb48b456438eeca8a74ef0053f4dae3b95d29c - languageName: node - linkType: hard - -"jest-each@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-each@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - chalk: ^4.0.0 - jest-get-type: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 - checksum: b5a6d8730fd938982569c9e0b42bdf3c242f97b957ed8155a6473b5f7b540970f8685524e7f53963dc1805319f4b6602abfc56605590ca19d55bd7a87e467e63 - languageName: node - linkType: hard - -"jest-environment-jsdom@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-environment-jsdom@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - jsdom: ^16.6.0 - checksum: bc104aef7d7530d0740402aa84ac812138b6d1e51fe58adecce679f82b99340ddab73e5ec68fa079f33f50c9ddec9728fc9f0ddcca2ad6f0b351eed2762cc555 - languageName: node - linkType: hard - -"jest-environment-node@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-environment-node@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - checksum: 0f988330c4f3eec092e3fb37ea753b0c6f702e83cd8f4d770af9c2bf964a70bc45fbd34ec6fdb6d71ce98a778d9f54afd673e63f222e4667fff289e8069dba39 - languageName: node - linkType: hard - -"jest-get-type@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-get-type@npm:27.5.1" - checksum: 63064ab70195c21007d897c1157bf88ff94a790824a10f8c890392e7d17eda9c3900513cb291ca1c8d5722cad79169764e9a1279f7c8a9c4cd6e9109ff04bbc0 - languageName: node - linkType: hard - -"jest-get-type@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-get-type@npm:29.6.3" - checksum: 88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 - languageName: node - linkType: hard - -"jest-haste-map@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-haste-map@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - "@types/graceful-fs": ^4.1.2 - "@types/node": "*" - anymatch: ^3.0.3 - fb-watchman: ^2.0.0 - fsevents: ^2.3.2 - graceful-fs: ^4.2.9 - jest-regex-util: ^27.5.1 - jest-serializer: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 - micromatch: ^4.0.4 - walker: ^1.0.7 - dependenciesMeta: - fsevents: - optional: true - checksum: e092a1412829a9254b4725531ee72926de530f77fda7b0d9ea18008fb7623c16f72e772d8e93be71cac9e591b2c6843a669610887dd2c89bd9eb528856e3ab47 - languageName: node - linkType: hard - -"jest-jasmine2@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-jasmine2@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/source-map": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - co: ^4.6.0 - expect: ^27.5.1 - is-generator-fn: ^2.0.0 - jest-each: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 - throat: ^6.0.1 - checksum: b716adf253ceb73db661936153394ab90d7f3a8ba56d6189b7cd4df8e4e2a4153b4e63ebb5d36e29ceb0f4c211d5a6f36ab7048c6abbd881c8646567e2ab8e6d - languageName: node - linkType: hard - -"jest-leak-detector@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-leak-detector@npm:27.5.1" - dependencies: - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: 5c9689060960567ddaf16c570d87afa760a461885765d2c71ef4f4857bbc3af1482c34e3cce88e50beefde1bf35e33530b020480752057a7e3dbb1ca0bae359f - languageName: node - linkType: hard - -"jest-matcher-utils@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-matcher-utils@npm:27.5.1" - dependencies: - chalk: ^4.0.0 - jest-diff: ^27.5.1 - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: bb2135fc48889ff3fe73888f6cc7168ddab9de28b51b3148f820c89fdfd2effdcad005f18be67d0b9be80eda208ad47290f62f03d0a33f848db2dd0273c8217a - languageName: node - linkType: hard - -"jest-matcher-utils@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-matcher-utils@npm:29.7.0" - dependencies: - chalk: ^4.0.0 - jest-diff: ^29.7.0 - jest-get-type: ^29.6.3 - pretty-format: ^29.7.0 - checksum: d7259e5f995d915e8a37a8fd494cb7d6af24cd2a287b200f831717ba0d015190375f9f5dc35393b8ba2aae9b2ebd60984635269c7f8cff7d85b077543b7744cd - languageName: node - linkType: hard - -"jest-message-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-message-util@npm:27.5.1" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^27.5.1 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^27.5.1 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: eb6d637d1411c71646de578c49826b6da8e33dd293e501967011de9d1916d53d845afbfb52a5b661ff1c495be7c13f751c48c7f30781fd94fbd64842e8195796 - languageName: node - linkType: hard - -"jest-message-util@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-message-util@npm:28.1.3" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^28.1.3 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^28.1.3 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: 1f266854166dcc6900d75a88b54a25225a2f3710d463063ff1c99021569045c35c7d58557b25447a17eb3a65ce763b2f9b25550248b468a9d4657db365f39e96 - languageName: node - linkType: hard - -"jest-message-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-message-util@npm:29.7.0" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^29.6.3 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^29.7.0 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: a9d025b1c6726a2ff17d54cc694de088b0489456c69106be6b615db7a51b7beb66788bea7a59991a019d924fbf20f67d085a445aedb9a4d6760363f4d7d09930 - languageName: node - linkType: hard - -"jest-mock@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-mock@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - "@types/node": "*" - checksum: f5b5904bb1741b4a1687a5f492535b7b1758dc26534c72a5423305f8711292e96a601dec966df81bb313269fb52d47227e29f9c2e08324d79529172f67311be0 - languageName: node - linkType: hard - -"jest-pnp-resolver@npm:^1.2.2": - version: 1.2.3 - resolution: "jest-pnp-resolver@npm:1.2.3" - peerDependencies: - jest-resolve: "*" - peerDependenciesMeta: - jest-resolve: - optional: true - checksum: db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 - languageName: node - linkType: hard - -"jest-regex-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-regex-util@npm:27.5.1" - checksum: d45ca7a9543616a34f7f3079337439cf07566e677a096472baa2810e274b9808b76767c97b0a4029b8a5b82b9d256dee28ef9ad4138b2b9e5933f6fac106c418 - languageName: node - linkType: hard - -"jest-regex-util@npm:^28.0.0": - version: 28.0.2 - resolution: "jest-regex-util@npm:28.0.2" - checksum: 0ea8c5c82ec88bc85e273c0ec82e0c0f35f7a1e2d055070e50f0cc2a2177f848eec55f73e37ae0d045c3db5014c42b2f90ac62c1ab3fdb354d2abd66a9e08add - languageName: node - linkType: hard - -"jest-resolve-dependencies@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-resolve-dependencies@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - jest-regex-util: ^27.5.1 - jest-snapshot: ^27.5.1 - checksum: c67af97afad1da88f5530317c732bbd1262d1225f6cd7f4e4740a5db48f90ab0bd8564738ac70d1a43934894f9aef62205c1b8f8ee89e5c7a737e6a121ee4c25 - languageName: node - linkType: hard - -"jest-resolve@npm:^27.4.2, jest-resolve@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-resolve@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-pnp-resolver: ^1.2.2 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 - resolve: ^1.20.0 - resolve.exports: ^1.1.0 - slash: ^3.0.0 - checksum: 735830e7265b20a348029738680bb2f6e37f80ecea86cda869a4c318ba3a45d39c7a3a873a22f7f746d86258c50ead6e7f501de043e201c095d7ba628a1c440f - languageName: node - linkType: hard - -"jest-runner@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-runner@npm:27.5.1" - dependencies: - "@jest/console": ^27.5.1 - "@jest/environment": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - emittery: ^0.8.1 - graceful-fs: ^4.2.9 - jest-docblock: ^27.5.1 - jest-environment-jsdom: ^27.5.1 - jest-environment-node: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-leak-detector: ^27.5.1 - jest-message-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-runtime: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 - source-map-support: ^0.5.6 - throat: ^6.0.1 - checksum: 5bbe6cf847dd322b3332ec9d6977b54f91bd5f72ff620bc1a0192f0f129deda8aa7ca74c98922187a7aa87d8e0ce4f6c50e99a7ccb2a310bf4d94be2e0c3ce8e - languageName: node - linkType: hard - -"jest-runtime@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-runtime@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/globals": ^27.5.1 - "@jest/source-map": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - chalk: ^4.0.0 - cjs-module-lexer: ^1.0.0 - collect-v8-coverage: ^1.0.0 - execa: ^5.0.0 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-message-util: ^27.5.1 - jest-mock: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - slash: ^3.0.0 - strip-bom: ^4.0.0 - checksum: 929e3df0c53dab43f831f2af4e2996b22aa8cb2d6d483919d6b0426cbc100098fd5b777b998c6568b77f8c4d860b2e83127514292ff61416064f5ef926492386 - languageName: node - linkType: hard - -"jest-serializer@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-serializer@npm:27.5.1" - dependencies: - "@types/node": "*" - graceful-fs: ^4.2.9 - checksum: 803e03a552278610edc6753c0dd9fa5bb5cd3ca47414a7b2918106efb62b79fd5e9ae785d0a21f12a299fa599fea8acc1fa6dd41283328cee43962cf7df9bb44 - languageName: node - linkType: hard - -"jest-snapshot@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-snapshot@npm:27.5.1" - dependencies: - "@babel/core": ^7.7.2 - "@babel/generator": ^7.7.2 - "@babel/plugin-syntax-typescript": ^7.7.2 - "@babel/traverse": ^7.7.2 - "@babel/types": ^7.0.0 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/babel__traverse": ^7.0.4 - "@types/prettier": ^2.1.5 - babel-preset-current-node-syntax: ^1.0.0 - chalk: ^4.0.0 - expect: ^27.5.1 - graceful-fs: ^4.2.9 - jest-diff: ^27.5.1 - jest-get-type: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-util: ^27.5.1 - natural-compare: ^1.4.0 - pretty-format: ^27.5.1 - semver: ^7.3.2 - checksum: a5cfadf0d21cd76063925d1434bc076443ed6d87847d0e248f0b245f11db3d98ff13e45cc03b15404027dabecd712d925f47b6eae4f64986f688640a7d362514 - languageName: node - linkType: hard - -"jest-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-util@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: ac8d122f6daf7a035dcea156641fd3701aeba245417c40836a77e35b3341b9c02ddc5d904cfcd4ddbaa00ab854da76d3b911870cafdcdbaff90ea471de26c7d7 - languageName: node - linkType: hard - -"jest-util@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-util@npm:28.1.3" - dependencies: - "@jest/types": ^28.1.3 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: fd6459742c941f070223f25e38a2ac0719aad92561591e9fb2a50d602a5d19d754750b79b4074327a42b00055662b95da3b006542ceb8b54309da44d4a62e721 - languageName: node - linkType: hard - -"jest-util@npm:^29.7.0": - version: 29.7.0 - resolution: "jest-util@npm:29.7.0" - dependencies: - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: 042ab4980f4ccd4d50226e01e5c7376a8556b472442ca6091a8f102488c0f22e6e8b89ea874111d2328a2080083bf3225c86f3788c52af0bd0345a00eb57a3ca - languageName: node - linkType: hard - -"jest-validate@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-validate@npm:27.5.1" - dependencies: - "@jest/types": ^27.5.1 - camelcase: ^6.2.0 - chalk: ^4.0.0 - jest-get-type: ^27.5.1 - leven: ^3.1.0 - pretty-format: ^27.5.1 - checksum: 82e870f8ee7e4fb949652711b1567f05ae31c54be346b0899e8353e5c20fad7692b511905b37966945e90af8dc0383eb41a74f3ffefb16140ea4f9164d841412 - languageName: node - linkType: hard - -"jest-watch-typeahead@npm:^1.0.0": - version: 1.1.0 - resolution: "jest-watch-typeahead@npm:1.1.0" - dependencies: - ansi-escapes: ^4.3.1 - chalk: ^4.0.0 - jest-regex-util: ^28.0.0 - jest-watcher: ^28.0.0 - slash: ^4.0.0 - string-length: ^5.0.1 - strip-ansi: ^7.0.1 - peerDependencies: - jest: ^27.0.0 || ^28.0.0 - checksum: 59b0a494ac01e3801c9ec586de3209153eedb024b981e25443111c5703711d23b67ebc71b072986c1758307e0bfb5bf1c92bd323f73f58602d6f4f609dce6a0c - languageName: node - linkType: hard - -"jest-watcher@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-watcher@npm:27.5.1" - dependencies: - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - jest-util: ^27.5.1 - string-length: ^4.0.1 - checksum: 191c4e9c278c0902ade1a8a80883ac244963ba3e6e78607a3d5f729ccca9c6e71fb3b316f87883658132641c5d818aa84202585c76752e03c539e6cbecb820bd - languageName: node - linkType: hard - -"jest-watcher@npm:^28.0.0": - version: 28.1.3 - resolution: "jest-watcher@npm:28.1.3" - dependencies: - "@jest/test-result": ^28.1.3 - "@jest/types": ^28.1.3 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - emittery: ^0.10.2 - jest-util: ^28.1.3 - string-length: ^4.0.1 - checksum: 8f6d674a4865e7df251f71544f1b51f06fd36b5a3a61f2ac81aeb81fa2a196be354fba51d0f97911c88f67cd254583b3a22ee124bf2c5b6ee2fadec27356c207 - languageName: node - linkType: hard - -"jest-worker@npm:^26.2.1": - version: 26.6.2 - resolution: "jest-worker@npm:26.6.2" - dependencies: - "@types/node": "*" - merge-stream: ^2.0.0 - supports-color: ^7.0.0 - checksum: f9afa3b88e3f12027901e4964ba3ff048285b5783b5225cab28fac25b4058cea8ad54001e9a1577ee2bed125fac3ccf5c80dc507b120300cc1bbcb368796533e - languageName: node - linkType: hard - -"jest-worker@npm:^27.0.2, jest-worker@npm:^27.4.5, jest-worker@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-worker@npm:27.5.1" - dependencies: - "@types/node": "*" - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: 98cd68b696781caed61c983a3ee30bf880b5bd021c01d98f47b143d4362b85d0737f8523761e2713d45e18b4f9a2b98af1eaee77afade4111bb65c77d6f7c980 - languageName: node - linkType: hard - -"jest-worker@npm:^28.0.2": - version: 28.1.3 - resolution: "jest-worker@npm:28.1.3" - dependencies: - "@types/node": "*" - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: e921c9a1b8f0909da9ea07dbf3592f95b653aef3a8bb0cbcd20fc7f9a795a1304adecac31eecb308992c167e8d7e75c522061fec38a5928ace0f9571c90169ca - languageName: node - linkType: hard - -"jest@npm:^27.4.3": - version: 27.5.1 - resolution: "jest@npm:27.5.1" - dependencies: - "@jest/core": ^27.5.1 - import-local: ^3.0.2 - jest-cli: ^27.5.1 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 96f1d69042b3c6dfc695f2a4e4b0db38af6fb78582ad1a02beaa57cfcd77cbd31567d7d865c1c85709b7c3e176eefa3b2035ffecd646005f15d8ef528eccf205 - languageName: node - linkType: hard - -"jiti@npm:^1.18.2": - version: 1.20.0 - resolution: "jiti@npm:1.20.0" - bin: - jiti: bin/jiti.js - checksum: 7924062b5675142e3e272a27735be84b7bfc0a0eb73217fc2dcafa034f37c4f7b4b9ffc07dd98bcff0f739a8811ce1544db205ae7e97b1c86f0df92c65ce3c72 - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 - languageName: node - linkType: hard - -"js-yaml@npm:^3.13.1": - version: 3.14.1 - resolution: "js-yaml@npm:3.14.1" - dependencies: - argparse: ^1.0.7 - esprima: ^4.0.0 - bin: - js-yaml: bin/js-yaml.js - checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c - languageName: node - linkType: hard - -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" - dependencies: - argparse: ^2.0.1 - bin: - js-yaml: bin/js-yaml.js - checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a - languageName: node - linkType: hard - -"jsdom@npm:^16.6.0": - version: 16.7.0 - resolution: "jsdom@npm:16.7.0" - dependencies: - abab: ^2.0.5 - acorn: ^8.2.4 - acorn-globals: ^6.0.0 - cssom: ^0.4.4 - cssstyle: ^2.3.0 - data-urls: ^2.0.0 - decimal.js: ^10.2.1 - domexception: ^2.0.1 - escodegen: ^2.0.0 - form-data: ^3.0.0 - html-encoding-sniffer: ^2.0.1 - http-proxy-agent: ^4.0.1 - https-proxy-agent: ^5.0.0 - is-potential-custom-element-name: ^1.0.1 - nwsapi: ^2.2.0 - parse5: 6.0.1 - saxes: ^5.0.1 - symbol-tree: ^3.2.4 - tough-cookie: ^4.0.0 - w3c-hr-time: ^1.0.2 - w3c-xmlserializer: ^2.0.0 - webidl-conversions: ^6.1.0 - whatwg-encoding: ^1.0.5 - whatwg-mimetype: ^2.3.0 - whatwg-url: ^8.5.0 - ws: ^7.4.6 - xml-name-validator: ^3.0.0 - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true - checksum: 454b83371857000763ed31130a049acd1b113e3b927e6dcd75c67ddc30cdd242d7ebcac5c2294b7a1a6428155cb1398709c573b3c6d809218692ea68edd93370 - languageName: node - linkType: hard - -"jsesc@npm:^2.5.1": - version: 2.5.2 - resolution: "jsesc@npm:2.5.2" - bin: - jsesc: bin/jsesc - checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d - languageName: node - linkType: hard - -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" - bin: - jsesc: bin/jsesc - checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": - version: 2.3.1 - resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad - languageName: node - linkType: hard - -"json-schema@npm:^0.4.0": - version: 0.4.0 - resolution: "json-schema@npm:0.4.0" - checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 - languageName: node - linkType: hard - -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: ^1.2.0 - bin: - json5: lib/cli.js - checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 - languageName: node - linkType: hard - -"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.3": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 - languageName: node - linkType: hard - -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: ^4.1.6 - universalify: ^2.0.0 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 - languageName: node - linkType: hard - -"jsonpath@npm:^1.1.1": - version: 1.1.1 - resolution: "jsonpath@npm:1.1.1" - dependencies: - esprima: 1.2.2 - static-eval: 2.0.2 - underscore: 1.12.1 - checksum: 5480d8e9e424fe2ed4ade6860b6e2cefddb21adb3a99abe0254cd9428e8ef9b0c9fb5729d6a5a514e90df50d645ccea9f3be48d627570e6222dd5dadc28eba7b - languageName: node - linkType: hard - -"jsonpointer@npm:^5.0.0": - version: 5.0.1 - resolution: "jsonpointer@npm:5.0.1" - checksum: 0b40f712900ad0c846681ea2db23b6684b9d5eedf55807b4708c656f5894b63507d0e28ae10aa1bddbea551241035afe62b6df0800fc94c2e2806a7f3adecd7c - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": - version: 3.3.5 - resolution: "jsx-ast-utils@npm:3.3.5" - dependencies: - array-includes: ^3.1.6 - array.prototype.flat: ^1.3.1 - object.assign: ^4.1.4 - object.values: ^1.1.6 - checksum: f4b05fa4d7b5234230c905cfa88d36dc8a58a6666975a3891429b1a8cdc8a140bca76c297225cb7a499fad25a2c052ac93934449a2c31a44fc9edd06c773780a - languageName: node - linkType: hard - -"keyv@npm:^4.5.3": - version: 4.5.3 - resolution: "keyv@npm:4.5.3" - dependencies: - json-buffer: 3.0.1 - checksum: 3ffb4d5b72b6b4b4af443bbb75ca2526b23c750fccb5ac4c267c6116888b4b65681015c2833cb20d26cf3e6e32dac6b988c77f7f022e1a571b7d90f1442257da - languageName: node - linkType: hard - -"kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b - languageName: node - linkType: hard - -"kleur@npm:^3.0.3": - version: 3.0.3 - resolution: "kleur@npm:3.0.3" - checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 - languageName: node - linkType: hard - -"klona@npm:^2.0.4, klona@npm:^2.0.5": - version: 2.0.6 - resolution: "klona@npm:2.0.6" - checksum: ac9ee3732e42b96feb67faae4d27cf49494e8a3bf3fa7115ce242fe04786788e0aff4741a07a45a2462e2079aa983d73d38519c85d65b70ef11447bbc3c58ce7 - languageName: node - linkType: hard - -"language-subtag-registry@npm:~0.3.2": - version: 0.3.22 - resolution: "language-subtag-registry@npm:0.3.22" - checksum: 8ab70a7e0e055fe977ac16ea4c261faec7205ac43db5e806f72e5b59606939a3b972c4bd1e10e323b35d6ffa97c3e1c4c99f6553069dad2dfdd22020fa3eb56a - languageName: node - linkType: hard - -"language-tags@npm:=1.0.5": - version: 1.0.5 - resolution: "language-tags@npm:1.0.5" - dependencies: - language-subtag-registry: ~0.3.2 - checksum: c81b5d8b9f5f9cfd06ee71ada6ddfe1cf83044dd5eeefcd1e420ad491944da8957688db4a0a9bc562df4afdc2783425cbbdfd152c01d93179cf86888903123cf - languageName: node - linkType: hard - -"launch-editor@npm:^2.6.0": - version: 2.6.0 - resolution: "launch-editor@npm:2.6.0" - dependencies: - picocolors: ^1.0.0 - shell-quote: ^1.7.3 - checksum: 48e4230643e8fdb5c14c11314706d58d9f3fbafe2606be3d6e37da1918ad8bfe39dd87875c726a1b59b9f4da99d87ec3e36d4c528464f0b820f9e91e5cb1c02d - languageName: node - linkType: hard - -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: ^1.2.1 - type-check: ~0.4.0 - checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 - languageName: node - linkType: hard - -"levn@npm:~0.3.0": - version: 0.3.0 - resolution: "levn@npm:0.3.0" - dependencies: - prelude-ls: ~1.1.2 - type-check: ~0.3.2 - checksum: 0d084a524231a8246bb10fec48cdbb35282099f6954838604f3c7fc66f2e16fa66fd9cc2f3f20a541a113c4dafdf181e822c887c8a319c9195444e6c64ac395e - languageName: node - linkType: hard - -"lilconfig@npm:^2.0.3, lilconfig@npm:^2.0.5, lilconfig@npm:^2.1.0": - version: 2.1.0 - resolution: "lilconfig@npm:2.1.0" - checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 - languageName: node - linkType: hard - -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 - languageName: node - linkType: hard - -"loader-runner@npm:^4.2.0": - version: 4.3.0 - resolution: "loader-runner@npm:4.3.0" - checksum: a90e00dee9a16be118ea43fec3192d0b491fe03a32ed48a4132eb61d498f5536a03a1315531c19d284392a8726a4ecad71d82044c28d7f22ef62e029bf761569 - languageName: node - linkType: hard - -"loader-utils@npm:^2.0.0, loader-utils@npm:^2.0.4": - version: 2.0.4 - resolution: "loader-utils@npm:2.0.4" - dependencies: - big.js: ^5.2.2 - emojis-list: ^3.0.0 - json5: ^2.1.2 - checksum: a5281f5fff1eaa310ad5e1164095689443630f3411e927f95031ab4fb83b4a98f388185bb1fe949e8ab8d4247004336a625e9255c22122b815bb9a4c5d8fc3b7 - languageName: node - linkType: hard - -"loader-utils@npm:^3.2.0": - version: 3.2.1 - resolution: "loader-utils@npm:3.2.1" - checksum: 4e3ea054cdc8be1ab1f1238f49f42fdf0483039eff920fb1d442039f3f0ad4ebd11fb8e584ccdf2cb7e3c56b3d40c1832416e6408a55651b843da288960cc792 - languageName: node - linkType: hard - -"locate-path@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-path@npm:3.0.0" - dependencies: - p-locate: ^3.0.0 - path-exists: ^3.0.0 - checksum: 53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 - languageName: node - linkType: hard - -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" - dependencies: - p-locate: ^4.1.0 - checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: ^5.0.0 - checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a - languageName: node - linkType: hard - -"lodash.debounce@npm:^4.0.8": - version: 4.0.8 - resolution: "lodash.debounce@npm:4.0.8" - checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 - languageName: node - linkType: hard - -"lodash.memoize@npm:^4.1.2": - version: 4.1.2 - resolution: "lodash.memoize@npm:4.1.2" - checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 - languageName: node - linkType: hard - -"lodash.sortby@npm:^4.7.0": - version: 4.7.0 - resolution: "lodash.sortby@npm:4.7.0" - checksum: db170c9396d29d11fe9a9f25668c4993e0c1331bcb941ddbd48fb76f492e732add7f2a47cfdf8e9d740fa59ac41bbfaf931d268bc72aab3ab49e9f89354d718c - languageName: node - linkType: hard - -"lodash.uniq@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.uniq@npm:4.5.0" - checksum: a4779b57a8d0f3c441af13d9afe7ecff22dd1b8ce1129849f71d9bbc8e8ee4e46dfb4b7c28f7ad3d67481edd6e51126e4e2a6ee276e25906d10f7140187c392d - languageName: node - linkType: hard - -"lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 - languageName: node - linkType: hard - -"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: ^3.0.0 || ^4.0.0 - bin: - loose-envify: cli.js - checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 - languageName: node - linkType: hard - -"lower-case@npm:^2.0.2": - version: 2.0.2 - resolution: "lower-case@npm:2.0.2" - dependencies: - tslib: ^2.0.3 - checksum: 83a0a5f159ad7614bee8bf976b96275f3954335a84fad2696927f609ddae902802c4f3312d86668722e668bef41400254807e1d3a7f2e8c3eede79691aa1f010 - languageName: node - linkType: hard - -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: ^3.0.2 - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 - languageName: node - linkType: hard - -"lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 - languageName: node - linkType: hard - -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.1 - resolution: "lru-cache@npm:10.0.1" - checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 - languageName: node - linkType: hard - -"lz-string@npm:^1.5.0": - version: 1.5.0 - resolution: "lz-string@npm:1.5.0" - bin: - lz-string: bin/bin.js - checksum: 1ee98b4580246fd90dd54da6e346fb1caefcf05f677c686d9af237a157fdea3fd7c83a4bc58f858cd5b10a34d27afe0fdcbd0505a47e0590726a873dc8b8f65d - languageName: node - linkType: hard - -"magic-string@npm:^0.25.0, magic-string@npm:^0.25.7": - version: 0.25.9 - resolution: "magic-string@npm:0.25.9" - dependencies: - sourcemap-codec: ^1.4.8 - checksum: 9a0e55a15c7303fc360f9572a71cffba1f61451bc92c5602b1206c9d17f492403bf96f946dfce7483e66822d6b74607262e24392e87b0ac27b786e69a40e9b1a - languageName: node - linkType: hard - -"make-dir@npm:^3.0.2, make-dir@npm:^3.1.0": - version: 3.1.0 - resolution: "make-dir@npm:3.1.0" - dependencies: - semver: ^6.0.0 - checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 - languageName: node - linkType: hard - -"make-dir@npm:^4.0.0": - version: 4.0.0 - resolution: "make-dir@npm:4.0.0" - dependencies: - semver: ^7.5.3 - checksum: bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a - languageName: node - linkType: hard - -"make-fetch-happen@npm:^11.0.3": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" - dependencies: - agentkeepalive: ^4.2.1 - cacache: ^17.0.0 - http-cache-semantics: ^4.1.1 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^5.0.0 - minipass-fetch: ^3.0.0 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.3 - promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 - ssri: ^10.0.0 - checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 - languageName: node - linkType: hard - -"makeerror@npm:1.0.12": - version: 1.0.12 - resolution: "makeerror@npm:1.0.12" - dependencies: - tmpl: 1.0.5 - checksum: b38a025a12c8146d6eeea5a7f2bf27d51d8ad6064da8ca9405fcf7bf9b54acd43e3b30ddd7abb9b1bfa4ddb266019133313482570ddb207de568f71ecfcf6060 - languageName: node - linkType: hard - -"mdn-data@npm:2.0.14": - version: 2.0.14 - resolution: "mdn-data@npm:2.0.14" - checksum: 9d0128ed425a89f4cba8f787dca27ad9408b5cb1b220af2d938e2a0629d17d879a34d2cb19318bdb26c3f14c77dd5dfbae67211f5caaf07b61b1f2c5c8c7dc16 - languageName: node - linkType: hard - -"mdn-data@npm:2.0.4": - version: 2.0.4 - resolution: "mdn-data@npm:2.0.4" - checksum: add3c95e6d03d301b8a8bcfee3de33f4d07e4c5eee5b79f18d6d737de717e22472deadf67c1a8563983c0b603e10d7df40aa8e5fddf18884dfe118ccec7ae329 - languageName: node - linkType: hard - -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: af1b38516c28ec95d6b0826f6c8f276c58aec391f76be42aa07646b4e39d317723e869700933ca6995b056db4b09a78c92d5440dc23657e6764be5d28874bba1 - languageName: node - linkType: hard - -"memfs@npm:^3.1.2, memfs@npm:^3.4.3": - version: 3.5.3 - resolution: "memfs@npm:3.5.3" - dependencies: - fs-monkey: ^1.0.4 - checksum: 18dfdeacad7c8047b976a6ccd58bc98ba76e122ad3ca0e50a21837fe2075fc0d9aafc58ab9cf2576c2b6889da1dd2503083f2364191b695273f40969db2ecc44 - languageName: node - linkType: hard - -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 - languageName: node - linkType: hard - -"methods@npm:~1.1.2": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a - languageName: node - linkType: hard - -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": - version: 4.0.5 - resolution: "micromatch@npm:4.0.5" - dependencies: - braces: ^3.0.2 - picomatch: ^2.3.1 - checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc - languageName: node - linkType: hard - -"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: 1.52.0 - checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 - languageName: node - linkType: hard - -"mime@npm:1.6.0": - version: 1.6.0 - resolution: "mime@npm:1.6.0" - bin: - mime: cli.js - checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - -"min-indent@npm:^1.0.0": - version: 1.0.1 - resolution: "min-indent@npm:1.0.1" - checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 - languageName: node - linkType: hard - -"mini-css-extract-plugin@npm:^2.4.5": - version: 2.7.6 - resolution: "mini-css-extract-plugin@npm:2.7.6" - dependencies: - schema-utils: ^4.0.0 - peerDependencies: - webpack: ^5.0.0 - checksum: be6f7cefc6275168eb0a6b8fe977083a18c743c9612c9f00e6c1a62c3393ca7960e93fba1a7ebb09b75f36a0204ad087d772c1ef574bc29c90c0e8175a3c0b83 - languageName: node - linkType: hard - -"minimalistic-assert@npm:^1.0.0": - version: 1.0.1 - resolution: "minimalistic-assert@npm:1.0.1" - checksum: cc7974a9268fbf130fb055aff76700d7e2d8be5f761fb5c60318d0ed010d839ab3661a533ad29a5d37653133385204c503bfac995aaa4236f4e847461ea32ba7 - languageName: node - linkType: hard - -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - -"minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: ^2.0.1 - checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.1": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: ^2.0.1 - checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 - languageName: node - linkType: hard - -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" - dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.4 - resolution: "minipass-fetch@npm:3.0.4" - dependencies: - encoding: ^0.1.13 - minipass: ^7.0.3 - minipass-sized: ^1.0.3 - minizlib: ^2.1.2 - dependenciesMeta: - encoding: - optional: true - checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: ^3.0.0 - checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: ^3.0.0 - checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: ^3.0.0 - checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: ^4.0.0 - checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": - version: 7.0.3 - resolution: "minipass@npm:7.0.3" - checksum: 6f1614f5b5b55568a46bca5fec0e7c46dac027691db27d0e1923a8192866903144cd962ac772c0e9f89b608ea818b702709c042bce98e190d258847d85461531 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: ^3.0.0 - yallist: ^4.0.0 - checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f - languageName: node - linkType: hard - -"mkdirp@npm:~0.5.1": - version: 0.5.6 - resolution: "mkdirp@npm:0.5.6" - dependencies: - minimist: ^1.2.6 - bin: - mkdirp: bin/cmd.js - checksum: 0c91b721bb12c3f9af4b77ebf73604baf350e64d80df91754dc509491ae93bf238581e59c7188360cec7cb62fc4100959245a42cfe01834efedc5e9d068376c2 - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4 - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"multicast-dns@npm:^7.2.5": - version: 7.2.5 - resolution: "multicast-dns@npm:7.2.5" - dependencies: - dns-packet: ^5.2.2 - thunky: ^1.0.2 - bin: - multicast-dns: cli.js - checksum: 00b8a57df152d4cd0297946320a94b7c3cdf75a46a2247f32f958a8927dea42958177f9b7fdae69fab2e4e033fb3416881af1f5e9055a3e1542888767139e2fb - languageName: node - linkType: hard - -"mz@npm:^2.7.0": - version: 2.7.0 - resolution: "mz@npm:2.7.0" - dependencies: - any-promise: ^1.0.0 - object-assign: ^4.0.1 - thenify-all: ^1.0.0 - checksum: 8427de0ece99a07e9faed3c0c6778820d7543e3776f9a84d22cf0ec0a8eb65f6e9aee9c9d353ff9a105ff62d33a9463c6ca638974cc652ee8140cd1e35951c87 - languageName: node - linkType: hard - -"nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" - bin: - nanoid: bin/nanoid.cjs - checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 - languageName: node - linkType: hard - -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d - languageName: node - linkType: hard - -"negotiator@npm:0.6.3, negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 - languageName: node - linkType: hard - -"neo-async@npm:^2.6.2": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 - languageName: node - linkType: hard - -"no-case@npm:^3.0.4": - version: 3.0.4 - resolution: "no-case@npm:3.0.4" - dependencies: - lower-case: ^2.0.2 - tslib: ^2.0.3 - checksum: 0b2ebc113dfcf737d48dde49cfebf3ad2d82a8c3188e7100c6f375e30eafbef9e9124aadc3becef237b042fd5eb0aad2fd78669c20972d045bbe7fea8ba0be5c - languageName: node - linkType: hard - -"node-forge@npm:^1": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 08fb072d3d670599c89a1704b3e9c649ff1b998256737f0e06fbd1a5bf41cae4457ccaee32d95052d80bbafd9ffe01284e078c8071f0267dc9744e51c5ed42a9 - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 9.4.0 - resolution: "node-gyp@npm:9.4.0" - dependencies: - env-paths: ^2.2.0 - exponential-backoff: ^3.1.1 - glob: ^7.1.4 - graceful-fs: ^4.2.6 - make-fetch-happen: ^11.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 - semver: ^7.3.5 - tar: ^6.1.2 - which: ^2.0.2 - bin: - node-gyp: bin/node-gyp.js - checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 - languageName: node - linkType: hard - -"node-int64@npm:^0.4.0": - version: 0.4.0 - resolution: "node-int64@npm:0.4.0" - checksum: d0b30b1ee6d961851c60d5eaa745d30b5c95d94bc0e74b81e5292f7c42a49e3af87f1eb9e89f59456f80645d679202537de751b7d72e9e40ceea40c5e449057e - languageName: node - linkType: hard - -"node-releases@npm:^2.0.13": - version: 2.0.13 - resolution: "node-releases@npm:2.0.13" - checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 - languageName: node - linkType: hard - -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" - dependencies: - abbrev: ^1.0.0 - bin: - nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 - languageName: node - linkType: hard - -"normalize-range@npm:^0.1.2": - version: 0.1.2 - resolution: "normalize-range@npm:0.1.2" - checksum: 9b2f14f093593f367a7a0834267c24f3cb3e887a2d9809c77d8a7e5fd08738bcd15af46f0ab01cc3a3d660386f015816b5c922cea8bf2ee79777f40874063184 - languageName: node - linkType: hard - -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: ^3.0.0 - checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a - languageName: node - linkType: hard - -"nth-check@npm:^1.0.2": - version: 1.0.2 - resolution: "nth-check@npm:1.0.2" - dependencies: - boolbase: ~1.0.0 - checksum: 59e115fdd75b971d0030f42ada3aac23898d4c03aa13371fa8b3339d23461d1badf3fde5aad251fb956aaa75c0a3b9bfcd07c08a34a83b4f9dadfdce1d19337c - languageName: node - linkType: hard - -"nth-check@npm:^2.0.1": - version: 2.1.1 - resolution: "nth-check@npm:2.1.1" - dependencies: - boolbase: ^1.0.0 - checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 - languageName: node - linkType: hard - -"nwsapi@npm:^2.2.0": - version: 2.2.7 - resolution: "nwsapi@npm:2.2.7" - checksum: cab25f7983acec7e23490fec3ef7be608041b460504229770e3bfcf9977c41d6fe58f518994d3bd9aa3a101f501089a3d4a63536f4ff8ae4b8c4ca23bdbfda4e - languageName: node - linkType: hard - -"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f - languageName: node - linkType: hard - -"object-hash@npm:^3.0.0": - version: 3.0.0 - resolution: "object-hash@npm:3.0.0" - checksum: 80b4904bb3857c52cc1bfd0b52c0352532ca12ed3b8a6ff06a90cd209dfda1b95cee059a7625eb9da29537027f68ac4619363491eedb2f5d3dddbba97494fd6c - languageName: node - linkType: hard - -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db - languageName: node - linkType: hard - -"object-is@npm:^1.1.5": - version: 1.1.5 - resolution: "object-is@npm:1.1.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe - languageName: node - linkType: hard - -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a - languageName: node - linkType: hard - -"object.assign@npm:^4.1.4": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - has-symbols: ^1.0.3 - object-keys: ^1.1.1 - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 - languageName: node - linkType: hard - -"object.entries@npm:^1.1.6": - version: 1.1.7 - resolution: "object.entries@npm:1.1.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: da287d434e7e32989586cd734382364ba826a2527f2bc82e6acbf9f9bfafa35d51018b66ec02543ffdfa2a5ba4af2b6f1ca6e588c65030cb4fd9c67d6ced594c - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.6": - version: 2.0.7 - resolution: "object.fromentries@npm:2.0.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: 7341ce246e248b39a431b87a9ddd331ff52a454deb79afebc95609f94b1f8238966cf21f52188f2a353f0fdf83294f32f1ebf1f7826aae915ebad21fd0678065 - languageName: node - linkType: hard - -"object.getownpropertydescriptors@npm:^2.1.0": - version: 2.1.7 - resolution: "object.getownpropertydescriptors@npm:2.1.7" - dependencies: - array.prototype.reduce: ^1.0.6 - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - safe-array-concat: ^1.0.0 - checksum: 8e7ae1d522a3874d2d23a3d0fb75828cbcee60958b65c2ad8e58ce227f4efba8cc2b59c7431a0fd48b20d9e04ec075bc0e0d694b1d2c2296e534daf558beb10b - languageName: node - linkType: hard - -"object.groupby@npm:^1.0.0": - version: 1.0.1 - resolution: "object.groupby@npm:1.0.1" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - get-intrinsic: ^1.2.1 - checksum: d7959d6eaaba358b1608066fc67ac97f23ce6f573dc8fc661f68c52be165266fcb02937076aedb0e42722fdda0bdc0bbf74778196ac04868178888e9fd3b78b5 - languageName: node - linkType: hard - -"object.hasown@npm:^1.1.2": - version: 1.1.3 - resolution: "object.hasown@npm:1.1.3" - dependencies: - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: 76bc17356f6124542fb47e5d0e78d531eafa4bba3fc2d6fc4b1a8ce8b6878912366c0d99f37ce5c84ada8fd79df7aa6ea1214fddf721f43e093ad2df51f27da1 - languageName: node - linkType: hard - -"object.values@npm:^1.1.0, object.values@npm:^1.1.6": - version: 1.1.7 - resolution: "object.values@npm:1.1.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: f3e4ae4f21eb1cc7cebb6ce036d4c67b36e1c750428d7b7623c56a0db90edced63d08af8a316d81dfb7c41a3a5fa81b05b7cc9426e98d7da986b1682460f0777 - languageName: node - linkType: hard - -"obuf@npm:^1.0.0, obuf@npm:^1.1.2": - version: 1.1.2 - resolution: "obuf@npm:1.1.2" - checksum: 41a2ba310e7b6f6c3b905af82c275bf8854896e2e4c5752966d64cbcd2f599cfffd5932006bcf3b8b419dfdacebb3a3912d5d94e10f1d0acab59876c8757f27f - languageName: node - linkType: hard - -"on-finished@npm:2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: 1.1.1 - checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 - languageName: node - linkType: hard - -"on-headers@npm:~1.0.2": - version: 1.0.2 - resolution: "on-headers@npm:1.0.2" - checksum: 2bf13467215d1e540a62a75021e8b318a6cfc5d4fc53af8e8f84ad98dbcea02d506c6d24180cd62e1d769c44721ba542f3154effc1f7579a8288c9f7873ed8e5 - languageName: node - linkType: hard - -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: 1 - checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: ^2.1.0 - checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 - languageName: node - linkType: hard - -"open@npm:^8.0.9, open@npm:^8.4.0": - version: 8.4.2 - resolution: "open@npm:8.4.2" - dependencies: - define-lazy-prop: ^2.0.0 - is-docker: ^2.1.1 - is-wsl: ^2.2.0 - checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 - languageName: node - linkType: hard - -"optionator@npm:^0.8.1": - version: 0.8.3 - resolution: "optionator@npm:0.8.3" - dependencies: - deep-is: ~0.1.3 - fast-levenshtein: ~2.0.6 - levn: ~0.3.0 - prelude-ls: ~1.1.2 - type-check: ~0.3.2 - word-wrap: ~1.2.3 - checksum: b8695ddf3d593203e25ab0900e265d860038486c943ff8b774f596a310f8ceebdb30c6832407a8198ba3ec9debe1abe1f51d4aad94843612db3b76d690c61d34 - languageName: node - linkType: hard - -"optionator@npm:^0.9.3": - version: 0.9.3 - resolution: "optionator@npm:0.9.3" - dependencies: - "@aashutoshrathi/word-wrap": ^1.2.3 - deep-is: ^0.1.3 - fast-levenshtein: ^2.0.6 - levn: ^0.4.1 - prelude-ls: ^1.2.1 - type-check: ^0.4.0 - checksum: 09281999441f2fe9c33a5eeab76700795365a061563d66b098923eb719251a42bdbe432790d35064d0816ead9296dbeb1ad51a733edf4167c96bd5d0882e428a - languageName: node - linkType: hard - -"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: ^2.0.0 - checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: ^0.1.0 - checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 - languageName: node - linkType: hard - -"p-locate@npm:^3.0.0": - version: 3.0.0 - resolution: "p-locate@npm:3.0.0" - dependencies: - p-limit: ^2.0.0 - checksum: 83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae - languageName: node - linkType: hard - -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: ^2.2.0 - checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: ^3.0.2 - checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: ^3.0.0 - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c - languageName: node - linkType: hard - -"p-retry@npm:^4.5.0": - version: 4.6.2 - resolution: "p-retry@npm:4.6.2" - dependencies: - "@types/retry": 0.12.0 - retry: ^0.13.1 - checksum: 45c270bfddaffb4a895cea16cb760dcc72bdecb6cb45fef1971fa6ea2e91ddeafddefe01e444ac73e33b1b3d5d29fb0dd18a7effb294262437221ddc03ce0f2e - languageName: node - linkType: hard - -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - -"param-case@npm:^3.0.4": - version: 3.0.4 - resolution: "param-case@npm:3.0.4" - dependencies: - dot-case: ^3.0.4 - tslib: ^2.0.3 - checksum: b34227fd0f794e078776eb3aa6247442056cb47761e9cd2c4c881c86d84c64205f6a56ef0d70b41ee7d77da02c3f4ed2f88e3896a8fefe08bdfb4deca037c687 - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: ^3.0.0 - checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff - languageName: node - linkType: hard - -"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": - version: 5.2.0 - resolution: "parse-json@npm:5.2.0" - dependencies: - "@babel/code-frame": ^7.0.0 - error-ex: ^1.3.1 - json-parse-even-better-errors: ^2.3.0 - lines-and-columns: ^1.1.6 - checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 - languageName: node - linkType: hard - -"parse5@npm:6.0.1": - version: 6.0.1 - resolution: "parse5@npm:6.0.1" - checksum: 7d569a176c5460897f7c8f3377eff640d54132b9be51ae8a8fa4979af940830b2b0c296ce75e5bd8f4041520aadde13170dbdec44889975f906098ea0002f4bd - languageName: node - linkType: hard - -"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 - languageName: node - linkType: hard - -"pascal-case@npm:^3.1.2": - version: 3.1.2 - resolution: "pascal-case@npm:3.1.2" - dependencies: - no-case: ^3.0.4 - tslib: ^2.0.3 - checksum: ba98bfd595fc91ef3d30f4243b1aee2f6ec41c53b4546bfa3039487c367abaa182471dcfc830a1f9e1a0df00c14a370514fa2b3a1aacc68b15a460c31116873e - languageName: node - linkType: hard - -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - -"path-scurry@npm:^1.10.1": - version: 1.10.1 - resolution: "path-scurry@npm:1.10.1" - dependencies: - lru-cache: ^9.1.1 || ^10.0.0 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 - languageName: node - linkType: hard - -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce - languageName: node - linkType: hard - -"path-type@npm:^4.0.0": - version: 4.0.0 - resolution: "path-type@npm:4.0.0" - checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 - languageName: node - linkType: hard - -"performance-now@npm:^2.1.0": - version: 2.1.0 - resolution: "performance-now@npm:2.1.0" - checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550 - languageName: node - linkType: hard - -"picocolors@npm:^0.2.1": - version: 0.2.1 - resolution: "picocolors@npm:0.2.1" - checksum: 3b0f441f0062def0c0f39e87b898ae7461c3a16ffc9f974f320b44c799418cabff17780ee647fda42b856a1dc45897e2c62047e1b546d94d6d5c6962f45427b2 - languageName: node - linkType: hard - -"picocolors@npm:^1.0.0": - version: 1.0.0 - resolution: "picocolors@npm:1.0.0" - checksum: a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 - languageName: node - linkType: hard - -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf - languageName: node - linkType: hard - -"pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba - languageName: node - linkType: hard - -"pirates@npm:^4.0.1, pirates@npm:^4.0.4": - version: 4.0.6 - resolution: "pirates@npm:4.0.6" - checksum: 46a65fefaf19c6f57460388a5af9ab81e3d7fd0e7bc44ca59d753cb5c4d0df97c6c6e583674869762101836d68675f027d60f841c105d72734df9dfca97cbcc6 - languageName: node - linkType: hard - -"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: ^4.0.0 - checksum: 9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 - languageName: node - linkType: hard - -"pkg-up@npm:^3.1.0": - version: 3.1.0 - resolution: "pkg-up@npm:3.1.0" - dependencies: - find-up: ^3.0.0 - checksum: 5bac346b7c7c903613c057ae3ab722f320716199d753f4a7d053d38f2b5955460f3e6ab73b4762c62fd3e947f58e04f1343e92089e7bb6091c90877406fcd8c8 - languageName: node - linkType: hard - -"postcss-attribute-case-insensitive@npm:^5.0.2": - version: 5.0.2 - resolution: "postcss-attribute-case-insensitive@npm:5.0.2" - dependencies: - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: c0b8139f37e68dba372724cba03a53c30716224f0085f98485cada99489beb7c3da9d598ffc1d81519b59d9899291712c9041c250205e6ec0b034bb2c144dcf9 - languageName: node - linkType: hard - -"postcss-browser-comments@npm:^4": - version: 4.0.0 - resolution: "postcss-browser-comments@npm:4.0.0" - peerDependencies: - browserslist: ">=4" - postcss: ">=8" - checksum: 9b8e7094838c2d7bd1ab3ca9cb8d0a78a9a6c8e22f43133ba02db8862fb6c141630e9f590e46f7125cfa4723cacd27b74fa00c05a9907b364dc1f6f17cf13f6f - languageName: node - linkType: hard - -"postcss-calc@npm:^8.2.3": - version: 8.2.4 - resolution: "postcss-calc@npm:8.2.4" - dependencies: - postcss-selector-parser: ^6.0.9 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.2 - checksum: 314b4cebb0c4ed0cf8356b4bce71eca78f5a7842e6a3942a3bba49db168d5296b2bd93c3f735ae1c616f2651d94719ade33becc03c73d2d79c7394fb7f73eabb - languageName: node - linkType: hard - -"postcss-clamp@npm:^4.1.0": - version: 4.1.0 - resolution: "postcss-clamp@npm:4.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.4.6 - checksum: 118eec936b3b035dc8d75c89973408f15c5a3de3d1ee210a2b3511e3e431d9c56e6f354b509a90540241e2225ffe3caaa2fdf25919c63348ce4583a28ada642c - languageName: node - linkType: hard - -"postcss-color-functional-notation@npm:^4.2.4": - version: 4.2.4 - resolution: "postcss-color-functional-notation@npm:4.2.4" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: b763e164fe3577a1de96f75e4bf451585c4f80b8ce60799763a51582cc9402d76faed57324a5d5e5556d90ca7ea0ebde565acb820c95e04bee6f36a91b019831 - languageName: node - linkType: hard - -"postcss-color-hex-alpha@npm:^8.0.4": - version: 8.0.4 - resolution: "postcss-color-hex-alpha@npm:8.0.4" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.4 - checksum: a2f3173a60176cf0aea3b7ebbc799b2cb08229127f0fff708fa31efa14e4ded47ca49aff549d8ed92e74ffe24adee32d5b9d557dbde0524fde5fe389bc520b4e - languageName: node - linkType: hard - -"postcss-color-rebeccapurple@npm:^7.1.1": - version: 7.1.1 - resolution: "postcss-color-rebeccapurple@npm:7.1.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 03482f9b8170da0fa014c41a5d88bce7b987471fb73fc456d397222a2455c89ac7f974dd6ddf40fd31907e768aad158057164b7c5f62cee63a6ecf29d47d7467 - languageName: node - linkType: hard - -"postcss-colormin@npm:^5.3.1": - version: 5.3.1 - resolution: "postcss-colormin@npm:5.3.1" - dependencies: - browserslist: ^4.21.4 - caniuse-api: ^3.0.0 - colord: ^2.9.1 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: e5778baab30877cd1f51e7dc9d2242a162aeca6360a52956acd7f668c5bc235c2ccb7e4df0370a804d65ebe00c5642366f061db53aa823f9ed99972cebd16024 - languageName: node - linkType: hard - -"postcss-convert-values@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-convert-values@npm:5.1.3" - dependencies: - browserslist: ^4.21.4 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: df48cdaffabf9737f9cfdc58a3dc2841cf282506a7a944f6c70236cff295d3a69f63de6e0935eeb8a9d3f504324e5b4e240abc29e21df9e35a02585d3060aeb5 - languageName: node - linkType: hard - -"postcss-custom-media@npm:^8.0.2": - version: 8.0.2 - resolution: "postcss-custom-media@npm:8.0.2" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.3 - checksum: 887bbbacf6f8fab688123796e5dc1e8283b99f21e4c674235bd929dc8018c50df8634ea08932033ec93baaca32670ef2b87e6632863e0b4d84847375dbde9366 - languageName: node - linkType: hard - -"postcss-custom-properties@npm:^12.1.10": - version: 12.1.11 - resolution: "postcss-custom-properties@npm:12.1.11" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 421f9d8d6b9c9066919f39251859232efc4dc5dd406c01e62e08734319a6ccda6d03dd6b46063ba0971053ac6ad3f7abade56d67650b3e370851b2291e8e45e6 - languageName: node - linkType: hard - -"postcss-custom-selectors@npm:^6.0.3": - version: 6.0.3 - resolution: "postcss-custom-selectors@npm:6.0.3" - dependencies: - postcss-selector-parser: ^6.0.4 - peerDependencies: - postcss: ^8.3 - checksum: 18080d60a8a77a76d8ddff185104d65418fffd02bbf9824499f807ced7941509ba63828ab8fe3ec1d6b0d6c72a482bb90a79d79cdef58e5f4b30113cca16e69b - languageName: node - linkType: hard - -"postcss-dir-pseudo-class@npm:^6.0.5": - version: 6.0.5 - resolution: "postcss-dir-pseudo-class@npm:6.0.5" - dependencies: - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: 7810c439d8d1a9072c00f8ab39261a1492873ad170425745bd2819c59767db2f352f906588fc2a7d814e91117900563d7e569ecd640367c7332b26b9829927ef - languageName: node - linkType: hard - -"postcss-discard-comments@npm:^5.1.2": - version: 5.1.2 - resolution: "postcss-discard-comments@npm:5.1.2" - peerDependencies: - postcss: ^8.2.15 - checksum: abfd064ebc27aeaf5037643dd51ffaff74d1fa4db56b0523d073ace4248cbb64ffd9787bd6924b0983a9d0bd0e9bf9f10d73b120e50391dc236e0d26c812fa2a - languageName: node - linkType: hard - -"postcss-discard-duplicates@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-duplicates@npm:5.1.0" - peerDependencies: - postcss: ^8.2.15 - checksum: 88d6964201b1f4ed6bf7a32cefe68e86258bb6e42316ca01d9b32bdb18e7887d02594f89f4a2711d01b51ea6e3fcca8c54be18a59770fe5f4521c61d3eb6ca35 - languageName: node - linkType: hard - -"postcss-discard-empty@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-discard-empty@npm:5.1.1" - peerDependencies: - postcss: ^8.2.15 - checksum: 970adb12fae5c214c0768236ad9a821552626e77dedbf24a8213d19cc2c4a531a757cd3b8cdd3fc22fb1742471b8692a1db5efe436a71236dec12b1318ee8ff4 - languageName: node - linkType: hard - -"postcss-discard-overridden@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-overridden@npm:5.1.0" - peerDependencies: - postcss: ^8.2.15 - checksum: d64d4a545aa2c81b22542895cfcddc787d24119f294d35d29b0599a1c818b3cc51f4ee80b80f5a0a09db282453dd5ac49f104c2117cc09112d0ac9b40b499a41 - languageName: node - linkType: hard - -"postcss-double-position-gradients@npm:^3.1.2": - version: 3.1.2 - resolution: "postcss-double-position-gradients@npm:3.1.2" - dependencies: - "@csstools/postcss-progressive-custom-properties": ^1.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: ca09bf2aefddc180f1c1413f379eef30d492b8147543413f7251216f23f413c394b2ed10b7cd255e87b18e0c8efe36087ea8b9bfb26a09813f9607a0b8e538b6 - languageName: node - linkType: hard - -"postcss-env-function@npm:^4.0.6": - version: 4.0.6 - resolution: "postcss-env-function@npm:4.0.6" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.4 - checksum: 645b2363cfa21be9dcce7fe4a0f172f0af70c00d6a4c1eb3d7ff7e9cfe26d569e291ec2533114d77b12d610023cd168a92d62c38f2fc969fa333b5ae2bff5ffe - languageName: node - linkType: hard - -"postcss-flexbugs-fixes@npm:^5.0.2": - version: 5.0.2 - resolution: "postcss-flexbugs-fixes@npm:5.0.2" - peerDependencies: - postcss: ^8.1.4 - checksum: 022ddbcca8987303b9be75ff259e9de81b98643adac87a5fc6b52a0fcbbf95e1ac9fd508c4ed67cad76ac5d039b7123de8a0832329481b3c626f5d63f7a28f47 - languageName: node - linkType: hard - -"postcss-focus-visible@npm:^6.0.4": - version: 6.0.4 - resolution: "postcss-focus-visible@npm:6.0.4" - dependencies: - postcss-selector-parser: ^6.0.9 - peerDependencies: - postcss: ^8.4 - checksum: acd010b9ddef9b86ffb5fa604c13515ba83e18bc5118dad0a1281150f412aa0ece056c2c5ac56b55e2599f53ab0f740f5ebfdc51e1f5cfe43b8130bac0096fcc - languageName: node - linkType: hard - -"postcss-focus-within@npm:^5.0.4": - version: 5.0.4 - resolution: "postcss-focus-within@npm:5.0.4" - dependencies: - postcss-selector-parser: ^6.0.9 - peerDependencies: - postcss: ^8.4 - checksum: f23d8ab757345a6deaa807d76e10c88caf4b771c38b60e1593b24aee161c503b5823620e89302226a6ae5e7afdb6ac31809241291912e4176eb594a7ddcc9521 - languageName: node - linkType: hard - -"postcss-font-variant@npm:^5.0.0": - version: 5.0.0 - resolution: "postcss-font-variant@npm:5.0.0" - peerDependencies: - postcss: ^8.1.0 - checksum: a19286589261c2bc3e20470486e1ee3b4daf34271c5020167f30856c9b30c26f23264307cb97a184d503814e1b8c5d8a1f9f64a14fd4fd9551c173dca9424695 - languageName: node - linkType: hard - -"postcss-gap-properties@npm:^3.0.5": - version: 3.0.5 - resolution: "postcss-gap-properties@npm:3.0.5" - peerDependencies: - postcss: ^8.2 - checksum: aed559d6d375203a08a006c9ae8cf5ae90d9edaec5cadd20fe65c1b8ce63c2bc8dfe752d4331880a6e24a300541cde61058be790b7bd9b5d04d470c250fbcd39 - languageName: node - linkType: hard - -"postcss-image-set-function@npm:^4.0.7": - version: 4.0.7 - resolution: "postcss-image-set-function@npm:4.0.7" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 7e509330986de14250ead1a557e8da8baaf66ebe8a40354a5dff60ab40d99a483d92aa57d52713251ca1adbf0055ef476c5702b0d0ba5f85a4f407367cdabac0 - languageName: node - linkType: hard - -"postcss-import@npm:^15.1.0": - version: 15.1.0 - resolution: "postcss-import@npm:15.1.0" - dependencies: - postcss-value-parser: ^4.0.0 - read-cache: ^1.0.0 - resolve: ^1.1.7 - peerDependencies: - postcss: ^8.0.0 - checksum: 7bd04bd8f0235429009d0022cbf00faebc885de1d017f6d12ccb1b021265882efc9302006ba700af6cab24c46bfa2f3bc590be3f9aee89d064944f171b04e2a3 - languageName: node - linkType: hard - -"postcss-initial@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-initial@npm:4.0.1" - peerDependencies: - postcss: ^8.0.0 - checksum: 6956953853865de79c39d11533a2860e9f38b770bb284d0010d98a00b9469e22de344e4e5fd8208614d797030487e8918dd2f2c37d9e24d4dd59d565d4fc3e12 - languageName: node - linkType: hard - -"postcss-js@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-js@npm:4.0.1" - dependencies: - camelcase-css: ^2.0.1 - peerDependencies: - postcss: ^8.4.21 - checksum: 5c1e83efeabeb5a42676193f4357aa9c88f4dc1b3c4a0332c132fe88932b33ea58848186db117cf473049fc233a980356f67db490bd0a7832ccba9d0b3fd3491 - languageName: node - linkType: hard - -"postcss-lab-function@npm:^4.2.1": - version: 4.2.1 - resolution: "postcss-lab-function@npm:4.2.1" - dependencies: - "@csstools/postcss-progressive-custom-properties": ^1.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 26ac74b430011271b5581beba69b2cd788f56375fcb64c90f6ec1577379af85f6022dc38c410ff471dac520c7ddc289160a6a16cca3c7ff76f5af7e90d31eaa3 - languageName: node - linkType: hard - -"postcss-load-config@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-load-config@npm:4.0.1" - dependencies: - lilconfig: ^2.0.5 - yaml: ^2.1.1 - peerDependencies: - postcss: ">=8.0.9" - ts-node: ">=9.0.0" - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - checksum: b61f890499ed7dcda1e36c20a9582b17d745bad5e2b2c7bc96942465e406bc43ae03f270c08e60d1e29dab1ee50cb26970b5eb20c9aae30e066e20bd607ae4e4 - languageName: node - linkType: hard - -"postcss-loader@npm:^6.2.1": - version: 6.2.1 - resolution: "postcss-loader@npm:6.2.1" - dependencies: - cosmiconfig: ^7.0.0 - klona: ^2.0.5 - semver: ^7.3.5 - peerDependencies: - postcss: ^7.0.0 || ^8.0.1 - webpack: ^5.0.0 - checksum: e40ae79c3e39df37014677a817b001bd115d8b10dedf53a07b97513d93b1533cd702d7a48831bdd77b9a9484b1ec84a5d4a723f80e83fb28682c75b5e65e8a90 - languageName: node - linkType: hard - -"postcss-logical@npm:^5.0.4": - version: 5.0.4 - resolution: "postcss-logical@npm:5.0.4" - peerDependencies: - postcss: ^8.4 - checksum: 17c71291ed6a03883a5aa54b9923b874c32710707d041a0f0752e6febdb09dee5d2abf4ef271978d932e4a4c948f349bb23edf633c03e3427ba15e71bfc66ac7 - languageName: node - linkType: hard - -"postcss-media-minmax@npm:^5.0.0": - version: 5.0.0 - resolution: "postcss-media-minmax@npm:5.0.0" - peerDependencies: - postcss: ^8.1.0 - checksum: 2cd7283e07a1ac1acdcc3ecbaa0e9932f8d1e7647e7aeb14d91845fcb890d60d7257ec70c825cae8d48ae80a08cc77ebc4021a0dfa32360e0cd991e2bc021607 - languageName: node - linkType: hard - -"postcss-merge-longhand@npm:^5.1.7": - version: 5.1.7 - resolution: "postcss-merge-longhand@npm:5.1.7" - dependencies: - postcss-value-parser: ^4.2.0 - stylehacks: ^5.1.1 - peerDependencies: - postcss: ^8.2.15 - checksum: 81c3fc809f001b9b71a940148e242bdd6e2d77713d1bfffa15eb25c1f06f6648d5e57cb21645746d020a2a55ff31e1740d2b27900442913a9d53d8a01fb37e1b - languageName: node - linkType: hard - -"postcss-merge-rules@npm:^5.1.4": - version: 5.1.4 - resolution: "postcss-merge-rules@npm:5.1.4" - dependencies: - browserslist: ^4.21.4 - caniuse-api: ^3.0.0 - cssnano-utils: ^3.1.0 - postcss-selector-parser: ^6.0.5 - peerDependencies: - postcss: ^8.2.15 - checksum: 8ab6a569babe6cb412d6612adee74f053cea7edb91fa013398515ab36754b1fec830d68782ed8cdfb44cffdc6b78c79eab157bff650f428aa4460d3f3857447e - languageName: node - linkType: hard - -"postcss-minify-font-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-minify-font-values@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 35e858fa41efa05acdeb28f1c76579c409fdc7eabb1744c3bd76e895bb9fea341a016746362a67609688ab2471f587202b9a3e14ea28ad677754d663a2777ece - languageName: node - linkType: hard - -"postcss-minify-gradients@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-minify-gradients@npm:5.1.1" - dependencies: - colord: ^2.9.1 - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 27354072a07c5e6dab36731103b94ca2354d4ed3c5bc6aacfdf2ede5a55fa324679d8fee5450800bc50888dbb5e9ed67569c0012040c2be128143d0cebb36d67 - languageName: node - linkType: hard - -"postcss-minify-params@npm:^5.1.4": - version: 5.1.4 - resolution: "postcss-minify-params@npm:5.1.4" - dependencies: - browserslist: ^4.21.4 - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: bd63e2cc89edcf357bb5c2a16035f6d02ef676b8cede4213b2bddd42626b3d428403849188f95576fc9f03e43ebd73a29bf61d33a581be9a510b13b7f7f100d5 - languageName: node - linkType: hard - -"postcss-minify-selectors@npm:^5.2.1": - version: 5.2.1 - resolution: "postcss-minify-selectors@npm:5.2.1" - dependencies: - postcss-selector-parser: ^6.0.5 - peerDependencies: - postcss: ^8.2.15 - checksum: 6fdbc84f99a60d56b43df8930707da397775e4c36062a106aea2fd2ac81b5e24e584a1892f4baa4469fa495cb87d1422560eaa8f6c9d500f9f0b691a5f95bab5 - languageName: node - linkType: hard - -"postcss-modules-extract-imports@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-extract-imports@npm:3.0.0" - peerDependencies: - postcss: ^8.1.0 - checksum: 4b65f2f1382d89c4bc3c0a1bdc5942f52f3cb19c110c57bd591ffab3a5fee03fcf831604168205b0c1b631a3dce2255c70b61aaae3ef39d69cd7eb450c2552d2 - languageName: node - linkType: hard - -"postcss-modules-local-by-default@npm:^4.0.3": - version: 4.0.3 - resolution: "postcss-modules-local-by-default@npm:4.0.3" - dependencies: - icss-utils: ^5.0.0 - postcss-selector-parser: ^6.0.2 - postcss-value-parser: ^4.1.0 - peerDependencies: - postcss: ^8.1.0 - checksum: 2f8083687f3d6067885f8863dd32dbbb4f779cfcc7e52c17abede9311d84faf6d3ed8760e7c54c6380281732ae1f78e5e56a28baf3c271b33f450a11c9e30485 - languageName: node - linkType: hard - -"postcss-modules-scope@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-scope@npm:3.0.0" - dependencies: - postcss-selector-parser: ^6.0.4 - peerDependencies: - postcss: ^8.1.0 - checksum: 330b9398dbd44c992c92b0dc612c0626135e2cc840fee41841eb61247a6cfed95af2bd6f67ead9dd9d0bb41f5b0367129d93c6e434fa3e9c58ade391d9a5a138 - languageName: node - linkType: hard - -"postcss-modules-values@npm:^4.0.0": - version: 4.0.0 - resolution: "postcss-modules-values@npm:4.0.0" - dependencies: - icss-utils: ^5.0.0 - peerDependencies: - postcss: ^8.1.0 - checksum: f7f2cdf14a575b60e919ad5ea52fed48da46fe80db2733318d71d523fc87db66c835814940d7d05b5746b0426e44661c707f09bdb83592c16aea06e859409db6 - languageName: node - linkType: hard - -"postcss-nested@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-nested@npm:6.0.1" - dependencies: - postcss-selector-parser: ^6.0.11 - peerDependencies: - postcss: ^8.2.14 - checksum: 7ddb0364cd797de01e38f644879189e0caeb7ea3f78628c933d91cc24f327c56d31269384454fc02ecaf503b44bfa8e08870a7c4cc56b23bc15640e1894523fa - languageName: node - linkType: hard - -"postcss-nesting@npm:^10.2.0": - version: 10.2.0 - resolution: "postcss-nesting@npm:10.2.0" - dependencies: - "@csstools/selector-specificity": ^2.0.0 - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: 25e6e66186bd7f18bc4628cf0f43e02189268f28a449aa4a63b33b8f2c33745af99acfcd4ce2ac69319dc850e83b28dbaabcf517e3977dfe20e37fed0e032c7d - languageName: node - linkType: hard - -"postcss-normalize-charset@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-charset@npm:5.1.0" - peerDependencies: - postcss: ^8.2.15 - checksum: e79d92971fc05b8b3c9b72f3535a574e077d13c69bef68156a0965f397fdf157de670da72b797f57b0e3bac8f38155b5dd1735ecab143b9cc4032d72138193b4 - languageName: node - linkType: hard - -"postcss-normalize-display-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-display-values@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: b6eb7b9b02c3bdd62bbc54e01e2b59733d73a1c156905d238e178762962efe0c6f5104544da39f32cade8a4fb40f10ff54b63a8ebfbdff51e8780afb9fbdcf86 - languageName: node - linkType: hard - -"postcss-normalize-positions@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-positions@npm:5.1.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: d9afc233729c496463c7b1cdd06732469f401deb387484c3a2422125b46ec10b4af794c101f8c023af56f01970b72b535e88373b9058ecccbbf88db81662b3c4 - languageName: node - linkType: hard - -"postcss-normalize-repeat-style@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-repeat-style@npm:5.1.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 2c6ad2b0ae10a1fda156b948c34f78c8f1e185513593de4d7e2480973586675520edfec427645fa168c337b0a6b3ceca26f92b96149741ca98a9806dad30d534 - languageName: node - linkType: hard - -"postcss-normalize-string@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-string@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 6e549c6e5b2831e34c7bdd46d8419e2278f6af1d5eef6d26884a37c162844e60339340c57e5e06058cdbe32f27fc6258eef233e811ed2f71168ef2229c236ada - languageName: node - linkType: hard - -"postcss-normalize-timing-functions@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-timing-functions@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: da550f50e90b0b23e17b67449a7d1efd1aa68288e66d4aa7614ca6f5cc012896be1972b7168eee673d27da36504faccf7b9f835c0f7e81243f966a42c8c030aa - languageName: node - linkType: hard - -"postcss-normalize-unicode@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-unicode@npm:5.1.1" - dependencies: - browserslist: ^4.21.4 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 4c24d26cc9f4b19a9397db4e71dd600dab690f1de8e14a3809e2aa1452dbc3791c208c38a6316bbc142f29e934fdf02858e68c94038c06174d78a4937e0f273c - languageName: node - linkType: hard - -"postcss-normalize-url@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-url@npm:5.1.0" - dependencies: - normalize-url: ^6.0.1 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 3bd4b3246d6600230bc827d1760b24cb3101827ec97570e3016cbe04dc0dd28f4dbe763245d1b9d476e182c843008fbea80823061f1d2219b96f0d5c724a24c0 - languageName: node - linkType: hard - -"postcss-normalize-whitespace@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-whitespace@npm:5.1.1" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 12d8fb6d1c1cba208cc08c1830959b7d7ad447c3f5581873f7e185f99a9a4230c43d3af21ca12c818e4690a5085a95b01635b762ad4a7bef69d642609b4c0e19 - languageName: node - linkType: hard - -"postcss-normalize@npm:^10.0.1": - version: 10.0.1 - resolution: "postcss-normalize@npm:10.0.1" - dependencies: - "@csstools/normalize.css": "*" - postcss-browser-comments: ^4 - sanitize.css: "*" - peerDependencies: - browserslist: ">= 4" - postcss: ">= 8" - checksum: af67ade84e5d65de0cf84cde479840da96ffb2037fe6bf86737788216f67e414622e718e7d84182885ad65fa948150e4a0c3e454ca63e619dd5c7b4eb4224c39 - languageName: node - linkType: hard - -"postcss-opacity-percentage@npm:^1.1.2": - version: 1.1.3 - resolution: "postcss-opacity-percentage@npm:1.1.3" - peerDependencies: - postcss: ^8.2 - checksum: 54d1b8ca68035bc1a5788aaabdbc3b66ffee34b5a2412cecf073627dad7e3f2bae07c01fac3bc7f46bbac5da3291ac9ddcf74bfee26dfd86f9f96c847a0afc13 - languageName: node - linkType: hard - -"postcss-ordered-values@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-ordered-values@npm:5.1.3" - dependencies: - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 6f3ca85b6ceffc68aadaf319d9ee4c5ac16d93195bf8cba2d1559b631555ad61941461cda6d3909faab86e52389846b2b36345cff8f0c3f4eb345b1b8efadcf9 - languageName: node - linkType: hard - -"postcss-overflow-shorthand@npm:^3.0.4": - version: 3.0.4 - resolution: "postcss-overflow-shorthand@npm:3.0.4" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 74009022491e3901263f8f5811630393480323e51f5d23ef17f3fdc7e03bf9c2502a632f3ba8fe6a468b57590f13b2fa3b17a68ef19653589e76277607696743 - languageName: node - linkType: hard - -"postcss-page-break@npm:^3.0.4": - version: 3.0.4 - resolution: "postcss-page-break@npm:3.0.4" - peerDependencies: - postcss: ^8 - checksum: a7d08c945fc691f62c77ac701e64722218b14ec5c8fc1972b8af9c21553492d40808cf95e61b9697b1dacaf7e6180636876d7fee314f079e6c9e39ac1b1edc6f - languageName: node - linkType: hard - -"postcss-place@npm:^7.0.5": - version: 7.0.5 - resolution: "postcss-place@npm:7.0.5" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 903fec0c313bb7ec20f2c8f0a125866fb7804aa3186b5b2c7c2d58cb9039ff301461677a060e9db643d1aaffaf80a0ff71e900a6da16705dad6b49c804cb3c73 - languageName: node - linkType: hard - -"postcss-preset-env@npm:^7.0.1": - version: 7.8.3 - resolution: "postcss-preset-env@npm:7.8.3" - dependencies: - "@csstools/postcss-cascade-layers": ^1.1.1 - "@csstools/postcss-color-function": ^1.1.1 - "@csstools/postcss-font-format-keywords": ^1.0.1 - "@csstools/postcss-hwb-function": ^1.0.2 - "@csstools/postcss-ic-unit": ^1.0.1 - "@csstools/postcss-is-pseudo-class": ^2.0.7 - "@csstools/postcss-nested-calc": ^1.0.0 - "@csstools/postcss-normalize-display-values": ^1.0.1 - "@csstools/postcss-oklab-function": ^1.1.1 - "@csstools/postcss-progressive-custom-properties": ^1.3.0 - "@csstools/postcss-stepped-value-functions": ^1.0.1 - "@csstools/postcss-text-decoration-shorthand": ^1.0.0 - "@csstools/postcss-trigonometric-functions": ^1.0.2 - "@csstools/postcss-unset-value": ^1.0.2 - autoprefixer: ^10.4.13 - browserslist: ^4.21.4 - css-blank-pseudo: ^3.0.3 - css-has-pseudo: ^3.0.4 - css-prefers-color-scheme: ^6.0.3 - cssdb: ^7.1.0 - postcss-attribute-case-insensitive: ^5.0.2 - postcss-clamp: ^4.1.0 - postcss-color-functional-notation: ^4.2.4 - postcss-color-hex-alpha: ^8.0.4 - postcss-color-rebeccapurple: ^7.1.1 - postcss-custom-media: ^8.0.2 - postcss-custom-properties: ^12.1.10 - postcss-custom-selectors: ^6.0.3 - postcss-dir-pseudo-class: ^6.0.5 - postcss-double-position-gradients: ^3.1.2 - postcss-env-function: ^4.0.6 - postcss-focus-visible: ^6.0.4 - postcss-focus-within: ^5.0.4 - postcss-font-variant: ^5.0.0 - postcss-gap-properties: ^3.0.5 - postcss-image-set-function: ^4.0.7 - postcss-initial: ^4.0.1 - postcss-lab-function: ^4.2.1 - postcss-logical: ^5.0.4 - postcss-media-minmax: ^5.0.0 - postcss-nesting: ^10.2.0 - postcss-opacity-percentage: ^1.1.2 - postcss-overflow-shorthand: ^3.0.4 - postcss-page-break: ^3.0.4 - postcss-place: ^7.0.5 - postcss-pseudo-class-any-link: ^7.1.6 - postcss-replace-overflow-wrap: ^4.0.0 - postcss-selector-not: ^6.0.1 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2 - checksum: 71bfb697ffc55e27895b2bf3a579dd9b4c1321872816091935e33d6f659cab60795a03bb022dc8a4cab48fd5680a419fe9ae5d61a3a3d8c785ec9308f323e787 - languageName: node - linkType: hard - -"postcss-pseudo-class-any-link@npm:^7.1.6": - version: 7.1.6 - resolution: "postcss-pseudo-class-any-link@npm:7.1.6" - dependencies: - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: 43aa18ea1ef1b168f61310856dd92f46ceb3dc60b6cf820e079ca1a849df5cc0f12a1511bdc1811a23f03d60ddcc959200c80c3f9a7b57feebe32bab226afb39 - languageName: node - linkType: hard - -"postcss-reduce-initial@npm:^5.1.2": - version: 5.1.2 - resolution: "postcss-reduce-initial@npm:5.1.2" - dependencies: - browserslist: ^4.21.4 - caniuse-api: ^3.0.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 55db697f85231a81f1969d54c894e4773912d9ddb914f9b03d2e73abc4030f2e3bef4d7465756d0c1acfcc2c2d69974bfb50a972ab27546a7d68b5a4fc90282b - languageName: node - linkType: hard - -"postcss-reduce-transforms@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-reduce-transforms@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 0c6af2cba20e3ff63eb9ad045e634ddfb9c3e5c0e614c020db2a02f3aa20632318c4ede9e0c995f9225d9a101e673de91c0a6e10bb2fa5da6d6c75d15a55882f - languageName: node - linkType: hard - -"postcss-replace-overflow-wrap@npm:^4.0.0": - version: 4.0.0 - resolution: "postcss-replace-overflow-wrap@npm:4.0.0" - peerDependencies: - postcss: ^8.0.3 - checksum: 3ffe20b300a4c377a11c588b142740d8557e03c707474c45234c934190ac374750ddc92c7906c373471d273a20504a429c2062c21fdcaff830fb28e0a81ac1dc - languageName: node - linkType: hard - -"postcss-selector-not@npm:^6.0.1": - version: 6.0.1 - resolution: "postcss-selector-not@npm:6.0.1" - dependencies: - postcss-selector-parser: ^6.0.10 - peerDependencies: - postcss: ^8.2 - checksum: fe523a0219e4bd34f04498534bb9e8aec3193f3585eafe4c388d086955b41201cae71fd20980ca465acade7f182029b43dbd5ca7e9d50bf34bbcaf1d19fe3ee6 - languageName: node - linkType: hard - -"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": - version: 6.0.13 - resolution: "postcss-selector-parser@npm:6.0.13" - dependencies: - cssesc: ^3.0.0 - util-deprecate: ^1.0.2 - checksum: f89163338a1ce3b8ece8e9055cd5a3165e79a15e1c408e18de5ad8f87796b61ec2d48a2902d179ae0c4b5de10fccd3a325a4e660596549b040bc5ad1b465f096 - languageName: node - linkType: hard - -"postcss-svgo@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-svgo@npm:5.1.0" - dependencies: - postcss-value-parser: ^4.2.0 - svgo: ^2.7.0 - peerDependencies: - postcss: ^8.2.15 - checksum: d86eb5213d9f700cf5efe3073799b485fb7cacae0c731db3d7749c9c2b1c9bc85e95e0baeca439d699ff32ea24815fc916c4071b08f67ed8219df229ce1129bd - languageName: node - linkType: hard - -"postcss-unique-selectors@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-unique-selectors@npm:5.1.1" - dependencies: - postcss-selector-parser: ^6.0.5 - peerDependencies: - postcss: ^8.2.15 - checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 - languageName: node - linkType: hard - -"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": - version: 4.2.0 - resolution: "postcss-value-parser@npm:4.2.0" - checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f - languageName: node - linkType: hard - -"postcss@npm:^7.0.35": - version: 7.0.39 - resolution: "postcss@npm:7.0.39" - dependencies: - picocolors: ^0.2.1 - source-map: ^0.6.1 - checksum: 4ac793f506c23259189064bdc921260d869a115a82b5e713973c5af8e94fbb5721a5cc3e1e26840500d7e1f1fa42a209747c5b1a151918a9bc11f0d7ed9048e3 - languageName: node - linkType: hard - -"postcss@npm:^8.3.5, postcss@npm:^8.4.21, postcss@npm:^8.4.23, postcss@npm:^8.4.4": - version: 8.4.30 - resolution: "postcss@npm:8.4.30" - dependencies: - nanoid: ^3.3.6 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 6c810c10c9bd3e03ca016e0b6b6756261e640aba1a9a7b1200b55502bc34b9165e38f590aef3493afc2f30ab55cdfcd43fd0f8408d69a77318ddbcf2a8ad164b - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a - languageName: node - linkType: hard - -"prelude-ls@npm:~1.1.2": - version: 1.1.2 - resolution: "prelude-ls@npm:1.1.2" - checksum: c4867c87488e4a0c233e158e4d0d5565b609b105d75e4c05dc760840475f06b731332eb93cc8c9cecb840aa8ec323ca3c9a56ad7820ad2e63f0261dadcb154e4 - languageName: node - linkType: hard - -"pretty-bytes@npm:^5.3.0, pretty-bytes@npm:^5.4.1": - version: 5.6.0 - resolution: "pretty-bytes@npm:5.6.0" - checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd - languageName: node - linkType: hard - -"pretty-error@npm:^4.0.0": - version: 4.0.0 - resolution: "pretty-error@npm:4.0.0" - dependencies: - lodash: ^4.17.20 - renderkid: ^3.0.0 - checksum: a5b9137365690104ded6947dca2e33360bf55e62a4acd91b1b0d7baa3970e43754c628cc9e16eafbdd4e8f8bcb260a5865475d4fc17c3106ff2d61db4e72cdf3 - languageName: node - linkType: hard - -"pretty-format@npm:^27.0.2, pretty-format@npm:^27.5.1": - version: 27.5.1 - resolution: "pretty-format@npm:27.5.1" - dependencies: - ansi-regex: ^5.0.1 - ansi-styles: ^5.0.0 - react-is: ^17.0.1 - checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088 - languageName: node - linkType: hard - -"pretty-format@npm:^28.1.3": - version: 28.1.3 - resolution: "pretty-format@npm:28.1.3" - dependencies: - "@jest/schemas": ^28.1.3 - ansi-regex: ^5.0.1 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: e69f857358a3e03d271252d7524bec758c35e44680287f36c1cb905187fbc82da9981a6eb07edfd8a03bc3cbeebfa6f5234c13a3d5b59f2bbdf9b4c4053e0a7f - languageName: node - linkType: hard - -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": - version: 29.7.0 - resolution: "pretty-format@npm:29.7.0" - dependencies: - "@jest/schemas": ^29.6.3 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: 032c1602383e71e9c0c02a01bbd25d6759d60e9c7cf21937dde8357aa753da348fcec5def5d1002c9678a8524d5fe099ad98861286550ef44de8808cc61e43b6 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: ^2.0.2 - retry: ^0.12.0 - checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 - languageName: node - linkType: hard - -"promise@npm:^8.1.0": - version: 8.3.0 - resolution: "promise@npm:8.3.0" - dependencies: - asap: ~2.0.6 - checksum: a69f0ddbddf78ffc529cffee7ad950d307347615970564b17988ce43fbe767af5c738a9439660b24a9a8cbea106c0dcbb6c2b20e23b7e96a8e89e5c2679e94d5 - languageName: node - linkType: hard - -"prompts@npm:^2.0.1, prompts@npm:^2.4.2": - version: 2.4.2 - resolution: "prompts@npm:2.4.2" - dependencies: - kleur: ^3.0.3 - sisteransi: ^1.0.5 - checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d - languageName: node - linkType: hard - -"prop-types@npm:^15.8.1": - version: 15.8.1 - resolution: "prop-types@npm:15.8.1" - dependencies: - loose-envify: ^1.4.0 - object-assign: ^4.1.1 - react-is: ^16.13.1 - checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459 - languageName: node - linkType: hard - -"proxy-addr@npm:~2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 - languageName: node - linkType: hard - -"psl@npm:^1.1.33": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d - languageName: node - linkType: hard - -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 - languageName: node - linkType: hard - -"q@npm:^1.1.2": - version: 1.5.1 - resolution: "q@npm:1.5.1" - checksum: 147baa93c805bc1200ed698bdf9c72e9e42c05f96d007e33a558b5fdfd63e5ea130e99313f28efc1783e90e6bdb4e48b67a36fcc026b7b09202437ae88a1fb12 - languageName: node - linkType: hard - -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" - dependencies: - side-channel: ^1.0.4 - checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 - languageName: node - linkType: hard - -"querystringify@npm:^2.1.1": - version: 2.2.0 - resolution: "querystringify@npm:2.2.0" - checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 - languageName: node - linkType: hard - -"raf@npm:^3.4.1": - version: 3.4.1 - resolution: "raf@npm:3.4.1" - dependencies: - performance-now: ^2.1.0 - checksum: 50ba284e481c8185dbcf45fc4618ba3aec580bb50c9121385d5698cb6012fe516d2015b1df6dd407a7b7c58d44be8086108236affbce1861edd6b44637c8cd52 - languageName: node - linkType: hard - -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: ^5.1.0 - checksum: d779499376bd4cbb435ef3ab9a957006c8682f343f14089ed5f27764e4645114196e75b7f6abf1cbd84fd247c0cb0651698444df8c9bf30e62120fbbc52269d6 - languageName: node - linkType: hard - -"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 - languageName: node - linkType: hard - -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e - languageName: node - linkType: hard - -"react-app-polyfill@npm:^3.0.0": - version: 3.0.0 - resolution: "react-app-polyfill@npm:3.0.0" - dependencies: - core-js: ^3.19.2 - object-assign: ^4.1.1 - promise: ^8.1.0 - raf: ^3.4.1 - regenerator-runtime: ^0.13.9 - whatwg-fetch: ^3.6.2 - checksum: 1bb031080af15397d6eb9c69a0c2e93799991f7197a086e4409ba719398f1256b542a3d6c9a34673d516c684eef3e8226c99b335982593851f58f65f6e43571b - languageName: node - linkType: hard - -"react-cookie@npm:^5.0.0": - version: 5.0.0 - resolution: "react-cookie@npm:5.0.0" - dependencies: - "@types/hoist-non-react-statics": ^3.3.1 - hoist-non-react-statics: ^3.3.2 - universal-cookie: ^4.0.0 - peerDependencies: - react: ">= 16.3.0" - checksum: b3dc3eabe61e1989b9a245c89c068527d42ae2f9779749bb7af932ae7c347ae8492bc42aee9739c4acd1759a44847bcd104cec6cbfca7c74bdd18f1093e5b45b - languageName: node - linkType: hard - -"react-dev-utils@npm:^12.0.1": - version: 12.0.1 - resolution: "react-dev-utils@npm:12.0.1" - dependencies: - "@babel/code-frame": ^7.16.0 - address: ^1.1.2 - browserslist: ^4.18.1 - chalk: ^4.1.2 - cross-spawn: ^7.0.3 - detect-port-alt: ^1.1.6 - escape-string-regexp: ^4.0.0 - filesize: ^8.0.6 - find-up: ^5.0.0 - fork-ts-checker-webpack-plugin: ^6.5.0 - global-modules: ^2.0.0 - globby: ^11.0.4 - gzip-size: ^6.0.0 - immer: ^9.0.7 - is-root: ^2.1.0 - loader-utils: ^3.2.0 - open: ^8.4.0 - pkg-up: ^3.1.0 - prompts: ^2.4.2 - react-error-overlay: ^6.0.11 - recursive-readdir: ^2.2.2 - shell-quote: ^1.7.3 - strip-ansi: ^6.0.1 - text-table: ^0.2.0 - checksum: 2c6917e47f03d9595044770b0f883a61c6b660fcaa97b8ba459a1d57c9cca9aa374cd51296b22d461ff5e432105dbe6f04732dab128e52729c79239e1c23ab56 - languageName: node - linkType: hard - -"react-dom@npm:^18.2.0": - version: 18.2.0 - resolution: "react-dom@npm:18.2.0" - dependencies: - loose-envify: ^1.1.0 - scheduler: ^0.23.0 - peerDependencies: - react: ^18.2.0 - checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc - languageName: node - linkType: hard - -"react-error-overlay@npm:^6.0.11": - version: 6.0.11 - resolution: "react-error-overlay@npm:6.0.11" - checksum: ce7b44c38fadba9cedd7c095cf39192e632daeccf1d0747292ed524f17dcb056d16bc197ddee5723f9dd888f0b9b19c3b486c430319e30504289b9296f2d2c42 - languageName: node - linkType: hard - -"react-is@npm:^16.13.1, react-is@npm:^16.7.0": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f - languageName: node - linkType: hard - -"react-is@npm:^17.0.1": - version: 17.0.2 - resolution: "react-is@npm:17.0.2" - checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8 - languageName: node - linkType: hard - -"react-is@npm:^18.0.0": - version: 18.2.0 - resolution: "react-is@npm:18.2.0" - checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e - languageName: node - linkType: hard - -"react-refresh@npm:^0.11.0": - version: 0.11.0 - resolution: "react-refresh@npm:0.11.0" - checksum: 112178a05b1e0ffeaf5d9fb4e56b4410a34a73adeb04dbf13abdc50d9ac9df2ada83e81485156cca0b3fa296aa3612751b3d6cd13be4464642a43679b819cbc7 - languageName: node - linkType: hard - -"react-router-dom@npm:^6.15.0": - version: 6.16.0 - resolution: "react-router-dom@npm:6.16.0" - dependencies: - "@remix-run/router": 1.9.0 - react-router: 6.16.0 - peerDependencies: - react: ">=16.8" - react-dom: ">=16.8" - checksum: 18b398924bb0f0d97cf2f71dab71d860b960a7a267b2f77388990c662bb6d8738bdc3042d92f713fd63d269ae9ad90df39c8e97661b6ba758bbb7386b9f20ae0 - languageName: node - linkType: hard - -"react-router@npm:6.16.0": - version: 6.16.0 - resolution: "react-router@npm:6.16.0" - dependencies: - "@remix-run/router": 1.9.0 - peerDependencies: - react: ">=16.8" - checksum: b31c187e3fdcdf7294ffdad6ff834e14d012840c94d8ee8c7fbe451062a8fcb6e31e8bc7827fb1ff45445dd40fad2b8c96a7e98f0ac1c3eb1d716c257a0821c9 - languageName: node - linkType: hard - -"react-scripts@npm:5.0.1": - version: 5.0.1 - resolution: "react-scripts@npm:5.0.1" - dependencies: - "@babel/core": ^7.16.0 - "@pmmmwh/react-refresh-webpack-plugin": ^0.5.3 - "@svgr/webpack": ^5.5.0 - babel-jest: ^27.4.2 - babel-loader: ^8.2.3 - babel-plugin-named-asset-import: ^0.3.8 - babel-preset-react-app: ^10.0.1 - bfj: ^7.0.2 - browserslist: ^4.18.1 - camelcase: ^6.2.1 - case-sensitive-paths-webpack-plugin: ^2.4.0 - css-loader: ^6.5.1 - css-minimizer-webpack-plugin: ^3.2.0 - dotenv: ^10.0.0 - dotenv-expand: ^5.1.0 - eslint: ^8.3.0 - eslint-config-react-app: ^7.0.1 - eslint-webpack-plugin: ^3.1.1 - file-loader: ^6.2.0 - fs-extra: ^10.0.0 - fsevents: ^2.3.2 - html-webpack-plugin: ^5.5.0 - identity-obj-proxy: ^3.0.0 - jest: ^27.4.3 - jest-resolve: ^27.4.2 - jest-watch-typeahead: ^1.0.0 - mini-css-extract-plugin: ^2.4.5 - postcss: ^8.4.4 - postcss-flexbugs-fixes: ^5.0.2 - postcss-loader: ^6.2.1 - postcss-normalize: ^10.0.1 - postcss-preset-env: ^7.0.1 - prompts: ^2.4.2 - react-app-polyfill: ^3.0.0 - react-dev-utils: ^12.0.1 - react-refresh: ^0.11.0 - resolve: ^1.20.0 - resolve-url-loader: ^4.0.0 - sass-loader: ^12.3.0 - semver: ^7.3.5 - source-map-loader: ^3.0.0 - style-loader: ^3.3.1 - tailwindcss: ^3.0.2 - terser-webpack-plugin: ^5.2.5 - webpack: ^5.64.4 - webpack-dev-server: ^4.6.0 - webpack-manifest-plugin: ^4.0.2 - workbox-webpack-plugin: ^6.4.1 - peerDependencies: - react: ">= 16" - typescript: ^3.2.1 || ^4 - dependenciesMeta: - fsevents: - optional: true - peerDependenciesMeta: - typescript: - optional: true - bin: - react-scripts: bin/react-scripts.js - checksum: 92afa2f245c7092ccc97d5609dc7a2130616262e34da7f15072d9442e2d2e1d4909a91022abd1faac1336eb17c5525a10d9bd43e1ae374c7ec941ca20addca68 - languageName: node - linkType: hard - -"react@npm:^18.2.0": - version: 18.2.0 - resolution: "react@npm:18.2.0" - dependencies: - loose-envify: ^1.1.0 - checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b - languageName: node - linkType: hard - -"read-cache@npm:^1.0.0": - version: 1.0.0 - resolution: "read-cache@npm:1.0.0" - dependencies: - pify: ^2.3.0 - checksum: cffc728b9ede1e0667399903f9ecaf3789888b041c46ca53382fa3a06303e5132774dc0a96d0c16aa702dbac1ea0833d5a868d414f5ab2af1e1438e19e6657c6 - languageName: node - linkType: hard - -"readable-stream@npm:^2.0.1": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: ~1.0.0 - inherits: ~2.0.3 - isarray: ~1.0.0 - process-nextick-args: ~2.0.0 - safe-buffer: ~5.1.1 - string_decoder: ~1.1.1 - util-deprecate: ~1.0.1 - checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 - languageName: node - linkType: hard - -"readable-stream@npm:^3.0.6, readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: ^2.0.3 - string_decoder: ^1.1.1 - util-deprecate: ^1.0.1 - checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d - languageName: node - linkType: hard - -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: ^2.2.1 - checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 - languageName: node - linkType: hard - -"recursive-readdir@npm:^2.2.2": - version: 2.2.3 - resolution: "recursive-readdir@npm:2.2.3" - dependencies: - minimatch: ^3.0.5 - checksum: 88ec96e276237290607edc0872b4f9842837b95cfde0cdbb1e00ba9623dfdf3514d44cdd14496ab60a0c2dd180a6ef8a3f1c34599e6cf2273afac9b72a6fb2b5 - languageName: node - linkType: hard - -"redent@npm:^3.0.0": - version: 3.0.0 - resolution: "redent@npm:3.0.0" - dependencies: - indent-string: ^4.0.0 - strip-indent: ^3.0.0 - checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b - languageName: node - linkType: hard - -"reflect.getprototypeof@npm:^1.0.4": - version: 1.0.4 - resolution: "reflect.getprototypeof@npm:1.0.4" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - get-intrinsic: ^1.2.1 - globalthis: ^1.0.3 - which-builtin-type: ^1.1.3 - checksum: 16e2361988dbdd23274b53fb2b1b9cefeab876c3941a2543b4cadac6f989e3db3957b07a44aac46cfceb3e06e2871785ec2aac992d824f76292f3b5ee87f66f2 - languageName: node - linkType: hard - -"regenerate-unicode-properties@npm:^10.1.0": - version: 10.1.1 - resolution: "regenerate-unicode-properties@npm:10.1.1" - dependencies: - regenerate: ^1.4.2 - checksum: b80958ef40f125275824c2c47d5081dfaefebd80bff26c76761e9236767c748a4a95a69c053fe29d2df881177f2ca85df4a71fe70a82360388b31159ef19adcf - languageName: node - linkType: hard - -"regenerate@npm:^1.4.2": - version: 1.4.2 - resolution: "regenerate@npm:1.4.2" - checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.13.9": - version: 0.13.11 - resolution: "regenerator-runtime@npm:0.13.11" - checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.14.0": - version: 0.14.0 - resolution: "regenerator-runtime@npm:0.14.0" - checksum: 1c977ad82a82a4412e4f639d65d22be376d3ebdd30da2c003eeafdaaacd03fc00c2320f18120007ee700900979284fc78a9f00da7fb593f6e6eeebc673fba9a3 - languageName: node - linkType: hard - -"regenerator-transform@npm:^0.15.2": - version: 0.15.2 - resolution: "regenerator-transform@npm:0.15.2" - dependencies: - "@babel/runtime": ^7.8.4 - checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 - languageName: node - linkType: hard - -"regex-parser@npm:^2.2.11": - version: 2.2.11 - resolution: "regex-parser@npm:2.2.11" - checksum: 78200331ec0cc372302d287a4946c38681eb5fe435453fca572cb53cac0ba579e5eb3b9e25eac24c0c80a555fb3ea7a637814a35da1e9bc88e8819110ae5de24 - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.0, regexp.prototype.flags@npm:^1.5.1": - version: 1.5.1 - resolution: "regexp.prototype.flags@npm:1.5.1" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - set-function-name: ^2.0.0 - checksum: 869edff00288442f8d7fa4c9327f91d85f3b3acf8cbbef9ea7a220345cf23e9241b6def9263d2c1ebcf3a316b0aa52ad26a43a84aa02baca3381717b3e307f47 - languageName: node - linkType: hard - -"regexpu-core@npm:^5.3.1": - version: 5.3.2 - resolution: "regexpu-core@npm:5.3.2" - dependencies: - "@babel/regjsgen": ^0.8.0 - regenerate: ^1.4.2 - regenerate-unicode-properties: ^10.1.0 - regjsparser: ^0.9.1 - unicode-match-property-ecmascript: ^2.0.0 - unicode-match-property-value-ecmascript: ^2.1.0 - checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 - languageName: node - linkType: hard - -"regjsparser@npm:^0.9.1": - version: 0.9.1 - resolution: "regjsparser@npm:0.9.1" - dependencies: - jsesc: ~0.5.0 - bin: - regjsparser: bin/parser - checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc - languageName: node - linkType: hard - -"relateurl@npm:^0.2.7": - version: 0.2.7 - resolution: "relateurl@npm:0.2.7" - checksum: 5891e792eae1dfc3da91c6fda76d6c3de0333a60aa5ad848982ebb6dccaa06e86385fb1235a1582c680a3d445d31be01c6bfc0804ebbcab5aaf53fa856fde6b6 - languageName: node - linkType: hard - -"renderkid@npm:^3.0.0": - version: 3.0.0 - resolution: "renderkid@npm:3.0.0" - dependencies: - css-select: ^4.1.3 - dom-converter: ^0.2.0 - htmlparser2: ^6.1.0 - lodash: ^4.17.21 - strip-ansi: ^6.0.1 - checksum: 77162b62d6f33ab81f337c39efce0439ff0d1f6d441e29c35183151f83041c7850774fb904da163d6c844264d440d10557714e6daa0b19e4561a5cd4ef305d41 - languageName: node - linkType: hard - -"require-directory@npm:^2.1.1": - version: 2.1.1 - resolution: "require-directory@npm:2.1.1" - checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b - languageName: node - linkType: hard - -"requires-port@npm:^1.0.0": - version: 1.0.0 - resolution: "requires-port@npm:1.0.0" - checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff - languageName: node - linkType: hard - -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: ^5.0.0 - checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 - languageName: node - linkType: hard - -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf - languageName: node - linkType: hard - -"resolve-url-loader@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-url-loader@npm:4.0.0" - dependencies: - adjust-sourcemap-loader: ^4.0.0 - convert-source-map: ^1.7.0 - loader-utils: ^2.0.0 - postcss: ^7.0.35 - source-map: 0.6.1 - peerDependencies: - rework: 1.0.1 - rework-visit: 1.0.0 - peerDependenciesMeta: - rework: - optional: true - rework-visit: - optional: true - checksum: 8e5bcf97867a5e128b6b86988d445b7fbd1214f7c5c0214332f835e8607438e153d9b3899799a03ddd03540254bb591e572feb330981a4478be934f6f045c925 - languageName: node - linkType: hard - -"resolve.exports@npm:^1.1.0": - version: 1.1.1 - resolution: "resolve.exports@npm:1.1.1" - checksum: 485aa10082eb388a569d696e17ad7b16f4186efc97dd34eadd029d95b811f21ffee13b1b733198bb4584dbb3cb296aa6f141835221fb7613b9606b84f1386655 - languageName: node - linkType: hard - -"resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": - version: 1.22.6 - resolution: "resolve@npm:1.22.6" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: d13bf66d4e2ee30d291491f16f2fa44edd4e0cefb85d53249dd6f93e70b2b8c20ec62f01b18662e3cd40e50a7528f18c4087a99490048992a3bb954cf3201a5b - languageName: node - linkType: hard - -"resolve@npm:^2.0.0-next.4": - version: 2.0.0-next.4 - resolution: "resolve@npm:2.0.0-next.4" - dependencies: - is-core-module: ^2.9.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: c438ac9a650f2030fd074219d7f12ceb983b475da2d89ad3d6dd05fbf6b7a0a8cd37d4d10b43cb1f632bc19f22246ab7f36ebda54d84a29bfb2910a0680906d3 - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin": - version: 1.22.6 - resolution: "resolve@patch:resolve@npm%3A1.22.6#~builtin::version=1.22.6&hash=07638b" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 9d3b3c67aefd12cecbe5f10ca4d1f51ea190891096497c43f301b086883b426466918c3a64f1bbf1788fabb52b579d58809614006c5d0b49186702b3b8fb746a - languageName: node - linkType: hard - -"resolve@patch:resolve@^2.0.0-next.4#~builtin": - version: 2.0.0-next.4 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=07638b" - dependencies: - is-core-module: ^2.9.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 4bf9f4f8a458607af90518ff73c67a4bc1a38b5a23fef2bb0ccbd45e8be89820a1639b637b0ba377eb2be9eedfb1739a84cde24fe4cd670c8207d8fea922b011 - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c - languageName: node - linkType: hard - -"retry@npm:^0.13.1": - version: 0.13.1 - resolution: "retry@npm:0.13.1" - checksum: 47c4d5be674f7c13eee4cfe927345023972197dbbdfba5d3af7e461d13b44de1bfd663bfc80d2f601f8ef3fc8164c16dd99655a221921954a65d044a2fc1233b - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc - languageName: node - linkType: hard - -"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: ^7.1.3 - bin: - rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 - languageName: node - linkType: hard - -"rollup-plugin-terser@npm:^7.0.0": - version: 7.0.2 - resolution: "rollup-plugin-terser@npm:7.0.2" - dependencies: - "@babel/code-frame": ^7.10.4 - jest-worker: ^26.2.1 - serialize-javascript: ^4.0.0 - terser: ^5.0.0 - peerDependencies: - rollup: ^2.0.0 - checksum: af84bb7a7a894cd00852b6486528dfb8653cf94df4c126f95f389a346f401d054b08c46bee519a2ab6a22b33804d1d6ac6d8c90b1b2bf8fffb097eed73fc3c72 - languageName: node - linkType: hard - -"rollup@npm:^2.43.1": - version: 2.79.1 - resolution: "rollup@npm:2.79.1" - dependencies: - fsevents: ~2.3.2 - dependenciesMeta: - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 6a2bf167b3587d4df709b37d149ad0300692cc5deb510f89ac7bdc77c8738c9546ae3de9322b0968e1ed2b0e984571f5f55aae28fa7de4cfcb1bc5402a4e2be6 - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: ^1.2.2 - checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.0.0, safe-array-concat@npm:^1.0.1": - version: 1.0.1 - resolution: "safe-array-concat@npm:1.0.1" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.1 - has-symbols: ^1.0.3 - isarray: ^2.0.5 - checksum: 001ecf1d8af398251cbfabaf30ed66e3855127fbceee178179524b24160b49d15442f94ed6c0db0b2e796da76bb05b73bf3cc241490ec9c2b741b41d33058581 - languageName: node - linkType: hard - -"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c - languageName: node - linkType: hard - -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-regex-test@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - is-regex: ^1.1.4 - checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 - languageName: node - linkType: hard - -"sanitize.css@npm:*": - version: 13.0.0 - resolution: "sanitize.css@npm:13.0.0" - checksum: a99ca77c4d135800a4a93c3555e5aa4a2eb040a833df716dbe9132e1f2086fbf9acdb8021a579f40dcf77166d2d50f3358b4b6121a247d26fed5a0e6f5af3bb7 - languageName: node - linkType: hard - -"sass-loader@npm:^12.3.0": - version: 12.6.0 - resolution: "sass-loader@npm:12.6.0" - dependencies: - klona: ^2.0.4 - neo-async: ^2.6.2 - peerDependencies: - fibers: ">= 3.1.0" - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - sass: ^1.3.0 - sass-embedded: "*" - webpack: ^5.0.0 - peerDependenciesMeta: - fibers: - optional: true - node-sass: - optional: true - sass: - optional: true - sass-embedded: - optional: true - checksum: 5d73a428588150f704016aa27397941bb9246cecd2ee083b573e95d969fc080ac6a16f2fe1cc64aca08f6e70da6f3c586ee68f0efc9f527fecc360e5f1c299ec - languageName: node - linkType: hard - -"sax@npm:~1.2.4": - version: 1.2.4 - resolution: "sax@npm:1.2.4" - checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe - languageName: node - linkType: hard - -"saxes@npm:^5.0.1": - version: 5.0.1 - resolution: "saxes@npm:5.0.1" - dependencies: - xmlchars: ^2.2.0 - checksum: 5636b55cf15f7cf0baa73f2797bf992bdcf75d1b39d82c0aa4608555c774368f6ac321cb641fd5f3d3ceb87805122cd47540da6a7b5960fe0dbdb8f8c263f000 - languageName: node - linkType: hard - -"scheduler@npm:^0.23.0": - version: 0.23.0 - resolution: "scheduler@npm:0.23.0" - dependencies: - loose-envify: ^1.1.0 - checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a - languageName: node - linkType: hard - -"schema-utils@npm:2.7.0": - version: 2.7.0 - resolution: "schema-utils@npm:2.7.0" - dependencies: - "@types/json-schema": ^7.0.4 - ajv: ^6.12.2 - ajv-keywords: ^3.4.1 - checksum: 8889325b0ee1ae6a8f5d6aaa855c71e136ebbb7fd731b01a9d3ec8225dcb245f644c47c50104db4c741983b528cdff8558570021257d4d397ec6aaecd9172a8e - languageName: node - linkType: hard - -"schema-utils@npm:^2.6.5": - version: 2.7.1 - resolution: "schema-utils@npm:2.7.1" - dependencies: - "@types/json-schema": ^7.0.5 - ajv: ^6.12.4 - ajv-keywords: ^3.5.2 - checksum: 32c62fc9e28edd101e1bd83453a4216eb9bd875cc4d3775e4452b541908fa8f61a7bbac8ffde57484f01d7096279d3ba0337078e85a918ecbeb72872fb09fb2b - languageName: node - linkType: hard - -"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.1, schema-utils@npm:^3.2.0": - version: 3.3.0 - resolution: "schema-utils@npm:3.3.0" - dependencies: - "@types/json-schema": ^7.0.8 - ajv: ^6.12.5 - ajv-keywords: ^3.5.2 - checksum: ea56971926fac2487f0757da939a871388891bc87c6a82220d125d587b388f1704788f3706e7f63a7b70e49fc2db974c41343528caea60444afd5ce0fe4b85c0 - languageName: node - linkType: hard - -"schema-utils@npm:^4.0.0": - version: 4.2.0 - resolution: "schema-utils@npm:4.2.0" - dependencies: - "@types/json-schema": ^7.0.9 - ajv: ^8.9.0 - ajv-formats: ^2.1.1 - ajv-keywords: ^5.1.0 - checksum: 26a0463d47683258106e6652e9aeb0823bf0b85843039e068b57da1892f7ae6b6b1094d48e9ed5ba5cbe9f7166469d880858b9d91abe8bd249421eb813850cde - languageName: node - linkType: hard - -"select-hose@npm:^2.0.0": - version: 2.0.0 - resolution: "select-hose@npm:2.0.0" - checksum: d7e5fcc695a4804209d232a1b18624a5134be334d4e1114b0721f7a5e72bd73da483dcf41528c1af4f4f4892ad7cfd6a1e55c8ffb83f9c9fe723b738db609dbb - languageName: node - linkType: hard - -"selfsigned@npm:^2.1.1": - version: 2.1.1 - resolution: "selfsigned@npm:2.1.1" - dependencies: - node-forge: ^1 - checksum: aa9ce2150a54838978d5c0aee54d7ebe77649a32e4e690eb91775f71fdff773874a4fbafd0ac73d8ec3b702ff8a395c604df4f8e8868528f36fd6c15076fb43a - languageName: node - linkType: hard - -"semver@npm:^6.0.0, semver@npm:^6.3.0, semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 - languageName: node - linkType: hard - -"semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 - languageName: node - linkType: hard - -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - etag: ~1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: ~1.2.1 - statuses: 2.0.1 - checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 - languageName: node - linkType: hard - -"serialize-javascript@npm:^4.0.0": - version: 4.0.0 - resolution: "serialize-javascript@npm:4.0.0" - dependencies: - randombytes: ^2.1.0 - checksum: 3273b3394b951671fcf388726e9577021870dfbf85e742a1183fb2e91273e6101bdccea81ff230724f6659a7ee4cef924b0ff9baca32b79d9384ec37caf07302 - languageName: node - linkType: hard - -"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1": - version: 6.0.1 - resolution: "serialize-javascript@npm:6.0.1" - dependencies: - randombytes: ^2.1.0 - checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f - languageName: node - linkType: hard - -"serve-index@npm:^1.9.1": - version: 1.9.1 - resolution: "serve-index@npm:1.9.1" - dependencies: - accepts: ~1.3.4 - batch: 0.6.1 - debug: 2.6.9 - escape-html: ~1.0.3 - http-errors: ~1.6.2 - mime-types: ~2.1.17 - parseurl: ~1.3.2 - checksum: e2647ce13379485b98a53ba2ea3fbad4d44b57540d00663b02b976e426e6194d62ac465c0d862cb7057f65e0de8ab8a684aa095427a4b8612412eca0d300d22f - languageName: node - linkType: hard - -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" - dependencies: - encodeurl: ~1.0.2 - escape-html: ~1.0.3 - parseurl: ~1.3.3 - send: 0.18.0 - checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d - languageName: node - linkType: hard - -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.0, set-function-name@npm:^2.0.1": - version: 2.0.1 - resolution: "set-function-name@npm:2.0.1" - dependencies: - define-data-property: ^1.0.1 - functions-have-names: ^1.2.3 - has-property-descriptors: ^1.0.0 - checksum: 4975d17d90c40168eee2c7c9c59d023429f0a1690a89d75656306481ece0c3c1fb1ebcc0150ea546d1913e35fbd037bace91372c69e543e51fc5d1f31a9fa126 - languageName: node - linkType: hard - -"setprototypeof@npm:1.1.0": - version: 1.1.0 - resolution: "setprototypeof@npm:1.1.0" - checksum: 27cb44304d6c9e1a23bc6c706af4acaae1a7aa1054d4ec13c05f01a99fd4887109a83a8042b67ad90dbfcd100d43efc171ee036eb080667172079213242ca36e - languageName: node - linkType: hard - -"setprototypeof@npm:1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: be18cbbf70e7d8097c97f713a2e76edf84e87299b40d085c6bf8b65314e994cc15e2e317727342fa6996e38e1f52c59720b53fe621e2eb593a6847bf0356db89 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: ^3.0.0 - checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"shell-quote@npm:^1.7.3": - version: 1.8.1 - resolution: "shell-quote@npm:1.8.1" - checksum: 5f01201f4ef504d4c6a9d0d283fa17075f6770bfbe4c5850b074974c68062f37929ca61700d95ad2ac8822e14e8c4b990ca0e6e9272e64befd74ce5e19f0736b - languageName: node - linkType: hard - -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" - dependencies: - call-bind: ^1.0.0 - get-intrinsic: ^1.0.2 - object-inspect: ^1.9.0 - checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 - languageName: node - linkType: hard - -"sisteransi@npm:^1.0.5": - version: 1.0.5 - resolution: "sisteransi@npm:1.0.5" - checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 - languageName: node - linkType: hard - -"slash@npm:^3.0.0": - version: 3.0.0 - resolution: "slash@npm:3.0.0" - checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c - languageName: node - linkType: hard - -"slash@npm:^4.0.0": - version: 4.0.0 - resolution: "slash@npm:4.0.0" - checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b - languageName: node - linkType: hard - -"sockjs@npm:^0.3.24": - version: 0.3.24 - resolution: "sockjs@npm:0.3.24" - dependencies: - faye-websocket: ^0.11.3 - uuid: ^8.3.2 - websocket-driver: ^0.7.4 - checksum: 355309b48d2c4e9755349daa29cea1c0d9ee23e49b983841c6bf7a20276b00d3c02343f9f33f26d2ee8b261a5a02961b52a25c8da88b2538c5b68d3071b4934c - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" - dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 - languageName: node - linkType: hard - -"socks@npm:^2.6.2": - version: 2.7.1 - resolution: "socks@npm:2.7.1" - dependencies: - ip: ^2.0.0 - smart-buffer: ^4.2.0 - checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 - languageName: node - linkType: hard - -"source-list-map@npm:^2.0.0, source-list-map@npm:^2.0.1": - version: 2.0.1 - resolution: "source-list-map@npm:2.0.1" - checksum: 806efc6f75e7cd31e4815e7a3aaf75a45c704871ea4075cb2eb49882c6fca28998f44fc5ac91adb6de03b2882ee6fb02f951fdc85e6a22b338c32bfe19557938 - languageName: node - linkType: hard - -"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2": - version: 1.0.2 - resolution: "source-map-js@npm:1.0.2" - checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c - languageName: node - linkType: hard - -"source-map-loader@npm:^3.0.0": - version: 3.0.2 - resolution: "source-map-loader@npm:3.0.2" - dependencies: - abab: ^2.0.5 - iconv-lite: ^0.6.3 - source-map-js: ^1.0.1 - peerDependencies: - webpack: ^5.0.0 - checksum: d5a4e2ab190c93ae5cba68c247fbaa9fd560333c91060602b634c399a8a4b3205b8c07714c3bcdb0a11c6cc5476c06256bd8e824e71fbbb7981e8fad5cba4a00 - languageName: node - linkType: hard - -"source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: ^1.0.0 - source-map: ^0.6.0 - checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 - languageName: node - linkType: hard - -"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - -"source-map@npm:^0.7.3": - version: 0.7.4 - resolution: "source-map@npm:0.7.4" - checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5 - languageName: node - linkType: hard - -"source-map@npm:^0.8.0-beta.0": - version: 0.8.0-beta.0 - resolution: "source-map@npm:0.8.0-beta.0" - dependencies: - whatwg-url: ^7.0.0 - checksum: e94169be6461ab0ac0913313ad1719a14c60d402bd22b0ad96f4a6cffd79130d91ab5df0a5336a326b04d2df131c1409f563c9dc0d21a6ca6239a44b6c8dbd92 - languageName: node - linkType: hard - -"sourcemap-codec@npm:^1.4.8": - version: 1.4.8 - resolution: "sourcemap-codec@npm:1.4.8" - checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 - languageName: node - linkType: hard - -"spdy-transport@npm:^3.0.0": - version: 3.0.0 - resolution: "spdy-transport@npm:3.0.0" - dependencies: - debug: ^4.1.0 - detect-node: ^2.0.4 - hpack.js: ^2.1.6 - obuf: ^1.1.2 - readable-stream: ^3.0.6 - wbuf: ^1.7.3 - checksum: 0fcaad3b836fb1ec0bdd39fa7008b9a7a84a553f12be6b736a2512613b323207ffc924b9551cef0378f7233c85916cff1118652e03a730bdb97c0e042243d56c - languageName: node - linkType: hard - -"spdy@npm:^4.0.2": - version: 4.0.2 - resolution: "spdy@npm:4.0.2" - dependencies: - debug: ^4.1.0 - handle-thing: ^2.0.0 - http-deceiver: ^1.2.7 - select-hose: ^2.0.0 - spdy-transport: ^3.0.0 - checksum: 2c739d0ff6f56ad36d2d754d0261d5ec358457bea7cbf77b1b05b0c6464f2ce65b85f196305f50b7bd9120723eb94bae9933466f28e67e5cd8cde4e27f1d75f8 - languageName: node - linkType: hard - -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3 - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.5 - resolution: "ssri@npm:10.0.5" - dependencies: - minipass: ^7.0.3 - checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 - languageName: node - linkType: hard - -"stable@npm:^0.1.8": - version: 0.1.8 - resolution: "stable@npm:0.1.8" - checksum: 2ff482bb100285d16dd75cd8f7c60ab652570e8952c0bfa91828a2b5f646a0ff533f14596ea4eabd48bb7f4aeea408dce8f8515812b975d958a4cc4fa6b9dfeb - languageName: node - linkType: hard - -"stack-utils@npm:^2.0.3": - version: 2.0.6 - resolution: "stack-utils@npm:2.0.6" - dependencies: - escape-string-regexp: ^2.0.0 - checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 - languageName: node - linkType: hard - -"stackframe@npm:^1.3.4": - version: 1.3.4 - resolution: "stackframe@npm:1.3.4" - checksum: bae1596873595c4610993fa84f86a3387d67586401c1816ea048c0196800c0646c4d2da98c2ee80557fd9eff05877efe33b91ba6cd052658ed96ddc85d19067d - languageName: node - linkType: hard - -"static-eval@npm:2.0.2": - version: 2.0.2 - resolution: "static-eval@npm:2.0.2" - dependencies: - escodegen: ^1.8.1 - checksum: 335a923c5ccb29add404ac23d0a55c0da6cee3071f6f67a7053aeac0dedc6dbfc53ac9269e9c25f403f5b7603a291ef47d7114f99bde241184f7aa3f9286dc32 - languageName: node - linkType: hard - -"statuses@npm:2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb - languageName: node - linkType: hard - -"statuses@npm:>= 1.4.0 < 2": - version: 1.5.0 - resolution: "statuses@npm:1.5.0" - checksum: c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c - languageName: node - linkType: hard - -"stop-iteration-iterator@npm:^1.0.0": - version: 1.0.0 - resolution: "stop-iteration-iterator@npm:1.0.0" - dependencies: - internal-slot: ^1.0.4 - checksum: d04173690b2efa40e24ab70e5e51a3ff31d56d699550cfad084104ab3381390daccb36652b25755e420245f3b0737de66c1879eaa2a8d4fc0a78f9bf892fcb42 - languageName: node - linkType: hard - -"string-length@npm:^4.0.1": - version: 4.0.2 - resolution: "string-length@npm:4.0.2" - dependencies: - char-regex: ^1.0.2 - strip-ansi: ^6.0.0 - checksum: ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 - languageName: node - linkType: hard - -"string-length@npm:^5.0.1": - version: 5.0.1 - resolution: "string-length@npm:5.0.1" - dependencies: - char-regex: ^2.0.0 - strip-ansi: ^7.0.1 - checksum: 71f73b8c8a743e01dcd001bcf1b197db78d5e5e53b12bd898cddaf0961be09f947dfd8c429783db3694b55b05cb5a51de6406c5085ff1aaa10c4771440c8396d - languageName: node - linkType: hard - -"string-natural-compare@npm:^3.0.1": - version: 3.0.1 - resolution: "string-natural-compare@npm:3.0.1" - checksum: 65910d9995074086e769a68728395effbba9b7186be5b4c16a7fad4f4ef50cae95ca16e3e9086e019cbb636ae8daac9c7b8fe91b5f21865c5c0f26e3c0725406 - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: ^8.0.0 - is-fullwidth-code-point: ^3.0.0 - strip-ansi: ^6.0.1 - checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: ^0.2.0 - emoji-regex: ^9.2.2 - strip-ansi: ^7.0.1 - checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - -"string.prototype.matchall@npm:^4.0.6, string.prototype.matchall@npm:^4.0.8": - version: 4.0.10 - resolution: "string.prototype.matchall@npm:4.0.10" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - get-intrinsic: ^1.2.1 - has-symbols: ^1.0.3 - internal-slot: ^1.0.5 - regexp.prototype.flags: ^1.5.0 - set-function-name: ^2.0.0 - side-channel: ^1.0.4 - checksum: 3c78bdeff39360c8e435d7c4c6ea19f454aa7a63eda95fa6fadc3a5b984446a2f9f2c02d5c94171ce22268a573524263fbd0c8edbe3ce2e9890d7cc036cdc3ed - languageName: node - linkType: hard - -"string.prototype.trim@npm:^1.2.8": - version: 1.2.8 - resolution: "string.prototype.trim@npm:1.2.8" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: 49eb1a862a53aba73c3fb6c2a53f5463173cb1f4512374b623bcd6b43ad49dd559a06fb5789bdec771a40fc4d2a564411c0a75d35fb27e76bbe738c211ecff07 - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.7": - version: 1.0.7 - resolution: "string.prototype.trimend@npm:1.0.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: 2375516272fd1ba75992f4c4aa88a7b5f3c7a9ca308d963bcd5645adf689eba6f8a04ebab80c33e30ec0aefc6554181a3a8416015c38da0aa118e60ec896310c - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.7": - version: 1.0.7 - resolution: "string.prototype.trimstart@npm:1.0.7" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.22.1 - checksum: 13d0c2cb0d5ff9e926fa0bec559158b062eed2b68cd5be777ffba782c96b2b492944e47057274e064549b94dd27cf81f48b27a31fee8af5b574cff253e7eb613 - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: ~5.2.0 - checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: ~5.1.0 - checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b - languageName: node - linkType: hard - -"stringify-object@npm:^3.3.0": - version: 3.3.0 - resolution: "stringify-object@npm:3.3.0" - dependencies: - get-own-enumerable-property-symbols: ^3.0.0 - is-obj: ^1.0.1 - is-regexp: ^1.0.0 - checksum: 6827a3f35975cfa8572e8cd3ed4f7b262def260af18655c6fde549334acdac49ddba69f3c861ea5a6e9c5a4990fe4ae870b9c0e6c31019430504c94a83b7a154 - languageName: node - linkType: hard - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: ^5.0.1 - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: ^6.0.1 - checksum: 859c73fcf27869c22a4e4d8c6acfe690064659e84bef9458aa6d13719d09ca88dcfd40cbf31fd0be63518ea1a643fe070b4827d353e09533a5b0b9fd4553d64d - languageName: node - linkType: hard - -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b - languageName: node - linkType: hard - -"strip-bom@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-bom@npm:4.0.0" - checksum: 9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 - languageName: node - linkType: hard - -"strip-comments@npm:^2.0.1": - version: 2.0.1 - resolution: "strip-comments@npm:2.0.1" - checksum: 36cd122e1c27b5be69df87e1687770a62fe183bdee9f3ff5cf85d30bbc98280afc012581f2fd50c7ad077c90f656f272560c9d2e520d28604b8b7ea3bc87d6f9 - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"strip-indent@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-indent@npm:3.0.0" - dependencies: - min-indent: ^1.0.0 - checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 - languageName: node - linkType: hard - -"style-loader@npm:^3.3.1": - version: 3.3.3 - resolution: "style-loader@npm:3.3.3" - peerDependencies: - webpack: ^5.0.0 - checksum: f59c953f56f6a935bd6a1dfa409f1128fed2b66b48ce4a7a75b85862a7156e5e90ab163878962762f528ec4d510903d828da645e143fbffd26f055dc1c094078 - languageName: node - linkType: hard - -"stylehacks@npm:^5.1.1": - version: 5.1.1 - resolution: "stylehacks@npm:5.1.1" - dependencies: - browserslist: ^4.21.4 - postcss-selector-parser: ^6.0.4 - peerDependencies: - postcss: ^8.2.15 - checksum: 11175366ef52de65bf06cefba0ddc9db286dc3a1451fd2989e74c6ea47091a02329a4bf6ce10b1a36950056927b6bbbe47c5ab3a1f4c7032df932d010fbde5a2 - languageName: node - linkType: hard - -"sucrase@npm:^3.32.0": - version: 3.34.0 - resolution: "sucrase@npm:3.34.0" - dependencies: - "@jridgewell/gen-mapping": ^0.3.2 - commander: ^4.0.0 - glob: 7.1.6 - lines-and-columns: ^1.1.6 - mz: ^2.7.0 - pirates: ^4.0.1 - ts-interface-checker: ^0.1.9 - bin: - sucrase: bin/sucrase - sucrase-node: bin/sucrase-node - checksum: 61860063bdf6103413698e13247a3074d25843e91170825a9752e4af7668ffadd331b6e99e92fc32ee5b3c484ee134936f926fa9039d5711fafff29d017a2110 - languageName: node - linkType: hard - -"supports-color@npm:^5.3.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: ^3.0.0 - checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac - languageName: node - linkType: hard - -"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: ^4.0.0 - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a - languageName: node - linkType: hard - -"supports-color@npm:^8.0.0": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: ^4.0.0 - checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 - languageName: node - linkType: hard - -"supports-hyperlinks@npm:^2.0.0": - version: 2.3.0 - resolution: "supports-hyperlinks@npm:2.3.0" - dependencies: - has-flag: ^4.0.0 - supports-color: ^7.0.0 - checksum: 9ee0de3c8ce919d453511b2b1588a8205bd429d98af94a01df87411391010fe22ca463f268c84b2ce2abad019dfff8452aa02806eeb5c905a8d7ad5c4f4c52b8 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae - languageName: node - linkType: hard - -"svg-parser@npm:^2.0.2": - version: 2.0.4 - resolution: "svg-parser@npm:2.0.4" - checksum: b3de6653048212f2ae7afe4a423e04a76ec6d2d06e1bf7eacc618a7c5f7df7faa5105561c57b94579ec831fbbdbf5f190ba56a9205ff39ed13eabdf8ab086ddf - languageName: node - linkType: hard - -"svgo@npm:^1.2.2": - version: 1.3.2 - resolution: "svgo@npm:1.3.2" - dependencies: - chalk: ^2.4.1 - coa: ^2.0.2 - css-select: ^2.0.0 - css-select-base-adapter: ^0.1.1 - css-tree: 1.0.0-alpha.37 - csso: ^4.0.2 - js-yaml: ^3.13.1 - mkdirp: ~0.5.1 - object.values: ^1.1.0 - sax: ~1.2.4 - stable: ^0.1.8 - unquote: ~1.1.1 - util.promisify: ~1.0.0 - bin: - svgo: ./bin/svgo - checksum: 28a5680a61245eb4a1603bc03459095bb01ad5ebd23e95882d886c3c81752313c0a9a9fe48dd0bcbb9a27c52e11c603640df952971573b2b550d9e15a9ee6116 - languageName: node - linkType: hard - -"svgo@npm:^2.7.0": - version: 2.8.0 - resolution: "svgo@npm:2.8.0" - dependencies: - "@trysound/sax": 0.2.0 - commander: ^7.2.0 - css-select: ^4.1.3 - css-tree: ^1.1.3 - csso: ^4.2.0 - picocolors: ^1.0.0 - stable: ^0.1.8 - bin: - svgo: bin/svgo - checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 - languageName: node - linkType: hard - -"symbol-tree@npm:^3.2.4": - version: 3.2.4 - resolution: "symbol-tree@npm:3.2.4" - checksum: 6e8fc7e1486b8b54bea91199d9535bb72f10842e40c79e882fc94fb7b14b89866adf2fd79efa5ebb5b658bc07fb459ccce5ac0e99ef3d72f474e74aaf284029d - languageName: node - linkType: hard - -"tailwindcss@npm:^3.0.2": - version: 3.3.3 - resolution: "tailwindcss@npm:3.3.3" - dependencies: - "@alloc/quick-lru": ^5.2.0 - arg: ^5.0.2 - chokidar: ^3.5.3 - didyoumean: ^1.2.2 - dlv: ^1.1.3 - fast-glob: ^3.2.12 - glob-parent: ^6.0.2 - is-glob: ^4.0.3 - jiti: ^1.18.2 - lilconfig: ^2.1.0 - micromatch: ^4.0.5 - normalize-path: ^3.0.0 - object-hash: ^3.0.0 - picocolors: ^1.0.0 - postcss: ^8.4.23 - postcss-import: ^15.1.0 - postcss-js: ^4.0.1 - postcss-load-config: ^4.0.1 - postcss-nested: ^6.0.1 - postcss-selector-parser: ^6.0.11 - resolve: ^1.22.2 - sucrase: ^3.32.0 - bin: - tailwind: lib/cli.js - tailwindcss: lib/cli.js - checksum: 0195c7a3ebb0de5e391d2a883d777c78a4749f0c532d204ee8aea9129f2ed8e701d8c0c276aa5f7338d07176a3c2a7682c1d0ab9c8a6c2abe6d9325c2954eb50 - languageName: node - linkType: hard - -"tapable@npm:^1.0.0": - version: 1.1.3 - resolution: "tapable@npm:1.1.3" - checksum: 53ff4e7c3900051c38cc4faab428ebfd7e6ad0841af5a7ac6d5f3045c5b50e88497bfa8295b4b3fbcadd94993c9e358868b78b9fb249a76cb8b018ac8dccafd7 - languageName: node - linkType: hard - -"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0": - version: 2.2.1 - resolution: "tapable@npm:2.2.1" - checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.2.0 - resolution: "tar@npm:6.2.0" - dependencies: - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - minipass: ^5.0.0 - minizlib: ^2.1.1 - mkdirp: ^1.0.3 - yallist: ^4.0.0 - checksum: db4d9fe74a2082c3a5016630092c54c8375ff3b280186938cfd104f2e089c4fd9bad58688ef6be9cf186a889671bf355c7cda38f09bbf60604b281715ca57f5c - languageName: node - linkType: hard - -"temp-dir@npm:^2.0.0": - version: 2.0.0 - resolution: "temp-dir@npm:2.0.0" - checksum: cc4f0404bf8d6ae1a166e0e64f3f409b423f4d1274d8c02814a59a5529f07db6cd070a749664141b992b2c1af337fa9bb451a460a43bb9bcddc49f235d3115aa - languageName: node - linkType: hard - -"tempy@npm:^0.6.0": - version: 0.6.0 - resolution: "tempy@npm:0.6.0" - dependencies: - is-stream: ^2.0.0 - temp-dir: ^2.0.0 - type-fest: ^0.16.0 - unique-string: ^2.0.0 - checksum: dd09c8b6615e4b785ea878e9a18b17ac0bfe5dccf5a0e205ebd274bb356356aff3f5c90a6c917077d51c75efb7648b113a78b0492e2ffc81a7c9912eb872ac52 - languageName: node - linkType: hard - -"terminal-link@npm:^2.0.0": - version: 2.1.1 - resolution: "terminal-link@npm:2.1.1" - dependencies: - ansi-escapes: ^4.2.1 - supports-hyperlinks: ^2.0.0 - checksum: ce3d2cd3a438c4a9453947aa664581519173ea40e77e2534d08c088ee6dda449eabdbe0a76d2a516b8b73c33262fedd10d5270ccf7576ae316e3db170ce6562f - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^5.2.5, terser-webpack-plugin@npm:^5.3.7": - version: 5.3.9 - resolution: "terser-webpack-plugin@npm:5.3.9" - dependencies: - "@jridgewell/trace-mapping": ^0.3.17 - jest-worker: ^27.4.5 - schema-utils: ^3.1.1 - serialize-javascript: ^6.0.1 - terser: ^5.16.8 - peerDependencies: - webpack: ^5.1.0 - peerDependenciesMeta: - "@swc/core": - optional: true - esbuild: - optional: true - uglify-js: - optional: true - checksum: 41705713d6f9cb83287936b21e27c658891c78c4392159f5148b5623f0e8c48559869779619b058382a4c9758e7820ea034695e57dc7c474b4962b79f553bc5f - languageName: node - linkType: hard - -"terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.16.8": - version: 5.20.0 - resolution: "terser@npm:5.20.0" - dependencies: - "@jridgewell/source-map": ^0.3.3 - acorn: ^8.8.2 - commander: ^2.20.0 - source-map-support: ~0.5.20 - bin: - terser: bin/terser - checksum: 251d1b62d7c651ace29f997cf336ff5d5f8e30c65c8698ab7b831764d9e012ab0640895cb609906fb939a5bdf5143d73b5781c5c8c67b9216c77ce92dafdc0bc - languageName: node - linkType: hard - -"test-exclude@npm:^6.0.0": - version: 6.0.0 - resolution: "test-exclude@npm:6.0.0" - dependencies: - "@istanbuljs/schema": ^0.1.2 - glob: ^7.1.4 - minimatch: ^3.0.4 - checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 - languageName: node - linkType: hard - -"text-table@npm:^0.2.0": - version: 0.2.0 - resolution: "text-table@npm:0.2.0" - checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a - languageName: node - linkType: hard - -"thenify-all@npm:^1.0.0": - version: 1.6.0 - resolution: "thenify-all@npm:1.6.0" - dependencies: - thenify: ">= 3.1.0 < 4" - checksum: dba7cc8a23a154cdcb6acb7f51d61511c37a6b077ec5ab5da6e8b874272015937788402fd271fdfc5f187f8cb0948e38d0a42dcc89d554d731652ab458f5343e - languageName: node - linkType: hard - -"thenify@npm:>= 3.1.0 < 4": - version: 3.3.1 - resolution: "thenify@npm:3.3.1" - dependencies: - any-promise: ^1.0.0 - checksum: 84e1b804bfec49f3531215f17b4a6e50fd4397b5f7c1bccc427b9c656e1ecfb13ea79d899930184f78bc2f57285c54d9a50a590c8868f4f0cef5c1d9f898b05e - languageName: node - linkType: hard - -"throat@npm:^6.0.1": - version: 6.0.2 - resolution: "throat@npm:6.0.2" - checksum: 463093768d4884772020bb18b0f33d3fec8a2b4173f7da3958dfbe88ff0f1e686ffadf0f87333bf6f6db7306b1450efc7855df69c78bf0bfa61f6d84a3361fe8 - languageName: node - linkType: hard - -"thunky@npm:^1.0.2": - version: 1.1.0 - resolution: "thunky@npm:1.1.0" - checksum: 993096c472b6b8f30e29dc777a8d17720e4cab448375041f20c0cb802a09a7fb2217f2a3e8cdc11851faa71c957e2db309357367fc9d7af3cb7a4d00f4b66034 - languageName: node - linkType: hard - -"tmpl@npm:1.0.5": - version: 1.0.5 - resolution: "tmpl@npm:1.0.5" - checksum: cd922d9b853c00fe414c5a774817be65b058d54a2d01ebb415840960406c669a0fc632f66df885e24cb022ec812739199ccbdb8d1164c3e513f85bfca5ab2873 - languageName: node - linkType: hard - -"to-fast-properties@npm:^2.0.0": - version: 2.0.0 - resolution: "to-fast-properties@npm:2.0.0" - checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: ^7.0.0 - checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed - languageName: node - linkType: hard - -"toidentifier@npm:1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 - languageName: node - linkType: hard - -"tough-cookie@npm:^4.0.0": - version: 4.1.3 - resolution: "tough-cookie@npm:4.1.3" - dependencies: - psl: ^1.1.33 - punycode: ^2.1.1 - universalify: ^0.2.0 - url-parse: ^1.5.3 - checksum: c9226afff36492a52118432611af083d1d8493a53ff41ec4ea48e5b583aec744b989e4280bcf476c910ec1525a89a4a0f1cae81c08b18fb2ec3a9b3a72b91dcc - languageName: node - linkType: hard - -"tr46@npm:^1.0.1": - version: 1.0.1 - resolution: "tr46@npm:1.0.1" - dependencies: - punycode: ^2.1.0 - checksum: 96d4ed46bc161db75dbf9247a236ea0bfcaf5758baae6749e92afab0bc5a09cb59af21788ede7e55080f2bf02dce3e4a8f2a484cc45164e29f4b5e68f7cbcc1a - languageName: node - linkType: hard - -"tr46@npm:^2.1.0": - version: 2.1.0 - resolution: "tr46@npm:2.1.0" - dependencies: - punycode: ^2.1.1 - checksum: ffe6049b9dca3ae329b059aada7f515b0f0064c611b39b51ff6b53897e954650f6f63d9319c6c008d36ead477c7b55e5f64c9dc60588ddc91ff720d64eb710b3 - languageName: node - linkType: hard - -"tryer@npm:^1.0.1": - version: 1.0.1 - resolution: "tryer@npm:1.0.1" - checksum: 1cf14d7f67c79613f054b569bfc9a89c7020d331573a812dfcf7437244e8f8e6eb6893b210cbd9cc217f67c1d72617f89793df231e4fe7d53634ed91cf3a89d1 - languageName: node - linkType: hard - -"ts-interface-checker@npm:^0.1.9": - version: 0.1.13 - resolution: "ts-interface-checker@npm:0.1.13" - checksum: 20c29189c2dd6067a8775e07823ddf8d59a33e2ffc47a1bd59a5cb28bb0121a2969a816d5e77eda2ed85b18171aa5d1c4005a6b88ae8499ec7cc49f78571cb5e - languageName: node - linkType: hard - -"tsconfig-paths@npm:^3.14.2": - version: 3.14.2 - resolution: "tsconfig-paths@npm:3.14.2" - dependencies: - "@types/json5": ^0.0.29 - json5: ^1.0.2 - minimist: ^1.2.6 - strip-bom: ^3.0.0 - checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 - languageName: node - linkType: hard - -"tslib@npm:^1.8.1": - version: 1.14.1 - resolution: "tslib@npm:1.14.1" - checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd - languageName: node - linkType: hard - -"tslib@npm:^2.0.3": - version: 2.6.2 - resolution: "tslib@npm:2.6.2" - checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad - languageName: node - linkType: hard - -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: ^1.8.1 - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: ^1.2.1 - checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a - languageName: node - linkType: hard - -"type-check@npm:~0.3.2": - version: 0.3.2 - resolution: "type-check@npm:0.3.2" - dependencies: - prelude-ls: ~1.1.2 - checksum: dd3b1495642731bc0e1fc40abe5e977e0263005551ac83342ecb6f4f89551d106b368ec32ad3fb2da19b3bd7b2d1f64330da2ea9176d8ddbfe389fb286eb5124 - languageName: node - linkType: hard - -"type-detect@npm:4.0.8": - version: 4.0.8 - resolution: "type-detect@npm:4.0.8" - checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 - languageName: node - linkType: hard - -"type-fest@npm:^0.16.0": - version: 0.16.0 - resolution: "type-fest@npm:0.16.0" - checksum: 1a4102c06dc109db00418c753062e206cab65befd469d000ece4452ee649bf2a9cf57686d96fb42326bc9d918d9a194d4452897b486dcc41989e5c99e4e87094 - languageName: node - linkType: hard - -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 - languageName: node - linkType: hard - -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 - languageName: node - linkType: hard - -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: 0.3.0 - mime-types: ~2.1.24 - checksum: 2c8e47675d55f8b4e404bcf529abdf5036c537a04c2b20177bcf78c9e3c1da69da3942b1346e6edb09e823228c0ee656ef0e033765ec39a70d496ef601a0c657 - languageName: node - linkType: hard - -"typed-array-buffer@npm:^1.0.0": - version: 1.0.0 - resolution: "typed-array-buffer@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.1 - is-typed-array: ^1.1.10 - checksum: 3e0281c79b2a40cd97fe715db803884301993f4e8c18e8d79d75fd18f796e8cd203310fec8c7fdb5e6c09bedf0af4f6ab8b75eb3d3a85da69328f28a80456bd3 - languageName: node - linkType: hard - -"typed-array-byte-length@npm:^1.0.0": - version: 1.0.0 - resolution: "typed-array-byte-length@npm:1.0.0" - dependencies: - call-bind: ^1.0.2 - for-each: ^0.3.3 - has-proto: ^1.0.1 - is-typed-array: ^1.1.10 - checksum: b03db16458322b263d87a702ff25388293f1356326c8a678d7515767ef563ef80e1e67ce648b821ec13178dd628eb2afdc19f97001ceae7a31acf674c849af94 - languageName: node - linkType: hard - -"typed-array-byte-offset@npm:^1.0.0": - version: 1.0.0 - resolution: "typed-array-byte-offset@npm:1.0.0" - dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - has-proto: ^1.0.1 - is-typed-array: ^1.1.10 - checksum: 04f6f02d0e9a948a95fbfe0d5a70b002191fae0b8fe0fe3130a9b2336f043daf7a3dda56a31333c35a067a97e13f539949ab261ca0f3692c41603a46a94e960b - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-length@npm:1.0.4" - dependencies: - call-bind: ^1.0.2 - for-each: ^0.3.3 - is-typed-array: ^1.1.9 - checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 - languageName: node - linkType: hard - -"typedarray-to-buffer@npm:^3.1.5": - version: 3.1.5 - resolution: "typedarray-to-buffer@npm:3.1.5" - dependencies: - is-typedarray: ^1.0.0 - checksum: 99c11aaa8f45189fcfba6b8a4825fd684a321caa9bd7a76a27cf0c7732c174d198b99f449c52c3818107430b5f41c0ccbbfb75cb2ee3ca4a9451710986d61a60 - languageName: node - linkType: hard - -"unbox-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "unbox-primitive@npm:1.0.2" - dependencies: - call-bind: ^1.0.2 - has-bigints: ^1.0.2 - has-symbols: ^1.0.3 - which-boxed-primitive: ^1.0.2 - checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 - languageName: node - linkType: hard - -"underscore@npm:1.12.1": - version: 1.12.1 - resolution: "underscore@npm:1.12.1" - checksum: ec327603aa112b99fe9d74cd9bf3b3b7451465a9d2610ceab269a532e3f191650ab017903be34dc86fe406a11d04d8905a3b04dd4c129493e51bee09a3f3074c - languageName: node - linkType: hard - -"unicode-canonical-property-names-ecmascript@npm:^2.0.0": - version: 2.0.0 - resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" - checksum: 39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 - languageName: node - linkType: hard - -"unicode-match-property-ecmascript@npm:^2.0.0": - version: 2.0.0 - resolution: "unicode-match-property-ecmascript@npm:2.0.0" - dependencies: - unicode-canonical-property-names-ecmascript: ^2.0.0 - unicode-property-aliases-ecmascript: ^2.0.0 - checksum: 1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a - languageName: node - linkType: hard - -"unicode-match-property-value-ecmascript@npm:^2.1.0": - version: 2.1.0 - resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" - checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220 - languageName: node - linkType: hard - -"unicode-property-aliases-ecmascript@npm:^2.0.0": - version: 2.1.0 - resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" - checksum: 243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: ^4.0.0 - checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: ^0.1.4 - checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 - languageName: node - linkType: hard - -"unique-string@npm:^2.0.0": - version: 2.0.0 - resolution: "unique-string@npm:2.0.0" - dependencies: - crypto-random-string: ^2.0.0 - checksum: ef68f639136bcfe040cf7e3cd7a8dff076a665288122855148a6f7134092e6ed33bf83a7f3a9185e46c98dddc445a0da6ac25612afa1a7c38b8b654d6c02498e - languageName: node - linkType: hard - -"universal-cookie@npm:^4.0.0": - version: 4.0.4 - resolution: "universal-cookie@npm:4.0.4" - dependencies: - "@types/cookie": ^0.3.3 - cookie: ^0.4.0 - checksum: bb2bafa7eb7e213e5448924329572dd1a913be00e23906189be2a0dc889b0eea1750f9c33462fc1c911d89092dbd82f6e220c2d61c4057bb3f69e7665d9d8ddf - languageName: node - linkType: hard - -"universalify@npm:^0.2.0": - version: 0.2.0 - resolution: "universalify@npm:0.2.0" - checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 - languageName: node - linkType: hard - -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 - languageName: node - linkType: hard - -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 - languageName: node - linkType: hard - -"unquote@npm:~1.1.1": - version: 1.1.1 - resolution: "unquote@npm:1.1.1" - checksum: 71745867d09cba44ba2d26cb71d6dda7045a98b14f7405df4faaf2b0c90d24703ad027a9d90ba9a6e0d096de2c8d56f864fd03f1c0498c0b7a3990f73b4c8f5f - languageName: node - linkType: hard - -"upath@npm:^1.2.0": - version: 1.2.0 - resolution: "upath@npm:1.2.0" - checksum: 4c05c094797cb733193a0784774dbea5b1889d502fc9f0572164177e185e4a59ba7099bf0b0adf945b232e2ac60363f9bf18aac9b2206fb99cbef971a8455445 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.0.13": - version: 1.0.13 - resolution: "update-browserslist-db@npm:1.0.13" - dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: ^2.1.0 - checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 - languageName: node - linkType: hard - -"url-parse@npm:^1.5.3": - version: 1.5.10 - resolution: "url-parse@npm:1.5.10" - dependencies: - querystringify: ^2.1.1 - requires-port: ^1.0.0 - checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - -"util.promisify@npm:~1.0.0": - version: 1.0.1 - resolution: "util.promisify@npm:1.0.1" - dependencies: - define-properties: ^1.1.3 - es-abstract: ^1.17.2 - has-symbols: ^1.0.1 - object.getownpropertydescriptors: ^2.1.0 - checksum: d823c75b3fc66510018596f128a6592c98991df38bc0464a633bdf9134e2de0a1a33199c5c21cc261048a3982d7a19e032ecff8835b3c587f843deba96063e37 - languageName: node - linkType: hard - -"utila@npm:~0.4": - version: 0.4.0 - resolution: "utila@npm:0.4.0" - checksum: 97ffd3bd2bb80c773429d3fb8396469115cd190dded1e733f190d8b602bd0a1bcd6216b7ce3c4395ee3c79e3c879c19d268dbaae3093564cb169ad1212d436f4 - languageName: node - linkType: hard - -"utils-merge@npm:1.0.1": - version: 1.0.1 - resolution: "utils-merge@npm:1.0.1" - checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df - languageName: node - linkType: hard - -"v8-to-istanbul@npm:^8.1.0": - version: 8.1.1 - resolution: "v8-to-istanbul@npm:8.1.1" - dependencies: - "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - source-map: ^0.7.3 - checksum: 54ce92bec2727879626f623d02c8d193f0c7e919941fa373ec135189a8382265117f5316ea317a1e12a5f9c13d84d8449052a731fe3306fa4beaafbfa4cab229 - languageName: node - linkType: hard - -"vary@npm:~1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b - languageName: node - linkType: hard - -"w3c-hr-time@npm:^1.0.2": - version: 1.0.2 - resolution: "w3c-hr-time@npm:1.0.2" - dependencies: - browser-process-hrtime: ^1.0.0 - checksum: ec3c2dacbf8050d917bbf89537a101a08c2e333b4c19155f7d3bedde43529d4339db6b3d049d9610789cb915f9515f8be037e0c54c079e9d4735c50b37ed52b9 - languageName: node - linkType: hard - -"w3c-xmlserializer@npm:^2.0.0": - version: 2.0.0 - resolution: "w3c-xmlserializer@npm:2.0.0" - dependencies: - xml-name-validator: ^3.0.0 - checksum: ae25c51cf71f1fb2516df1ab33a481f83461a117565b95e3d0927432522323f93b1b2846cbb60196d337970c421adb604fc2d0d180c6a47a839da01db5b9973b - languageName: node - linkType: hard - -"walker@npm:^1.0.7": - version: 1.0.8 - resolution: "walker@npm:1.0.8" - dependencies: - makeerror: 1.0.12 - checksum: ad7a257ea1e662e57ef2e018f97b3c02a7240ad5093c392186ce0bcf1f1a60bbadd520d073b9beb921ed99f64f065efb63dfc8eec689a80e569f93c1c5d5e16c - languageName: node - linkType: hard - -"watchpack@npm:^2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.1.2 - checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 - languageName: node - linkType: hard - -"wbuf@npm:^1.1.0, wbuf@npm:^1.7.3": - version: 1.7.3 - resolution: "wbuf@npm:1.7.3" - dependencies: - minimalistic-assert: ^1.0.0 - checksum: 2abc306c96930b757972a1c4650eb6b25b5d99f24088714957f88629e137db569368c5de0e57986c89ea70db2f1df9bba11a87cb6d0c8694b6f53a0159fab3bf - languageName: node - linkType: hard - -"web-vitals@npm:^2.1.4": - version: 2.1.4 - resolution: "web-vitals@npm:2.1.4" - checksum: 03d3f47dbf55c3dce07beb0ff5de8ddd52e2d0a53a8df5c84e7a16dda93543341d67231fa79b1d9772b091419af4ec0fd395b8bcf451a0e26846e3f76b3d0efc - languageName: node - linkType: hard - -"webidl-conversions@npm:^4.0.2": - version: 4.0.2 - resolution: "webidl-conversions@npm:4.0.2" - checksum: c93d8dfe908a0140a4ae9c0ebc87a33805b416a33ee638a605b551523eec94a9632165e54632f6d57a39c5f948c4bab10e0e066525e9a4b87a79f0d04fbca374 - languageName: node - linkType: hard - -"webidl-conversions@npm:^5.0.0": - version: 5.0.0 - resolution: "webidl-conversions@npm:5.0.0" - checksum: ccf1ec2ca7c0b5671e5440ace4a66806ae09c49016ab821481bec0c05b1b82695082dc0a27d1fe9d804d475a408ba0c691e6803fd21be608e710955d4589cd69 - languageName: node - linkType: hard - -"webidl-conversions@npm:^6.1.0": - version: 6.1.0 - resolution: "webidl-conversions@npm:6.1.0" - checksum: 1f526507aa491f972a0c1409d07f8444e1d28778dfa269a9971f2e157182f3d496dc33296e4ed45b157fdb3bf535bb90c90bf10c50dcf1dd6caacb2a34cc84fb - languageName: node - linkType: hard - -"webpack-dev-middleware@npm:^5.3.1": - version: 5.3.3 - resolution: "webpack-dev-middleware@npm:5.3.3" - dependencies: - colorette: ^2.0.10 - memfs: ^3.4.3 - mime-types: ^2.1.31 - range-parser: ^1.2.1 - schema-utils: ^4.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: dd332cc6da61222c43d25e5a2155e23147b777ff32fdf1f1a0a8777020c072fbcef7756360ce2a13939c3f534c06b4992a4d659318c4a7fe2c0530b52a8a6621 - languageName: node - linkType: hard - -"webpack-dev-server@npm:^4.6.0": - version: 4.15.1 - resolution: "webpack-dev-server@npm:4.15.1" - dependencies: - "@types/bonjour": ^3.5.9 - "@types/connect-history-api-fallback": ^1.3.5 - "@types/express": ^4.17.13 - "@types/serve-index": ^1.9.1 - "@types/serve-static": ^1.13.10 - "@types/sockjs": ^0.3.33 - "@types/ws": ^8.5.5 - ansi-html-community: ^0.0.8 - bonjour-service: ^1.0.11 - chokidar: ^3.5.3 - colorette: ^2.0.10 - compression: ^1.7.4 - connect-history-api-fallback: ^2.0.0 - default-gateway: ^6.0.3 - express: ^4.17.3 - graceful-fs: ^4.2.6 - html-entities: ^2.3.2 - http-proxy-middleware: ^2.0.3 - ipaddr.js: ^2.0.1 - launch-editor: ^2.6.0 - open: ^8.0.9 - p-retry: ^4.5.0 - rimraf: ^3.0.2 - schema-utils: ^4.0.0 - selfsigned: ^2.1.1 - serve-index: ^1.9.1 - sockjs: ^0.3.24 - spdy: ^4.0.2 - webpack-dev-middleware: ^5.3.1 - ws: ^8.13.0 - peerDependencies: - webpack: ^4.37.0 || ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - webpack-cli: - optional: true - bin: - webpack-dev-server: bin/webpack-dev-server.js - checksum: cd0063b068d2b938fd76c412d555374186ac2fa84bbae098265212ed50a5c15d6f03aa12a5a310c544a242943eb58c0bfde4c296d5c36765c182f53799e1bc71 - languageName: node - linkType: hard - -"webpack-manifest-plugin@npm:^4.0.2": - version: 4.1.1 - resolution: "webpack-manifest-plugin@npm:4.1.1" - dependencies: - tapable: ^2.0.0 - webpack-sources: ^2.2.0 - peerDependencies: - webpack: ^4.44.2 || ^5.47.0 - checksum: 426982030d3b0ef26432d98960ee1fa33889d8f0ed79b3d2c8e37be9b4e4beba7524c60631297ea557c642a340b76d70b0eb6a1e08b86a769409037185795038 - languageName: node - linkType: hard - -"webpack-sources@npm:^1.4.3": - version: 1.4.3 - resolution: "webpack-sources@npm:1.4.3" - dependencies: - source-list-map: ^2.0.0 - source-map: ~0.6.1 - checksum: 37463dad8d08114930f4bc4882a9602941f07c9f0efa9b6bc78738cd936275b990a596d801ef450d022bb005b109b9f451dd087db2f3c9baf53e8e22cf388f79 - languageName: node - linkType: hard - -"webpack-sources@npm:^2.2.0": - version: 2.3.1 - resolution: "webpack-sources@npm:2.3.1" - dependencies: - source-list-map: ^2.0.1 - source-map: ^0.6.1 - checksum: 6fd67f2274a84c5f51ad89767112ec8b47727134bf0f2ba0cff458c970f18966939a24128bdbddba621cd66eeb2bef0552642a9333cd8e54514f7b2a71776346 - languageName: node - linkType: hard - -"webpack-sources@npm:^3.2.3": - version: 3.2.3 - resolution: "webpack-sources@npm:3.2.3" - checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607 - languageName: node - linkType: hard - -"webpack@npm:^5.64.4": - version: 5.88.2 - resolution: "webpack@npm:5.88.2" - dependencies: - "@types/eslint-scope": ^3.7.3 - "@types/estree": ^1.0.0 - "@webassemblyjs/ast": ^1.11.5 - "@webassemblyjs/wasm-edit": ^1.11.5 - "@webassemblyjs/wasm-parser": ^1.11.5 - acorn: ^8.7.1 - acorn-import-assertions: ^1.9.0 - browserslist: ^4.14.5 - chrome-trace-event: ^1.0.2 - enhanced-resolve: ^5.15.0 - es-module-lexer: ^1.2.1 - eslint-scope: 5.1.1 - events: ^3.2.0 - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.2.9 - json-parse-even-better-errors: ^2.3.1 - loader-runner: ^4.2.0 - mime-types: ^2.1.27 - neo-async: ^2.6.2 - schema-utils: ^3.2.0 - tapable: ^2.1.1 - terser-webpack-plugin: ^5.3.7 - watchpack: ^2.4.0 - webpack-sources: ^3.2.3 - peerDependenciesMeta: - webpack-cli: - optional: true - bin: - webpack: bin/webpack.js - checksum: 79476a782da31a21f6dd38fbbd06b68da93baf6a62f0d08ca99222367f3b8668f5a1f2086b7bb78e23172e31fa6df6fa7ab09b25e827866c4fc4dc2b30443ce2 - languageName: node - linkType: hard - -"websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": - version: 0.7.4 - resolution: "websocket-driver@npm:0.7.4" - dependencies: - http-parser-js: ">=0.5.1" - safe-buffer: ">=5.1.0" - websocket-extensions: ">=0.1.1" - checksum: fffe5a33fe8eceafd21d2a065661d09e38b93877eae1de6ab5d7d2734c6ed243973beae10ae48c6613cfd675f200e5a058d1e3531bc9e6c5d4f1396ff1f0bfb9 - languageName: node - linkType: hard - -"websocket-extensions@npm:>=0.1.1": - version: 0.1.4 - resolution: "websocket-extensions@npm:0.1.4" - checksum: 5976835e68a86afcd64c7a9762ed85f2f27d48c488c707e67ba85e717b90fa066b98ab33c744d64255c9622d349eedecf728e65a5f921da71b58d0e9591b9038 - languageName: node - linkType: hard - -"whatwg-encoding@npm:^1.0.5": - version: 1.0.5 - resolution: "whatwg-encoding@npm:1.0.5" - dependencies: - iconv-lite: 0.4.24 - checksum: 5be4efe111dce29ddee3448d3915477fcc3b28f991d9cf1300b4e50d6d189010d47bca2f51140a844cf9b726e8f066f4aee72a04d687bfe4f2ee2767b2f5b1e6 - languageName: node - linkType: hard - -"whatwg-fetch@npm:^3.6.2": - version: 3.6.19 - resolution: "whatwg-fetch@npm:3.6.19" - checksum: 2896bc9ca867ea514392c73e2a272f65d5c4916248fe0837a9df5b1b92f247047bc76cf7c29c28a01ac6c5fb4314021d2718958c8a08292a96d56f72b2f56806 - languageName: node - linkType: hard - -"whatwg-mimetype@npm:^2.3.0": - version: 2.3.0 - resolution: "whatwg-mimetype@npm:2.3.0" - checksum: 23eb885940bcbcca4ff841c40a78e9cbb893ec42743993a42bf7aed16085b048b44b06f3402018931687153550f9a32d259dfa524e4f03577ab898b6965e5383 - languageName: node - linkType: hard - -"whatwg-url@npm:^7.0.0": - version: 7.1.0 - resolution: "whatwg-url@npm:7.1.0" - dependencies: - lodash.sortby: ^4.7.0 - tr46: ^1.0.1 - webidl-conversions: ^4.0.2 - checksum: fecb07c87290b47d2ec2fb6d6ca26daad3c9e211e0e531dd7566e7ff95b5b3525a57d4f32640ad4adf057717e0c215731db842ad761e61d947e81010e05cf5fd - languageName: node - linkType: hard - -"whatwg-url@npm:^8.0.0, whatwg-url@npm:^8.5.0": - version: 8.7.0 - resolution: "whatwg-url@npm:8.7.0" - dependencies: - lodash: ^4.7.0 - tr46: ^2.1.0 - webidl-conversions: ^6.1.0 - checksum: a87abcc6cefcece5311eb642858c8fdb234e51ec74196bfacf8def2edae1bfbffdf6acb251646ed6301f8cee44262642d8769c707256125a91387e33f405dd1e - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "which-boxed-primitive@npm:1.0.2" - dependencies: - is-bigint: ^1.0.1 - is-boolean-object: ^1.1.0 - is-number-object: ^1.0.4 - is-string: ^1.0.5 - is-symbol: ^1.0.3 - checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e - languageName: node - linkType: hard - -"which-builtin-type@npm:^1.1.3": - version: 1.1.3 - resolution: "which-builtin-type@npm:1.1.3" - dependencies: - function.prototype.name: ^1.1.5 - has-tostringtag: ^1.0.0 - is-async-function: ^2.0.0 - is-date-object: ^1.0.5 - is-finalizationregistry: ^1.0.2 - is-generator-function: ^1.0.10 - is-regex: ^1.1.4 - is-weakref: ^1.0.2 - isarray: ^2.0.5 - which-boxed-primitive: ^1.0.2 - which-collection: ^1.0.1 - which-typed-array: ^1.1.9 - checksum: 43730f7d8660ff9e33d1d3f9f9451c4784265ee7bf222babc35e61674a11a08e1c2925019d6c03154fcaaca4541df43abe35d2720843b9b4cbcebdcc31408f36 - languageName: node - linkType: hard - -"which-collection@npm:^1.0.1": - version: 1.0.1 - resolution: "which-collection@npm:1.0.1" - dependencies: - is-map: ^2.0.1 - is-set: ^2.0.1 - is-weakmap: ^2.0.1 - is-weakset: ^2.0.1 - checksum: c815bbd163107ef9cb84f135e6f34453eaf4cca994e7ba85ddb0d27cea724c623fae2a473ceccfd5549c53cc65a5d82692de418166df3f858e1e5dc60818581c - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.11, which-typed-array@npm:^1.1.9": - version: 1.1.11 - resolution: "which-typed-array@npm:1.1.11" - dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: 711ffc8ef891ca6597b19539075ec3e08bb9b4c2ca1f78887e3c07a977ab91ac1421940505a197758fb5939aa9524976d0a5bbcac34d07ed6faa75cedbb17206 - languageName: node - linkType: hard - -"which@npm:^1.3.1": - version: 1.3.1 - resolution: "which@npm:1.3.1" - dependencies: - isexe: ^2.0.0 - bin: - which: ./bin/which - checksum: f2e185c6242244b8426c9df1510e86629192d93c1a986a7d2a591f2c24869e7ffd03d6dac07ca863b2e4c06f59a4cc9916c585b72ee9fa1aa609d0124df15e04 - languageName: node - linkType: hard - -"which@npm:^2.0.1, which@npm:^2.0.2": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: ^2.0.0 - bin: - node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 - languageName: node - linkType: hard - -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 - languageName: node - linkType: hard - -"word-wrap@npm:~1.2.3": - version: 1.2.5 - resolution: "word-wrap@npm:1.2.5" - checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb - languageName: node - linkType: hard - -"workbox-background-sync@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-background-sync@npm:6.6.0" - dependencies: - idb: ^7.0.1 - workbox-core: 6.6.0 - checksum: ac2990110643aef62ca0be54e962296de7b09593b0262bd09fe4893978a42fa1f256c6d989ed472a31ae500b2255b80c6678530a6024eafb0b2f3a93a3c94a5f - languageName: node - linkType: hard - -"workbox-broadcast-update@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-broadcast-update@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: 46a74b3b703244eb363e1731a2d6fe1fb2cd9b82d454733dfc6941fd35b76a852685f56db92408383ac50d564c2fd4282f0c6c4db60ba9beb5f311ea8f944dc7 - languageName: node - linkType: hard - -"workbox-build@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-build@npm:6.6.0" - dependencies: - "@apideck/better-ajv-errors": ^0.3.1 - "@babel/core": ^7.11.1 - "@babel/preset-env": ^7.11.0 - "@babel/runtime": ^7.11.2 - "@rollup/plugin-babel": ^5.2.0 - "@rollup/plugin-node-resolve": ^11.2.1 - "@rollup/plugin-replace": ^2.4.1 - "@surma/rollup-plugin-off-main-thread": ^2.2.3 - ajv: ^8.6.0 - common-tags: ^1.8.0 - fast-json-stable-stringify: ^2.1.0 - fs-extra: ^9.0.1 - glob: ^7.1.6 - lodash: ^4.17.20 - pretty-bytes: ^5.3.0 - rollup: ^2.43.1 - rollup-plugin-terser: ^7.0.0 - source-map: ^0.8.0-beta.0 - stringify-object: ^3.3.0 - strip-comments: ^2.0.1 - tempy: ^0.6.0 - upath: ^1.2.0 - workbox-background-sync: 6.6.0 - workbox-broadcast-update: 6.6.0 - workbox-cacheable-response: 6.6.0 - workbox-core: 6.6.0 - workbox-expiration: 6.6.0 - workbox-google-analytics: 6.6.0 - workbox-navigation-preload: 6.6.0 - workbox-precaching: 6.6.0 - workbox-range-requests: 6.6.0 - workbox-recipes: 6.6.0 - workbox-routing: 6.6.0 - workbox-strategies: 6.6.0 - workbox-streams: 6.6.0 - workbox-sw: 6.6.0 - workbox-window: 6.6.0 - checksum: cd1a6c413659c2fd66f4438012f65b211cc748bb594c79bf0d9a60de0cefff3f8a4a23ab06f32c62064c37397ffffc1b77d3328658b7556ea7ff88e57f6ee4fd - languageName: node - linkType: hard - -"workbox-cacheable-response@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-cacheable-response@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: 9e4e00c53679fd2020874cbdf54bb17560fd12353120ea08ca6213e5a11bf08139072616d79f5f8ab80d09f00efde94b003fe9bf5b6e23815be30d7aca760835 - languageName: node - linkType: hard - -"workbox-core@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-core@npm:6.6.0" - checksum: 7d773a866b73a733780c52b895f9cf7bec926c9187395c307174deefba9a0a2fcd1edce0d1ca12b8a6c95ca9cf7755ccc1885b03bc82ebcfc4843e015bd84d7b - languageName: node - linkType: hard - -"workbox-expiration@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-expiration@npm:6.6.0" - dependencies: - idb: ^7.0.1 - workbox-core: 6.6.0 - checksum: b100b9c512754bc3e1a9c7c7d20d215d72c601a7b956333ca7753704a771a9f00e1732e9b774da4549bae390dd3cd138c6392f6a25fd67f7dcd84f89b0df7e9c - languageName: node - linkType: hard - -"workbox-google-analytics@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-google-analytics@npm:6.6.0" - dependencies: - workbox-background-sync: 6.6.0 - workbox-core: 6.6.0 - workbox-routing: 6.6.0 - workbox-strategies: 6.6.0 - checksum: 7b287da7517ae416aae8ea1494830bb517a29ab9786b2a8b8bf98971377b83715070e784399065ab101d4bba381ab0abbb8bd0962b3010bc01f54fdafb0b6702 - languageName: node - linkType: hard - -"workbox-navigation-preload@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-navigation-preload@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: d254465648e45ec6b6d7c3471354336501901d3872622ea9ba1aa1f935d4d52941d0f92fa6c06e7363e10dbac4874d5d4bff7d99cbe094925046f562a37e88cc - languageName: node - linkType: hard - -"workbox-precaching@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-precaching@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - workbox-routing: 6.6.0 - workbox-strategies: 6.6.0 - checksum: 62e5ee2e40568a56d4131bba461623579f56b9bd273aa7d2805e43151057f413c2ef32fb3d007aff0a5ac3ad84d5feae87408284249a487a5d51c3775c46c816 - languageName: node - linkType: hard - -"workbox-range-requests@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-range-requests@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: a55d1a364b2155548695dc8f6f85baade196d7d1bec980bcdbda80236803b14167995a81b944cffe932a94c4d556466773121afe3661a6f0a13403cbe96d8d9f - languageName: node - linkType: hard - -"workbox-recipes@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-recipes@npm:6.6.0" - dependencies: - workbox-cacheable-response: 6.6.0 - workbox-core: 6.6.0 - workbox-expiration: 6.6.0 - workbox-precaching: 6.6.0 - workbox-routing: 6.6.0 - workbox-strategies: 6.6.0 - checksum: f2ecf38502260703e4b0dcef67e3ac26d615f2c90f6d863ca7308db52454f67934ba842fd577ee807d9f510f1a277fd66af7caf57d39e50a181d05dbb3e550a7 - languageName: node - linkType: hard - -"workbox-routing@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-routing@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: 7a70b836196eb67332d33a94c0b57859781fe869e81a9c95452d3f4f368d3199f8c3da632dbc10425fde902a1930cf8cfd83f6434ad2b586904ce68cd9f35c6d - languageName: node - linkType: hard - -"workbox-strategies@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-strategies@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - checksum: 236232a77fb4a4847d1e9ae6c7c9bd9c6b9449209baab9d8d90f78240326a9c0f69551b408ebf9e76610d86da15563bf27439b7e885a7bac01dfd08047c0dd7b - languageName: node - linkType: hard - -"workbox-streams@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-streams@npm:6.6.0" - dependencies: - workbox-core: 6.6.0 - workbox-routing: 6.6.0 - checksum: 64a295e48e44e3fa4743b5baec646fc9117428e7592033475e38c461e45c294910712f322c32417d354b22999902ef8035119e070e61e159e531d878d991fc33 - languageName: node - linkType: hard - -"workbox-sw@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-sw@npm:6.6.0" - checksum: bb5f8695de02f89c7955465dcbd568299915565008dc8a068c5d19c1347f75d417640b9f61590e16b169b703e77d02f8b1e10c4b241f74f43cfe76175bfa5fed - languageName: node - linkType: hard - -"workbox-webpack-plugin@npm:^6.4.1": - version: 6.6.0 - resolution: "workbox-webpack-plugin@npm:6.6.0" - dependencies: - fast-json-stable-stringify: ^2.1.0 - pretty-bytes: ^5.4.1 - upath: ^1.2.0 - webpack-sources: ^1.4.3 - workbox-build: 6.6.0 - peerDependencies: - webpack: ^4.4.0 || ^5.9.0 - checksum: b8e04a342f2d45086f28ae56e4806d74dd153c3b750855533a55954f4e85752113e76a6d79a32206eb697a342725897834c9e7976894374d8698cd950477d37a - languageName: node - linkType: hard - -"workbox-window@npm:6.6.0": - version: 6.6.0 - resolution: "workbox-window@npm:6.6.0" - dependencies: - "@types/trusted-types": ^2.0.2 - workbox-core: 6.6.0 - checksum: bb1dd031c1525317ceffbdc3e4f502a70dce461fd6355146e1050c1090f3c640bf65edf42a5d2a3b91b4d0c313df32c1405d88bf701d44c0e3ebc492cd77fe14 - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: ^6.1.0 - string-width: ^5.0.1 - strip-ansi: ^7.0.1 - checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"write-file-atomic@npm:^3.0.0": - version: 3.0.3 - resolution: "write-file-atomic@npm:3.0.3" - dependencies: - imurmurhash: ^0.1.4 - is-typedarray: ^1.0.0 - signal-exit: ^3.0.2 - typedarray-to-buffer: ^3.1.5 - checksum: c55b24617cc61c3a4379f425fc62a386cc51916a9b9d993f39734d005a09d5a4bb748bc251f1304e7abd71d0a26d339996c275955f527a131b1dcded67878280 - languageName: node - linkType: hard - -"ws@npm:^7.4.6": - version: 7.5.9 - resolution: "ws@npm:7.5.9" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: c3c100a181b731f40b7f2fddf004aa023f79d64f489706a28bc23ff88e87f6a64b3c6651fbec3a84a53960b75159574d7a7385709847a62ddb7ad6af76f49138 - languageName: node - linkType: hard - -"ws@npm:^8.13.0": - version: 8.14.2 - resolution: "ws@npm:8.14.2" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b - languageName: node - linkType: hard - -"xml-name-validator@npm:^3.0.0": - version: 3.0.0 - resolution: "xml-name-validator@npm:3.0.0" - checksum: b3ac459afed783c285bb98e4960bd1f3ba12754fd4f2320efa0f9181ca28928c53cc75ca660d15d205e81f92304419afe94c531c7cfb3e0649aa6d140d53ecb0 - languageName: node - linkType: hard - -"xmlchars@npm:^2.2.0": - version: 2.2.0 - resolution: "xmlchars@npm:2.2.0" - checksum: 8c70ac94070ccca03f47a81fcce3b271bd1f37a591bf5424e787ae313fcb9c212f5f6786e1fa82076a2c632c0141552babcd85698c437506dfa6ae2d58723062 - languageName: node - linkType: hard - -"y18n@npm:^5.0.5": - version: 5.0.8 - resolution: "y18n@npm:5.0.8" - checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 - languageName: node - linkType: hard - -"yaml@npm:^1.10.0, yaml@npm:^1.10.2, yaml@npm:^1.7.2": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f - languageName: node - linkType: hard - -"yaml@npm:^2.1.1": - version: 2.3.2 - resolution: "yaml@npm:2.3.2" - checksum: acd80cc24df12c808c6dec8a0176d404ef9e6f08ad8786f746ecc9d8974968c53c6e8a67fdfabcc5f99f3dc59b6bb0994b95646ff03d18e9b1dcd59eccc02146 - languageName: node - linkType: hard - -"yargs-parser@npm:^20.2.2": - version: 20.2.9 - resolution: "yargs-parser@npm:20.2.9" - checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 - languageName: node - linkType: hard - -"yargs@npm:^16.2.0": - version: 16.2.0 - resolution: "yargs@npm:16.2.0" - dependencies: - cliui: ^7.0.2 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.0 - y18n: ^5.0.5 - yargs-parser: ^20.2.2 - checksum: b14afbb51e3251a204d81937c86a7e9d4bdbf9a2bcee38226c900d00f522969ab675703bee2a6f99f8e20103f608382936034e64d921b74df82b63c07c5e8f59 - languageName: node - linkType: hard - -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 - languageName: node - linkType: hard From 807215a0cb04376a5bc79df52874fc3865b6c08c Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Wed, 27 Sep 2023 18:13:07 +0300 Subject: [PATCH 027/362] Web:Client:OAuth: fix mobx warning, add infinity list for table view --- .../developer-tools/OAuth/OAuth.types.ts | 2 +- .../developer-tools/OAuth/index.tsx | 4 +- .../sub-components/List/TableView/Header.tsx | 11 +- .../sub-components/List/TableView/Row.tsx | 145 ++---------- .../List/TableView/TableView.styled.ts | 98 ++++++++ .../List/TableView/TableView.types.ts | 46 ++++ .../List/TableView/columns/name.tsx | 4 +- .../sub-components/List/TableView/index.tsx | 105 ++++----- packages/client/src/store/OAuthStore.ts | 219 ++++++++++++++++-- public/locales/en/Common.json | 1 + 10 files changed, 423 insertions(+), 212 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.styled.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.types.ts diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts index e1f640dcb8..3967c65ba9 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/OAuth.types.ts @@ -8,5 +8,5 @@ export interface OAuthProps { viewAs: ViewAsType; clientList: ClientProps[]; isEmptyClientList: boolean; - fetchClients: (page: number) => Promise; + fetchClients: () => Promise; } diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx index ea8bfb3162..b38195c53f 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/index.tsx @@ -24,8 +24,8 @@ const OAuth = ({ const [isLoading, setIsLoading] = React.useState(true); const startLoadingRef = React.useRef(null); - const getClientList = React.useCallback(async (page = 0) => { - await fetchClients(page); + const getClientList = React.useCallback(async () => { + await fetchClients(); if (startLoadingRef.current) { const currentDate = new Date(); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.tsx index d66f945eee..dd10613ec7 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Header.tsx @@ -1,18 +1,9 @@ -import React from "react"; import { useTranslation } from "react-i18next"; -import { inject, observer } from "mobx-react"; //@ts-ignore import TableHeader from "@docspace/components/table-container/TableHeader"; -const TABLE_VERSION = "1"; -const TABLE_COLUMNS = `oauthConfigColumns_ver-${TABLE_VERSION}`; - -interface HeaderProps { - sectionWidth: number; - tableRef: HTMLDivElement; - columnStorageName: string; -} +import { HeaderProps } from "./TableView.types"; const Header = (props: HeaderProps) => { const { sectionWidth, tableRef, columnStorageName } = props; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx index 64803a870f..c6dfdf7a9c 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx @@ -1,118 +1,31 @@ -import React from "react"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import styled, { css } from "styled-components"; - -//@ts-ignore -import TableRow from "@docspace/components/table-container/TableRow"; //@ts-ignore import TableCell from "@docspace/components/table-container/TableCell"; import Text from "@docspace/components/text"; import ToggleButton from "@docspace/components/toggle-button"; -import { Base } from "@docspace/components/themes"; - -import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; -import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; - -import { ClientProps } from "@docspace/common/utils/oauth/interfaces"; import NameCell from "./columns/name"; -const StyledWrapper = styled.div` - display: contents; -`; - -const StyledTableRow = styled(TableRow)` - .table-container_cell { - text-overflow: ellipsis; - - padding-right: 8px; - } - - .mr-8 { - margin-right: 8px; - } - - .textOverflow { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .toggleButton { - display: contents; - - input { - position: relative; - - margin-left: -8px; - } - } - - .table-container_row-loader { - margin-left: 8px; - margin-right: 16px; - } - - :hover { - .table-container_cell { - cursor: pointer; - background: ${(props) => - `${props.theme.filesSection.tableView.row.backgroundActive} !important`}; - - margin-top: -1px; - - border-top: ${(props) => - `1px solid ${props.theme.filesSection.tableView.row.borderColor}`}; - } - - .table-container_file-name-cell { - ${(props) => - props.theme.interfaceDirection === "rtl" - ? css` - margin-right: -24px; - padding-right: 24px; - ` - : css` - margin-left: -24px; - padding-left: 24px; - `} - } - .table-container_row-context-menu-wrapper { - ${(props) => - props.theme.interfaceDirection === "rtl" - ? css` - margin-left: -20px; - padding-left: 18px; - ` - : css` - margin-right: -20px; - padding-right: 18px; - `} - } - } -`; - -StyledTableRow.defaultProps = { theme: Base }; - -interface RowProps { - item: ClientProps; - isChecked: boolean; - inProgress: boolean; - setSelection?: (clientId: string) => void; - changeClientStatus?: (clientId: string, status: boolean) => Promise; -} +import { StyledRowWrapper, StyledTableRow } from "./TableView.styled"; +import { RowProps } from "./TableView.types"; const Row = (props: RowProps) => { - const { item, changeClientStatus, isChecked, inProgress, setSelection } = - props; + const { + item, + changeClientStatus, + isChecked, + inProgress, + getContextMenuItems, + setSelection, + } = props; const navigate = useNavigate(); const { t } = useTranslation(["Webhooks", "Common"]); const editClient = () => { - navigate(window.location.pathname + `/${item.clientId}`); + navigate(`${item.clientId}`); }; const handleToggleEnabled = async () => { @@ -120,45 +33,31 @@ const Row = (props: RowProps) => { await changeClientStatus(item.clientId, !item.enabled); }; - const onDeleteOpen = () => {}; - const handleRowClick = (e: any) => { if ( e.target.closest(".checkbox") || e.target.closest(".table-container_row-checkbox") || - e.target.closest(".type-combobox") || - e.target.closest(".table-container_row-context-menu-wrapper") || - e.target.closest(".toggleButton") || e.detail === 0 ) { return; } + if ( + e.target.closest(".type-combobox") || + e.target.closest(".table-container_row-context-menu-wrapper") || + e.target.closest(".toggleButton") + ) { + return setSelection && setSelection(""); + } + editClient(); }; - const contextOptions = [ - { - key: "settings", - label: t("Common:Settings"), - icon: SettingsIcon, - onClick: editClient, - }, - { - key: "Separator dropdownItem", - isSeparator: true, - }, - { - key: "delete", - label: t("Common:Delete"), - icon: DeleteIcon, - onClick: onDeleteOpen, - }, - ]; + const contextOptions = getContextMenuItems && getContextMenuItems(t, item); return ( <> - + { />
- + ); }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.styled.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.styled.ts new file mode 100644 index 0000000000..b9d53df1b0 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.styled.ts @@ -0,0 +1,98 @@ +import styled, { css } from "styled-components"; + +//@ts-ignore +import TableContainer from "@docspace/components/table-container/TableContainer"; +//@ts-ignore +import TableRow from "@docspace/components/table-container/TableRow"; +import { Base } from "@docspace/components/themes"; + +export const TableWrapper = styled(TableContainer)` + margin-top: 0px; + + .header-container-text { + font-size: 12px; + } + + .table-container_header { + position: absolute; + } +`; + +const StyledRowWrapper = styled.div` + display: contents; +`; + +const StyledTableRow = styled(TableRow)` + .table-container_cell { + text-overflow: ellipsis; + + padding-right: 8px; + } + + .mr-8 { + margin-right: 8px; + } + + .textOverflow { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .toggleButton { + display: contents; + + input { + position: relative; + + margin-left: -8px; + } + } + + .table-container_row-loader { + margin-left: 8px; + margin-right: 16px; + } + + :hover { + .table-container_cell { + cursor: pointer; + background: ${(props) => + `${props.theme.filesSection.tableView.row.backgroundActive} !important`}; + + margin-top: -1px; + + border-top: ${(props) => + `1px solid ${props.theme.filesSection.tableView.row.borderColor}`}; + } + + .table-container_file-name-cell { + ${(props) => + props.theme.interfaceDirection === "rtl" + ? css` + margin-right: -24px; + padding-right: 24px; + ` + : css` + margin-left: -24px; + padding-left: 24px; + `} + } + .table-container_row-context-menu-wrapper { + ${(props) => + props.theme.interfaceDirection === "rtl" + ? css` + margin-left: -20px; + padding-left: 18px; + ` + : css` + margin-right: -20px; + padding-right: 18px; + `} + } + } +`; + +StyledTableRow.defaultProps = { theme: Base }; + +export { StyledRowWrapper, StyledTableRow }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.types.ts new file mode 100644 index 0000000000..9fea246cb4 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/TableView.types.ts @@ -0,0 +1,46 @@ +import { ClientProps } from "@docspace/common/utils/oauth/interfaces"; + +//@ts-ignore +import { ViewAsType } from "SRC_DIR/store/OAuthStore"; + +export interface TableViewProps { + items: ClientProps[]; + sectionWidth: number; + viewAs?: ViewAsType; + setViewAs?: (value: ViewAsType) => void; + userId?: string; + selection?: string[]; + setSelection?: (clientId: string) => void; + getContextMenuItems?: ( + t: any, + item: ClientProps + ) => { + [key: string]: any | string | boolean | ((clientId: string) => void); + }[]; + bufferSelection?: ClientProps | null; + activeClients?: string[]; + hasNextPage?: boolean; + totalElements?: number; + fetchNextClients?: (startIndex: number) => Promise; + changeClientStatus?: (clientId: string, status: boolean) => Promise; +} + +export interface HeaderProps { + sectionWidth: number; + tableRef: HTMLDivElement; + columnStorageName: string; +} + +export interface RowProps { + item: ClientProps; + isChecked: boolean; + inProgress: boolean; + getContextMenuItems?: ( + t: any, + item: ClientProps + ) => { + [key: string]: any | string | boolean | ((clientId: string) => void); + }[]; + setSelection?: (clientId: string) => void; + changeClientStatus?: (clientId: string, status: boolean) => Promise; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/columns/name.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/columns/name.tsx index a678abc0b3..3dd219f7bf 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/columns/name.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/columns/name.tsx @@ -24,8 +24,8 @@ const StyledImage = styled.img` interface NameCellProps { name: string; - icon?: string; clientId: string; + icon?: string; inProgress?: boolean; isChecked?: boolean; setSelection?: (clientId: string) => void; @@ -39,7 +39,7 @@ const NameCell = ({ isChecked, setSelection, }: NameCellProps) => { - const onChange = (e: React.ChangeEvent) => { + const onChange = () => { setSelection && setSelection(clientId); }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.tsx index 0c81652cd9..57ded5a611 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/index.tsx @@ -1,66 +1,35 @@ import React from "react"; import { inject, observer } from "mobx-react"; import { isMobile } from "react-device-detect"; -import styled from "styled-components"; -import { ClientProps } from "@docspace/common/utils/oauth/interfaces"; - -//@ts-ignore -import TableContainer from "@docspace/components/table-container/TableContainer"; //@ts-ignore import TableBody from "@docspace/components/table-container/TableBody"; //@ts-ignore -import { OAuthStoreProps, ViewAsType } from "SRC_DIR/store/OAuthStore"; +import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore"; import Row from "./Row"; import Header from "./Header"; -const TableWrapper = styled(TableContainer)` - margin-top: 0px; - - .header-container-text { - font-size: 12px; - } - - .table-container_header { - position: absolute; - } -`; +import { TableViewProps } from "./TableView.types"; +import { TableWrapper } from "./TableView.styled"; const TABLE_VERSION = "1"; const COLUMNS_SIZE = `oauthConfigColumnsSize_ver-${TABLE_VERSION}`; -interface TableViewProps { - items: ClientProps[]; - sectionWidth: number; - viewAs?: ViewAsType; - setViewAs?: (value: ViewAsType) => void; - userId?: string; - selection?: string[]; - setSelection?: (clientId: string) => void; - - bufferSelection?: ClientProps | null; - currentClient?: ClientProps | null; - setBufferSelection?: (clientId: string) => void; - changeClientStatus?: (clientId: string, status: boolean) => Promise; -} - const TableView = ({ items, - sectionWidth, - viewAs, setViewAs, - selection, - bufferSelection, - + activeClients, setSelection, - + getContextMenuItems, changeClientStatus, - userId, + hasNextPage, + totalElements, + fetchNextClients, }: TableViewProps) => { const tableRef = React.useRef(null); @@ -73,6 +42,29 @@ const TableView = ({ } }, [sectionWidth, viewAs, setViewAs]); + const clickOutside = React.useCallback( + (e: any) => { + if ( + e.target.closest(".checkbox") || + e.target.closest(".table-container_row-checkbox") || + e.detail === 0 + ) { + return; + } + + setSelection && setSelection(""); + }, + [setSelection] + ); + + React.useEffect(() => { + window.addEventListener("click", clickOutside); + + return () => { + window.removeEventListener("click", clickOutside); + }; + }, [clickOutside, setSelection]); + const columnStorageName = `${COLUMNS_SIZE}=${userId}`; return ( @@ -88,18 +80,24 @@ const TableView = ({ useReactWindow columnStorageName={columnStorageName} filesLength={items.length} - fetchMoreFiles={() => console.log("call")} - hasMoreFiles={false} - itemCount={items.length} + fetchMoreFiles={({ + startIndex, + }: { + startIndex: number; + stopIndex: number; + }) => fetchNextClients && fetchNextClients(startIndex)} + hasMoreFiles={hasNextPage} + itemCount={totalElements} > - {items.map((item, index) => ( + {items.map((item) => ( ))} @@ -115,26 +113,29 @@ export default inject( viewAs, setViewAs, selection, - bufferSelection, - setSelection, setBufferSelection, - changeClientStatus, - - currentClient, + getContextMenuItems, + activeClients, + hasNextPage, + totalElements, + fetchNextClients, } = oauthStore; + return { viewAs, setViewAs, userId, changeClientStatus, selection, - bufferSelection, - setSelection, setBufferSelection, - currentClient, + activeClients, + getContextMenuItems, + hasNextPage, + totalElements, + fetchNextClients, }; } )(observer(TableView)); diff --git a/packages/client/src/store/OAuthStore.ts b/packages/client/src/store/OAuthStore.ts index f329704e41..0e77e09411 100644 --- a/packages/client/src/store/OAuthStore.ts +++ b/packages/client/src/store/OAuthStore.ts @@ -1,4 +1,4 @@ -import { makeAutoObservable } from "mobx"; +import { makeAutoObservable, runInAction } from "mobx"; //@ts-ignore import { getPortal } from "@docspace/common/api/portal"; @@ -21,19 +21,37 @@ import { Scope, } from "@docspace/common/utils/oauth/interfaces"; +import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url"; +import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url"; +import EnableReactSvgUrl from "PUBLIC_DIR/images/enable.react.svg?url"; +import RemoveReactSvgUrl from "PUBLIC_DIR/images/remove.react.svg?url"; + const PAGE_LIMIT = 20; export type ViewAsType = "table" | "row"; export interface OAuthStoreProps { viewAs: ViewAsType; + setViewAs: (value: "table" | "row") => void; deleteDialogVisible: boolean; setDeleteDialogVisible: (value: boolean) => void; + editClient: (clientId: string) => void; + clients: ClientProps[]; + fetchClient: (clientId: string) => Promise; + fetchClients: () => Promise; + fetchNextClients: (startIndex: number) => Promise; + saveClient: (client: ClientProps) => Promise; + updateClient: (clientId: string, client: ClientProps) => Promise; + changeClientStatus: (clientId: string, status: boolean) => Promise; + regenerateSecret: (clientId: string) => Promise; + deleteClient: (clientId: string) => Promise; + currentPage: number; totalPages: number; + totalElements: number; selection: string[]; setSelection: (clientId: string) => void; @@ -44,21 +62,20 @@ export interface OAuthStoreProps { tenant: number; fetchTenant: () => Promise; + activeClients: string[]; + setActiveClient: (clientId: string) => void; + scopes: Scope[]; - - setViewAs: (value: "table" | "row") => void; - - fetchClient: (clientId: string) => Promise; - fetchClients: (page: number) => Promise; - saveClient: (client: ClientProps) => Promise; - updateClient: (clientId: string, client: ClientProps) => Promise; - changeClientStatus: (clientId: string, status: boolean) => Promise; - regenerateSecret: (clientId: string) => Promise; - deleteClient: (clientId: string) => Promise; - fetchScope: (name: string) => Promise; fetchScopes: () => Promise; + getContextMenuItems: ( + t: any, + item: ClientProps + ) => { + [key: string]: any | string | boolean | ((clientId: string) => void); + }[]; + clientList: ClientProps[]; isEmptyClientList: boolean; hasNextPage: boolean; @@ -70,6 +87,7 @@ class OAuthStore implements OAuthStoreProps { currentPage: number = 0; totalPages: number = 0; + totalElements: number = 0; deleteDialogVisible: boolean = false; @@ -81,6 +99,8 @@ class OAuthStore implements OAuthStoreProps { clients: ClientProps[] = []; + activeClients: string[] = []; + scopes: Scope[] = []; constructor() { @@ -96,10 +116,14 @@ class OAuthStore implements OAuthStoreProps { }; setSelection = (clientId: string) => { - if (this.selection.includes(clientId)) { - this.selection = this.selection.filter((s) => s !== clientId); + if (!clientId) { + this.selection = []; } else { - this.selection.push(clientId); + if (this.selection.includes(clientId)) { + this.selection = this.selection.filter((s) => s !== clientId); + } else { + this.selection.push(clientId); + } } }; @@ -111,6 +135,25 @@ class OAuthStore implements OAuthStoreProps { } }; + setActiveClient = (clientId: string) => { + if (!clientId) { + this.activeClients = []; + } else { + if (this.activeClients.includes(clientId)) { + this.activeClients = this.activeClients.filter((s) => s !== clientId); + } else { + this.activeClients.push(clientId); + } + } + }; + + editClient = (clientId: string) => { + //@ts-ignore + window?.DocSpace?.navigate( + `/portal-settings/developer-tools/oauth/${clientId}` + ); + }; + fetchTenant = async () => { if (this.tenant > -1) return this.tenant; @@ -130,27 +173,52 @@ class OAuthStore implements OAuthStoreProps { } }; - fetchClients = async (page: number) => { + fetchClients = async () => { try { + runInAction(() => { + this.currentPage = 1; + }); + const clientList: ClientListProps = await getClientList(0, PAGE_LIMIT); - this.totalPages = clientList.totalPages; - this.currentPage = page; - this.clients = clientList.content; + runInAction(() => { + this.totalPages = clientList.totalPages; + + this.totalElements = clientList.totalElements; + this.clients = clientList.content; + }); } catch (e) { console.log(e); } }; + fetchNextClients = async (startIndex: number) => { + const page = startIndex / PAGE_LIMIT; + runInAction(() => { + this.currentPage = page + 1; + }); + const clientList: ClientListProps = await getClientList(page, PAGE_LIMIT); + + runInAction(() => { + this.totalPages = clientList.totalPages; + + this.totalElements = clientList.totalElements; + this.clients = [...this.clients, ...clientList.content]; + }); + }; + //TODO: OAuth, add tenant and other params saveClient = async (client: ClientProps) => { try { client.tenant = 1; client.authenticationMethod = "zxc"; client.termsUrl = "zxc"; + const newClient = await addClient(client); - this.clients.push(newClient); + runInAction(() => { + this.clients.push(newClient); + }); } catch (e) { console.log(e); } @@ -163,7 +231,9 @@ class OAuthStore implements OAuthStoreProps { const idx = this.clients.findIndex((c) => c.clientId === clientId); if (idx > -1) { - this.clients[idx] = newClient; + runInAction(() => { + this.clients[idx] = newClient; + }); } } catch (e) { console.log(e); @@ -177,7 +247,9 @@ class OAuthStore implements OAuthStoreProps { const idx = this.clients.findIndex((c) => c.clientId === clientId); if (idx > -1) { - this.clients[idx] = { ...this.clients[idx], enabled: status }; + runInAction(() => { + this.clients[idx] = { ...this.clients[idx], enabled: status }; + }); } } catch (e) { console.log(e); @@ -222,6 +294,109 @@ class OAuthStore implements OAuthStoreProps { } }; + getContextMenuItems = (t: any, item: ClientProps) => { + const { clientId } = item; + + const isGroupContext = this.selection.length; + + const onDelete = () => { + if (!isGroupContext) { + this.setBufferSelection(clientId); + } + + this.setDeleteDialogVisible(true); + }; + + const onEnable = async (status: boolean) => { + if (isGroupContext) { + try { + const actions: Promise[] = []; + + this.selection.forEach((s) => { + this.setActiveClient(s); + actions.push(this.changeClientStatus(s, status)); + }); + + await Promise.all(actions); + + runInAction(() => { + this.activeClients = []; + this.selection = []; + }); + + //TODO OAuth, show toast + } catch (e) {} + } else { + this.setActiveClient(clientId); + + await this.changeClientStatus(clientId, status); + + //TODO OAuth, show toast + } + }; + + const settingsOption = { + key: "settings", + icon: SettingsIcon, + label: t("Common:Settings"), + onClick: () => this.editClient(clientId), + }; + + const enableOption = { + key: "enable", + icon: EnableReactSvgUrl, + label: t("Common:Enable"), + onClick: () => onEnable(true), + }; + + const disableOption = { + key: "disable", + icon: RemoveReactSvgUrl, + label: t("Common:Disable"), + onClick: () => onEnable(false), + }; + + const contextOptions = [ + { + key: "Separator dropdownItem", + isSeparator: true, + }, + { + key: "delete", + label: t("Common:Delete"), + icon: DeleteIcon, + onClick: () => onDelete(), + }, + ]; + + if (isGroupContext) { + let enabled = false; + + this.selection.forEach((s) => { + enabled = + enabled || + this.clientList.find((client) => client.clientId === s)?.enabled || + false; + }); + + if (enabled) { + contextOptions.unshift(disableOption); + } else { + contextOptions.unshift(enableOption); + } + } else { + if (item.enabled) { + contextOptions.unshift(disableOption); + } else { + contextOptions.unshift(enableOption); + } + + contextOptions.unshift(settingsOption); + } + + return contextOptions; + }; + get clientList() { return this.clients; } diff --git a/public/locales/en/Common.json b/public/locales/en/Common.json index e14ceaa88d..d85d62bca9 100644 --- a/public/locales/en/Common.json +++ b/public/locales/en/Common.json @@ -92,6 +92,7 @@ "Delete": "Delete", "DescriptionOfTheEveryoneRole": "The form is available for filling out by all participants of this room.", "DescriptionOfTheRoleQueue": "Each form filled out by users from the first role will go in turn to the next users listed below.", + "Disable": "Disable", "Disconnect": "Disconnect", "DocSpaceAdmin": "DocSpace admin", "DocSpaceOwner": "DocSpace owner", From ca73c5b0c41c8bdcb8ebf41e24775860485b6d4b Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Thu, 28 Sep 2023 10:21:43 +0300 Subject: [PATCH 028/362] Web:Client:OAuth: add row view --- .../OAuth/sub-components/List/RowView/Row.tsx | 85 ++++++++++++++++ .../List/RowView/RowContent.tsx | 57 +++++++++++ .../List/RowView/RowView.styled.ts | 67 +++++++++++++ .../List/RowView/RowView.types.ts | 49 +++++++++ .../sub-components/List/RowView/index.tsx | 99 +++++++++++++++++++ .../sub-components/List/TableView/Row.tsx | 2 +- .../OAuth/sub-components/List/index.tsx | 9 +- packages/client/src/store/OAuthStore.ts | 35 +++++-- 8 files changed, 392 insertions(+), 11 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.tsx create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.styled.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.types.ts create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.tsx diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.tsx new file mode 100644 index 0000000000..62328b4895 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/Row.tsx @@ -0,0 +1,85 @@ +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +//@ts-ignore +import Row from "@docspace/components/row"; +import ToggleButton from "@docspace/components/toggle-button"; + +import { RowContent } from "./RowContent"; +import { RowProps } from "./RowView.types"; + +export const OAuthRow = (props: RowProps) => { + const { + item, + sectionWidth, + changeClientStatus, + isChecked, + inProgress, + getContextMenuItems, + setSelection, + } = props; + const navigate = useNavigate(); + + const { t } = useTranslation(["Common"]); + + const editClient = () => { + navigate(`${item.clientId}`); + }; + + const handleToggleEnabled = async () => { + if (!changeClientStatus) return; + await changeClientStatus(item.clientId, !item.enabled); + }; + + const handleRowClick = (e: any) => { + if ( + e.target.closest(".checkbox") || + e.target.closest(".table-container_row-checkbox") || + e.detail === 0 + ) { + return; + } + + if ( + e.target.closest(".table-container_row-context-menu-wrapper") || + e.target.closest(".toggleButton") || + e.target.closest(".row_context-menu-wrapper") + ) { + return setSelection && setSelection(""); + } + + editClient(); + }; + + const contextOptions = getContextMenuItems && getContextMenuItems(t, item); + + const element = {"App; + + return ( + <> + setSelection && setSelection(item.clientId)} + > + + + + ); +}; + +export default OAuthRow; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.tsx new file mode 100644 index 0000000000..e4f0ac6269 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowContent.tsx @@ -0,0 +1,57 @@ +import React from "react"; + +import Text from "@docspace/components/text"; + +import ToggleButton from "@docspace/components/toggle-button"; + +import { isMobileOnly } from "react-device-detect"; + +import { + StyledRowContent, + ContentWrapper, + FlexWrapper, + ToggleButtonWrapper, +} from "./RowView.styled"; +import { RowContentProps } from "./RowView.types"; + +export const RowContent = ({ + sectionWidth, + item, + + handleToggleEnabled, +}: RowContentProps) => { + return ( + + + + {/* @ts-ignore */} + + {item.name} + + + + {!isMobileOnly && ( + <> + {/* @ts-ignore */} + + {item.description} + + + )} + + + + + + + ); +}; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.styled.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.styled.ts new file mode 100644 index 0000000000..0e1a142fb9 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.styled.ts @@ -0,0 +1,67 @@ +import styled from "styled-components"; + +//@ts-ignore +import RowContainer from "@docspace/components/row-container"; +//@ts-ignore +import RowContent from "@docspace/components/row-content"; + +export const StyledRowContainer = styled(RowContainer)` + margin-top: 0px; + + .row-list-item { + padding-left: 21px; + } + + .row-loader { + width: calc(100% - 46px) !important; + padding-left: 21px; + } + + img { + width: 32px; + max-width: 32px; + + height: 32px; + max-height: 32px; + } +`; + +export const StyledRowContent = styled(RowContent)` + display: flex; + padding-bottom: 10px; + + .rowMainContainer { + height: 100%; + width: 100%; + } + + .mainIcons { + min-width: 76px; + } +`; + +export const ContentWrapper = styled.div` + display: flex; + flex-direction: column; + justify-items: center; +`; + +export const ToggleButtonWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; + + label { + margin-top: 1px; + position: relative; + gap: 0px; + + margin-right: -8px; + } +`; + +export const FlexWrapper = styled.div` + display: flex; +`; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.types.ts new file mode 100644 index 0000000000..fc3ab07033 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/RowView.types.ts @@ -0,0 +1,49 @@ +import { ClientProps } from "@docspace/common/utils/oauth/interfaces"; + +//@ts-ignore +import { ViewAsType } from "SRC_DIR/store/OAuthStore"; + +export interface RowViewProps { + items: ClientProps[]; + sectionWidth: number; + viewAs?: ViewAsType; + setViewAs?: (value: ViewAsType) => void; + selection?: string[]; + setSelection?: (clientId: string) => void; + getContextMenuItems?: ( + t: any, + item: ClientProps + ) => { + [key: string]: any | string | boolean | ((clientId: string) => void); + }[]; + activeClients?: string[]; + hasNextPage?: boolean; + totalElements?: number; + fetchNextClients?: (startIndex: number) => Promise; + changeClientStatus?: (clientId: string, status: boolean) => Promise; +} + +export interface RowProps { + item: ClientProps; + isChecked: boolean; + inProgress: boolean; + sectionWidth: number; + getContextMenuItems?: ( + t: any, + item: ClientProps + ) => { + [key: string]: any | string | boolean | ((clientId: string) => void); + }[]; + setSelection?: (clientId: string) => void; + changeClientStatus?: (clientId: string, status: boolean) => Promise; +} + +export interface RowContentProps { + sectionWidth: number; + item: ClientProps; + isChecked: boolean; + inProgress: boolean; + handleToggleEnabled: () => void; + setSelection?: (clientId: string) => void; + changeClientStatus?: (clientId: string, status: boolean) => Promise; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.tsx new file mode 100644 index 0000000000..d4e2a1d166 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/RowView/index.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import { inject, observer } from "mobx-react"; +import { isMobile } from "react-device-detect"; + +//@ts-ignore +import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore"; + +import OAuthRow from "./Row"; + +import { RowViewProps } from "./RowView.types"; +import { StyledRowContainer } from "./RowView.styled"; + +const RowView = (props: RowViewProps) => { + const { + items, + sectionWidth, + viewAs, + setViewAs, + + changeClientStatus, + selection, + setSelection, + + activeClients, + getContextMenuItems, + hasNextPage, + totalElements, + fetchNextClients, + } = props; + + React.useEffect(() => { + if (viewAs !== "table" && viewAs !== "row") return; + + if (sectionWidth < 1025 || isMobile) { + viewAs !== "row" && setViewAs && setViewAs("row"); + } else { + viewAs !== "table" && setViewAs && setViewAs("table"); + } + }, [viewAs, setViewAs, sectionWidth]); + + return ( + fetchNextClients && fetchNextClients(startIndex)} + hasMoreFiles={hasNextPage} + itemCount={totalElements} + useReactWindow={true} + > + {items.map((item) => ( + + ))} + + ); +}; + +export default inject( + ({ oauthStore }: { auth: any; oauthStore: OAuthStoreProps }) => { + const { + viewAs, + setViewAs, + selection, + setSelection, + changeClientStatus, + getContextMenuItems, + activeClients, + hasNextPage, + totalElements, + fetchNextClients, + } = oauthStore; + + return { + viewAs, + setViewAs, + changeClientStatus, + selection, + setSelection, + activeClients, + getContextMenuItems, + hasNextPage, + totalElements, + fetchNextClients, + }; + } +)(observer(RowView)); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx index c6dfdf7a9c..33159e68a4 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/TableView/Row.tsx @@ -22,7 +22,7 @@ const Row = (props: RowProps) => { } = props; const navigate = useNavigate(); - const { t } = useTranslation(["Webhooks", "Common"]); + const { t } = useTranslation(["Common"]); const editClient = () => { navigate(`${item.clientId}`); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.tsx index cfb38ade3a..c2921094c7 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.tsx +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/List/index.tsx @@ -11,6 +11,8 @@ import { Consumer } from "@docspace/components/utils/context"; import { ViewAsType } from "SRC_DIR/store/OAuthStore"; import TableView from "./TableView"; +import RowView from "./RowView"; + import RegisterNewButton from "../RegisterNewButton"; const StyledContainer = styled.div` @@ -82,7 +84,12 @@ const List = ({ t, clients, viewAs, setViewAs }: ListProps) => { sectionWidth={context.sectionWidth} /> ) : ( -
row
+ )} )} diff --git a/packages/client/src/store/OAuthStore.ts b/packages/client/src/store/OAuthStore.ts index 0e77e09411..4970e2584e 100644 --- a/packages/client/src/store/OAuthStore.ts +++ b/packages/client/src/store/OAuthStore.ts @@ -37,6 +37,9 @@ export interface OAuthStoreProps { deleteDialogVisible: boolean; setDeleteDialogVisible: (value: boolean) => void; + clientsIsLoading: boolean; + setClientsIsLoading: (value: boolean) => void; + editClient: (clientId: string) => void; clients: ClientProps[]; @@ -85,7 +88,7 @@ export interface OAuthStoreProps { class OAuthStore implements OAuthStoreProps { viewAs: "table" | "row" = "table"; - currentPage: number = 0; + currentPage: number = -1; totalPages: number = 0; totalElements: number = 0; @@ -103,6 +106,8 @@ class OAuthStore implements OAuthStoreProps { scopes: Scope[] = []; + clientsIsLoading: boolean = true; + constructor() { makeAutoObservable(this); } @@ -135,6 +140,10 @@ class OAuthStore implements OAuthStoreProps { } }; + setClientsIsLoading = (value: boolean) => { + this.clientsIsLoading = value; + }; + setActiveClient = (clientId: string) => { if (!clientId) { this.activeClients = []; @@ -175,10 +184,7 @@ class OAuthStore implements OAuthStoreProps { fetchClients = async () => { try { - runInAction(() => { - this.currentPage = 1; - }); - + this.setClientsIsLoading(true); const clientList: ClientListProps = await getClientList(0, PAGE_LIMIT); runInAction(() => { @@ -186,14 +192,23 @@ class OAuthStore implements OAuthStoreProps { this.totalElements = clientList.totalElements; this.clients = clientList.content; + this.selection = []; + this.currentPage = 1; }); + this.setClientsIsLoading(false); } catch (e) { console.log(e); } }; fetchNextClients = async (startIndex: number) => { + if (this.clientsIsLoading) return; + this.setClientsIsLoading(true); + const page = startIndex / PAGE_LIMIT; + + console.log(page); + runInAction(() => { this.currentPage = page + 1; }); @@ -205,6 +220,8 @@ class OAuthStore implements OAuthStoreProps { this.totalElements = clientList.totalElements; this.clients = [...this.clients, ...clientList.content]; }); + + this.setClientsIsLoading(false); }; //TODO: OAuth, add tenant and other params @@ -338,21 +355,21 @@ class OAuthStore implements OAuthStoreProps { const settingsOption = { key: "settings", icon: SettingsIcon, - label: t("Common:Settings"), + label: t("Settings"), onClick: () => this.editClient(clientId), }; const enableOption = { key: "enable", icon: EnableReactSvgUrl, - label: t("Common:Enable"), + label: t("Enable"), onClick: () => onEnable(true), }; const disableOption = { key: "disable", icon: RemoveReactSvgUrl, - label: t("Common:Disable"), + label: t("Disable"), onClick: () => onEnable(false), }; @@ -363,7 +380,7 @@ class OAuthStore implements OAuthStoreProps { }, { key: "delete", - label: t("Common:Delete"), + label: t("Delete"), icon: DeleteIcon, onClick: () => onDelete(), }, From f6dca051acb328b7316faf0263f97a25a5c932b3 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Thu, 28 Sep 2023 13:26:00 +0300 Subject: [PATCH 029/362] Rename oauth service to oauth_api_service, add new oauth service --- build/build.backend.docker.ps1 | 5 ++++- build/install/docker/.env | 5 +++-- build/install/docker/Dockerfile | 3 ++- build/install/docker/Dockerfile.app | 3 ++- build/install/docker/Dockerfile.runtime | 3 ++- .../docker/config/nginx/templates/upstream.conf.template | 8 +++++++- build/install/docker/docspace.profiles.yml | 1 + build/install/docker/docspace.yml | 1 + build/start/start.backend.docker.ps1 | 4 +++- config/nginx/onlyoffice.conf | 4 ++++ 10 files changed, 29 insertions(+), 8 deletions(-) diff --git a/build/build.backend.docker.ps1 b/build/build.backend.docker.ps1 index a1940c895f..a634369066 100644 --- a/build/build.backend.docker.ps1 +++ b/build/build.backend.docker.ps1 @@ -13,7 +13,8 @@ $LocalIp = (Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where $Doceditor = ($LocalIp + ":5013") $Login = ($LocalIp + ":5011") $Client = ($LocalIp + ":5001") -$Oauth = ($LocalIp + ":9090") +$Oauth_api = ($LocalIp + ":9090") +$Oauth = ($LocalIp + ":8080") $PortalUrl = ("http://" + $LocalIp) $ProxyVersion="v1.0.0" @@ -95,6 +96,7 @@ $Env:Baseimage_Proxy_Run="onlyoffice/4testing-docspace-proxy-runtime:$ProxyVersi $Env:SERVICE_DOCEDITOR=$Doceditor $Env:SERVICE_LOGIN=$Login $Env:SERVICE_CLIENT=$Client +$Env:SERVICE_OAUTH_API=$Oauth_api $Env:SERVICE_OAUTH=$Oauth $Env:ROOT_DIR=$RootDir $Env:BUILD_PATH="/var/www" @@ -109,6 +111,7 @@ Write-Host "LOCAL IP: $LocalIp" -ForegroundColor Blue Write-Host "SERVICE_DOCEDITOR: $Env:SERVICE_DOCEDITOR" -ForegroundColor Blue Write-Host "SERVICE_LOGIN: $Env:SERVICE_LOGIN" -ForegroundColor Blue Write-Host "SERVICE_CLIENT: $Env:SERVICE_CLIENT" -ForegroundColor Blue +Write-Host "SERVICE_OAUTH_API: $Env:SERVICE_OAUTH_API" -ForegroundColor Blue Write-Host "SERVICE_OAUTH: $Env:SERVICE_OAUTH" -ForegroundColor Blue Write-Host "INSTALLATION_TYPE: $Env:INSTALLATION_TYPE" -ForegroundColor Blue diff --git a/build/install/docker/.env b/build/install/docker/.env index ae626f42ed..cfa9f2f7f2 100644 --- a/build/install/docker/.env +++ b/build/install/docker/.env @@ -125,8 +125,9 @@ SERVICE_DOCEDITOR=${DOCEDITOR_HOST}:5013 SERVICE_LOGIN=${LOGIN_HOST}:5011 SERVICE_HELTHCHECKS=${HELTHCHECKS_HOST}:${SERVICE_PORT} - SERVICE_OAUTH=${OAUTH_HOST}:9090 - + SERVICE_OAUTH_API=${OAUTH_API_HOST}:9090 + SERVICE_OAUTH=${OAUTH_HOST}:8080 + NETWORK_NAME=${PRODUCT} COMPOSE_IGNORE_ORPHANS=True diff --git a/build/install/docker/Dockerfile b/build/install/docker/Dockerfile index b6d466d29e..cc11082231 100644 --- a/build/install/docker/Dockerfile +++ b/build/install/docker/Dockerfile @@ -176,7 +176,8 @@ RUN chown nginx:nginx /etc/nginx/* -R && \ sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ - sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth_api/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:8080/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ if [[ -z "${SERVICE_CLIENT}" ]] ; then sed -i 's/127.0.0.1:5001/$service_client/' /etc/nginx/conf.d/onlyoffice.conf; fi && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/Dockerfile.app b/build/install/docker/Dockerfile.app index f207117f21..83b46b6860 100644 --- a/build/install/docker/Dockerfile.app +++ b/build/install/docker/Dockerfile.app @@ -163,7 +163,8 @@ RUN sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice. sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ - sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth_api/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:8080/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/http:\/\/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/Dockerfile.runtime b/build/install/docker/Dockerfile.runtime index b6bbfa4110..e731cafd8d 100644 --- a/build/install/docker/Dockerfile.runtime +++ b/build/install/docker/Dockerfile.runtime @@ -120,7 +120,8 @@ RUN chown onlyoffice:onlyoffice /etc/nginx/* -R && \ sed -i 's/127.0.0.1:9834/$service_sso/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5013/$service_doceditor/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \ - sed -i 's/127.0.0.1:9090/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:9090/$service_oauth_api/' /etc/nginx/conf.d/onlyoffice.conf && \ + sed -i 's/127.0.0.1:8080/$service_oauth/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5001/$service_client/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \ sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \ diff --git a/build/install/docker/config/nginx/templates/upstream.conf.template b/build/install/docker/config/nginx/templates/upstream.conf.template index 49a6825c7a..9f52f56afc 100644 --- a/build/install/docker/config/nginx/templates/upstream.conf.template +++ b/build/install/docker/config/nginx/templates/upstream.conf.template @@ -48,9 +48,15 @@ map $SERVICE_API $service_api { default $SERVICE_API; } -map $SERVICE_OAUTH $service_oauth { +map $SERVICE_OAUTH $service_oauth_api { volatile; "" 127.0.0.1:9090; + default $SERVICE_OAUTH_API; +} + +map $SERVICE_OAUTH $service_oauth { + volatile; + "" 127.0.0.1:8080; default $SERVICE_OAUTH; } diff --git a/build/install/docker/docspace.profiles.yml b/build/install/docker/docspace.profiles.yml index f16c2bcfc2..5bf91b64e8 100644 --- a/build/install/docker/docspace.profiles.yml +++ b/build/install/docker/docspace.profiles.yml @@ -261,6 +261,7 @@ services: - SERVICE_NOTIFY=${SERVICE_NOTIFY} - SERVICE_PEOPLE_SERVER=${SERVICE_PEOPLE_SERVER} - SERVICE_SOCKET=${SERVICE_SOCKET} + - SERVICE_OAUTH_API=${SERVICE_OAUTH_API} - SERVICE_OAUTH=${SERVICE_OAUTH} - SERVICE_STUDIO_NOTIFY=${SERVICE_STUDIO_NOTIFY} - SERVICE_API=${SERVICE_API} diff --git a/build/install/docker/docspace.yml b/build/install/docker/docspace.yml index 8decb941fa..0fd3353fed 100644 --- a/build/install/docker/docspace.yml +++ b/build/install/docker/docspace.yml @@ -207,6 +207,7 @@ services: - SERVICE_NOTIFY=${SERVICE_NOTIFY} - SERVICE_PEOPLE_SERVER=${SERVICE_PEOPLE_SERVER} - SERVICE_SOCKET=${SERVICE_SOCKET} + - SERVICE_OAUTH_API=${SERVICE_OAUTH_API} - SERVICE_OAUTH=${SERVICE_OAUTH} - SERVICE_STUDIO_NOTIFY=${SERVICE_STUDIO_NOTIFY} - SERVICE_API=${SERVICE_API} diff --git a/build/start/start.backend.docker.ps1 b/build/start/start.backend.docker.ps1 index 74f37213c8..8db9bb78b6 100644 --- a/build/start/start.backend.docker.ps1 +++ b/build/start/start.backend.docker.ps1 @@ -13,7 +13,8 @@ $LocalIp = (Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where $Doceditor = ($LocalIp + ":5013") $Login = ($LocalIp + ":5011") $Client = ($LocalIp + ":5001") -$Oauth = ($LocalIp + ":9090") +$Oauth_api = ($LocalIp + ":9090") +$Oauth = ($LocalIp + ":8080") Set-Location -Path $DockerDir @@ -26,6 +27,7 @@ $Env:DOCUMENT_SERVER_IMAGE_NAME="onlyoffice/documentserver-de:latest" $Env:SERVICE_DOCEDITOR=$Doceditor $Env:SERVICE_LOGIN=$Login $Env:SERVICE_CLIENT=$Client +$Env:SERVICE_OAUTH_API=$Oauth_api $Env:SERVICE_OAUTH=$Oauth $Env:ROOT_DIR=$RootDir $Env:BUILD_PATH="/var/www" diff --git a/config/nginx/onlyoffice.conf b/config/nginx/onlyoffice.conf index 2c063acc8c..682733dc57 100644 --- a/config/nginx/onlyoffice.conf +++ b/config/nginx/onlyoffice.conf @@ -279,6 +279,10 @@ server { proxy_set_header X-Tenant 1; } + location /oauth2 { + proxy_pass http://127.0.0.1:8080; + } + location /sso { rewrite sso/(.*) /$1 break; proxy_pass http://127.0.0.1:9834; From a34bedef1ea433f8290f3c8cae38018d3e73b325 Mon Sep 17 00:00:00 2001 From: Timofey Boyko Date: Thu, 28 Sep 2023 14:36:53 +0300 Subject: [PATCH 030/362] Web:Client:OAUth: add preview --- .../ClientForm/ClientForm.styled.ts | 65 ++++ .../ClientForm/ClientForm.types.ts | 6 + .../ClientForm/components/Preview.tsx | 98 +++++++ .../OAuth/sub-components/ClientForm/index.tsx | 277 +++++++++--------- 4 files changed, 315 insertions(+), 131 deletions(-) create mode 100644 packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Preview.tsx diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts index eecfc858fa..a373038c88 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.styled.ts @@ -1,6 +1,32 @@ import styled from "styled-components"; +//@ts-ignore +import Box from "@docspace/components/box"; +import { hugeMobile, tablet } from "@docspace/components/utils/device"; + const Container = styled.div` + width: 100%; + + display: grid; + grid-template-columns: 350px 350px; + + gap: 16px; + + .preview-container { + margin-top: 16px; + + width: fit-content; + min-width: 350px; + height: fit-content; + + border: 1px solid #a3aeae; + border-radius: 6px; + + padding: 16px; + } +`; + +const FormContainer = styled.div` max-width: 350px; display: flex; @@ -85,12 +111,51 @@ const CheckboxRaw = styled.div` } `; +const Frame = styled(Box)` + margin-top: 16px; + position: relative; + + display: flex; + justify-content: center; + + button { + width: auto; + max-width: auto; + + padding: 0 20px; + } +`; + +const CategorySubHeader = styled.div` + margin-top: 8px; + margin-bottom: 8px; + font-size: 15px; + font-style: normal; + font-weight: 600; + line-height: 16px; + + @media ${tablet} { + &:not(&.copy-window-code) { + margin-bottom: 0; + } + } + + @media ${hugeMobile} { + &:first-of-type { + margin-top: 0; + } + } +`; + export { Container, + FormContainer, BlockContainer, HeaderRaw, InputGroup, InputRaw, CheckboxGroup, CheckboxRaw, + Frame, + CategorySubHeader, }; diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts index dc8bed767e..df1585ebd6 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/ClientForm.types.ts @@ -54,3 +54,9 @@ export interface ClientFormProps { regenerateSecret?: (clientId: string) => Promise; } + +export interface PreviewProps { + clientId: string; + redirectURI: string; + scopes: string[]; +} diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Preview.tsx b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Preview.tsx new file mode 100644 index 0000000000..0c4d212e4d --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/OAuth/sub-components/ClientForm/components/Preview.tsx @@ -0,0 +1,98 @@ +import React from "react"; + +//@ts-ignore +import Loaders from "@docspace/common/components/Loaders"; + +//@ts-ignore +import Box from "@docspace/components/box"; +//@ts-ignore +import Textarea from "@docspace/components/textarea"; +//@ts-ignore +import TabContainer from "@docspace/components/tabs-container"; +//@ts-ignore +import SocialButton from "@docspace/components/social-button"; + +import ImagesLogoSvgUrl from "PUBLIC_DIR/images/logo/leftmenu.svg?url"; + +import { PreviewProps } from "../ClientForm.types"; +import { Frame, CategorySubHeader } from "../ClientForm.styled"; + +const Preview = ({ clientId, redirectURI, scopes }: PreviewProps) => { + const getAuthLink = () => { + const origin = window.location.origin; + const path = "/oauth2/authorize"; + + const params: { [key: string]: string } = { + response_type: "code", + client_id: clientId, + redirect_uri: redirectURI, + scope: scopes[0], + code_challenge_method: "S256", + code_challenge: "ZX8YUY6qL0EweJXhjDug0S2XuKI8beOWb1LGujmgfuQ", + }; + + const paramsString = []; + + for (let key in params) { + const str = `${key}=${params[key]}`; + + paramsString.push(str); + } + + const link = `${origin}${path}?${paramsString.join("&")}`; + + return link; + }; + + const onDocSpaceLogin = () => { + const url = getAuthLink(); + + window.open( + url, + "login", + "width=800,height=500,status=no,toolbar=no,menubar=no,resizable=yes,scrollbars=no" + ); + }; + + const preview = ( + + + + ); + + const codeBlock = "123"; + + const code = ( + <> + + {"Copy window code"} + +