From 1564f914fe7232047599a62a553bbd8b890395d2 Mon Sep 17 00:00:00 2001 From: Christophe Jossart Date: Tue, 27 Jun 2023 11:05:50 +0200 Subject: [PATCH] feat(publisher): authenticate Publisher with Drupal (#1339) --- apps/silverback-drupal/.gitignore | 2 + apps/silverback-drupal/README.md | 113 ++- apps/silverback-drupal/composer.json | 1 + apps/silverback-drupal/composer.lock | 778 ++++++++++++++++++ .../config/sync/core.extension.yml | 2 + ...oauth.oauth2_token.bundle.access_token.yml | 2 + ...le_oauth.oauth2_token.bundle.auth_code.yml | 2 + ...auth.oauth2_token.bundle.refresh_token.yml | 2 + ...oauth.oauth2_token.bundle.access_token.yml | 10 + ...le_oauth.oauth2_token.bundle.auth_code.yml | 10 + ...auth.oauth2_token.bundle.refresh_token.yml | 10 + .../config/sync/simple_oauth.settings.yml | 11 + ....action.user_add_role_action.publisher.yml | 14 + ...tion.user_remove_role_action.publisher.yml | 14 + .../config/sync/user.role.anonymous.yml | 2 +- .../config/sync/user.role.authenticated.yml | 4 +- .../config/sync/user.role.gatsby_build.yml | 2 +- .../config/sync/user.role.gatsby_preview.yml | 2 +- .../config/sync/user.role.publisher.yml | 12 + .../853581a6-575a-4f99-b3aa-d852fc1abf26.yml | 38 + .../silverback_gatsby.routing.yml | 12 + .../src/Controller/PublisherController.php | 34 + .../npm/@amazeelabs/publisher-ui/favicon.ico | Bin 0 -> 15406 bytes packages/npm/@amazeelabs/publisher/README.md | 85 ++ .../npm/@amazeelabs/publisher/package.json | 8 + .../@amazeelabs/publisher/publisher.config.ts | 19 + .../src/core/tools/authentication.ts | 68 ++ .../publisher/src/core/tools/config.ts | 17 + .../publisher/src/core/tools/oAuth2.ts | 400 +++++++++ .../src/core/tools/oAuth2GrantTypes.ts | 4 + .../npm/@amazeelabs/publisher/src/server.ts | 153 +++- pnpm-lock.yaml | 607 ++++---------- 32 files changed, 1949 insertions(+), 489 deletions(-) create mode 100644 apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.access_token.yml create mode 100644 apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.auth_code.yml create mode 100644 apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.refresh_token.yml create mode 100644 apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.access_token.yml create mode 100644 apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.auth_code.yml create mode 100644 apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.refresh_token.yml create mode 100644 apps/silverback-drupal/config/sync/simple_oauth.settings.yml create mode 100644 apps/silverback-drupal/config/sync/system.action.user_add_role_action.publisher.yml create mode 100644 apps/silverback-drupal/config/sync/system.action.user_remove_role_action.publisher.yml create mode 100644 apps/silverback-drupal/config/sync/user.role.publisher.yml create mode 100644 apps/silverback-drupal/web/modules/custom/silverback_default_content/content/consumer/853581a6-575a-4f99-b3aa-d852fc1abf26.yml create mode 100644 packages/composer/amazeelabs/silverback_gatsby/src/Controller/PublisherController.php create mode 100644 packages/npm/@amazeelabs/publisher-ui/favicon.ico create mode 100644 packages/npm/@amazeelabs/publisher/src/core/tools/authentication.ts create mode 100644 packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2.ts create mode 100644 packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2GrantTypes.ts diff --git a/apps/silverback-drupal/.gitignore b/apps/silverback-drupal/.gitignore index 06e57de10..87580f3cc 100644 --- a/apps/silverback-drupal/.gitignore +++ b/apps/silverback-drupal/.gitignore @@ -20,6 +20,8 @@ # Ignore .env files as they are personal /.env +# Ignore keys, used for authentication +/keys/ # Ignore modules and themes checkout out into sites/default for local development. /web/modules/development diff --git a/apps/silverback-drupal/README.md b/apps/silverback-drupal/README.md index ac3916a10..d79502540 100644 --- a/apps/silverback-drupal/README.md +++ b/apps/silverback-drupal/README.md @@ -2,29 +2,120 @@ ## Gatsby backend part -☝️ Overview and local setup instructions: [silverback.netlify.app/drupal/gatsby](https://silverback.netlify.app/drupal/gatsby) ([alt](../silverback-website/docs/drupal/gatsby.mdx)) +☝️ Overview and local setup instructions: +[silverback.netlify.app/drupal/gatsby](https://silverback.netlify.app/drupal/gatsby) +([alt](../silverback-website/docs/drupal/gatsby.mdx)) ### Entry points -- The content is exposed with [a custom GraphQL schema](./web/modules/custom/silverback_gatsby_test). -- [Gatsby module](https://www.drupal.org/project/gatsby) triggers Gatsby Preview refresh and Gatsby Site rebuild. - - Important: "Entity types to send to Gatsby Preview and Build Server" in the module settings should match [drupalNodes](../silverback-gatsby/src/gatsby-node-helpers/drupal-nodes.ts) on Gatsby side. +- The content is exposed with + [a custom GraphQL schema](./web/modules/custom/silverback_gatsby_test). +- [Gatsby module](https://www.drupal.org/project/gatsby) triggers Gatsby Preview + refresh and Gatsby Site rebuild. + - Important: "Entity types to send to Gatsby Preview and Build Server" in the + module settings should match + [drupalNodes](../silverback-gatsby/src/gatsby-node-helpers/drupal-nodes.ts) + on Gatsby side. -There is a special GatsbyPreview user having the "Bypass content access control" permission. This one is used by Gatsby Preview to fetch unpublished content. +There is a special GatsbyPreview user having the "Bypass content access control" +permission. This one is used by Gatsby Preview to fetch unpublished content. ### Why not version 3 of Drupal GraphQL module -[GraphQL module](https://www.drupal.org/project/graphql) version 3 comes with `graphql_core` submodule which automatically creates GraphQL schema for most of Drupal data. Version 4 however does not include such a feature and forces you to write custom schema/resolvers. +[GraphQL module](https://www.drupal.org/project/graphql) version 3 comes with +`graphql_core` submodule which automatically creates GraphQL schema for most of +Drupal data. Version 4 however does not include such a feature and forces you to +write custom schema/resolvers. -At first glance, v3 looks like an easier solution. We tried it but then switched to v4. We found that v4 is better because: +At first glance, v3 looks like an easier solution. We tried it but then switched +to v4. We found that v4 is better because: -- Custom schema serves as a project documentation. Here is [this app's schema](./web/modules/custom/silverback_gatsby_test/graphql/silverback_gatsby_test.graphqls) for instance. -- With a custom schema you will never hit a limitation. Custom schema can provide any data in any format. -- [Gatsby GraphQL Toolkit](https://github.com/gatsbyjs/gatsby-graphql-toolkit) transforms the source GraphQL data into Gatsby format. Yet the inner stricture is left unchanged. With v3 the frontend experience is not that good as with 4. Compare yourself: +- Custom schema serves as a project documentation. Here is + [this app's schema](./web/modules/custom/silverback_gatsby_test/graphql/silverback_gatsby_test.graphqls) + for instance. +- With a custom schema you will never hit a limitation. Custom schema can + provide any data in any format. +- [Gatsby GraphQL Toolkit](https://github.com/gatsbyjs/gatsby-graphql-toolkit) + transforms the source GraphQL data into Gatsby format. Yet the inner stricture + is left unchanged. With v3 the frontend experience is not that good as with 4. + Compare yourself: - v3: `DrupalNodeArticle.fieldImage.entity.fieldMediaImage.alt` - v4: `DrupalArticle.image.alt` -- It's really easy to write resolvers for v4. For example, [this file](./web/modules/custom/silverback_gatsby_test/src/Plugin/GraphQL/Schema/SilverbackGatsbyTestSchema.php) contains all resolvers for the schema mentioned above. If you scroll down the helpers, you'll see that each resolver takes just one line of code. +- It's really easy to write resolvers for v4. For example, + [this file](./web/modules/custom/silverback_gatsby_test/src/Plugin/GraphQL/Schema/SilverbackGatsbyTestSchema.php) + contains all resolvers for the schema mentioned above. If you scroll down the + helpers, you'll see that each resolver takes just one line of code. ### Gatsby part See [apps/silverback-gatsby](../silverback-gatsby). + +### Authentication server + +Based on OAuth2. + +The scopes are + +- [Publisher access](../../packages/npm/@amazeelabs/publisher/README.md#oauth2) + with Drupal credentials +- Gatsby Preview (instant preview) - WIP +- Gatsby Build (sourcing) - WIP +- Frontend users, other APIs, ... (project specific) + +#### Install on existing projects + +If you are not using the +[Silverback template](https://github.com/AmazeeLabs/silverback-template) or if +Simple OAuth is not installed yet, follow these steps. + +- `composer require drupal/simple_oauth` +- `drush en simple_oauth && drush cex` + +Add these patches in composer.json + +```json +"drupal/simple_oauth": { + "LogicException: leaked metadata was detected": "https://www.drupal.org/files/issues/2023-01-17/logic_exception_leaked_metadata_was_detected-3334329-02.patch", + "Revoke token": "https://www.drupal.org/files/issues/2021-10-30/simple_oauth-permit_logout_and_revoke_tokens-2945273-34.patch" +} +``` + +##### Generic configuration + +- Create a Role for each scope and assign the relevant permissions +- Create a Consumer for each scope (see below) + - Publisher does not need to have a specific user set + - Gatsby Preview and Gatsby Build should use a pre-defined user + - The `default` Consumer can be deleted +- Generate keys `/admin/config/people/simple_oauth` + - Create a directory outside the docroot `mkdir keys` + - Click on "Generate keys" and set `../keys/` as the directory name + - Click save + - It could be gitignored but then have to be generated on the environment and + persisted between deployments +- Drupal hash salt needs to be at least 32 characters long - make sure to + override `DRUPAL_HASH_SALT` env variable. An uuid is 36 chars long and can be + used for that. + +##### Publisher specific configuration + +Create the Publisher Role and the Publisher Consumer. + +_Consumer_ + +You can remove the default Consumer entity in /admin/config/services/consumer + +- Label: `Publisher` +- Client ID: `publisher` +- Client secret: the one configured in Publisher +- User: none +- Is confidential: `true` +- Is this consumer third party: `true` +- If using `Authorization Code` grant type, for the Publisher consumer, set the + redirect uri to `[publisher_base_url]/oauth/callback` +- Scopes: `Publisher` + +_Roles/permissions_ + +Add the `Grant OAuth2 codes` and `Access Publisher` permissions to relevant +roles (editors, ...) diff --git a/apps/silverback-drupal/composer.json b/apps/silverback-drupal/composer.json index bc65a55fa..e04dbe56d 100644 --- a/apps/silverback-drupal/composer.json +++ b/apps/silverback-drupal/composer.json @@ -52,6 +52,7 @@ "drupal/linkit": "6.0.0-rc1", "drupal/paragraphs": "1.15.0", "drupal/redirect": "1.8.0", + "drupal/simple_oauth": "^5.2", "drupal/test_session": "@dev", "drupal/typed_data": "1.0.0-beta2", "drupal/webform": "6.2.0-beta6", diff --git a/apps/silverback-drupal/composer.lock b/apps/silverback-drupal/composer.lock index 25e1e5118..c706a7969 100644 --- a/apps/silverback-drupal/composer.lock +++ b/apps/silverback-drupal/composer.lock @@ -2247,6 +2247,72 @@ }, "time": "2023-01-05T11:28:13+00:00" }, + { + "name": "defuse/php-encryption", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/defuse/php-encryption.git", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/77880488b9954b7884c25555c2a0ea9e7053f9d2", + "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": ">= 2", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5|^6|^7|^8|^9" + }, + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ], + "support": { + "issues": "https://github.com/defuse/php-encryption/issues", + "source": "https://github.com/defuse/php-encryption/tree/v2.3.1" + }, + "time": "2021-04-09T23:57:26+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.2", @@ -2954,6 +3020,54 @@ "slack": "https://drupal.slack.com/archives/C45342CDD" } }, + { + "name": "drupal/consumers", + "version": "1.17.0", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/consumers.git", + "reference": "8.x-1.17" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/consumers-8.x-1.17.zip", + "reference": "8.x-1.17", + "shasum": "8e7efc2c8386ead8ca459a1a5e0558fb66cde142" + }, + "require": { + "drupal/core": "^8 || ^9 || ^10" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "8.x-1.17", + "datestamp": "1679920063", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "e0ipso", + "homepage": "https://www.drupal.org/user/550110" + }, + { + "name": "eojthebrave", + "homepage": "https://www.drupal.org/user/79230" + } + ], + "description": "Declare all the consumers of your API", + "homepage": "https://www.drupal.org/project/consumers", + "support": { + "source": "https://git.drupalcode.org/project/consumers" + } + }, { "name": "drupal/core", "version": "10.0.9", @@ -3955,6 +4069,75 @@ "source": "https://git.drupalcode.org/project/redirect" } }, + { + "name": "drupal/simple_oauth", + "version": "5.2.3", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/simple_oauth.git", + "reference": "5.2.3" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/simple_oauth-5.2.3.zip", + "reference": "5.2.3", + "shasum": "9dae165101c0cff5e1f792457ec6a8eff5c1faf4" + }, + "require": { + "drupal/consumers": "^1.14", + "drupal/core": "^9 || ^10", + "lcobucci/jwt": "^4", + "league/oauth2-server": "^8.3", + "php": ">=7.4", + "steverhoades/oauth2-openid-connect-server": "^2.4" + }, + "require-dev": { + "phpspec/prophecy-phpunit": "^2" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "5.2.3", + "datestamp": "1670908048", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + }, + "drush": { + "services": { + "drush.services.yml": "^9" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "bojan_dev", + "homepage": "https://www.drupal.org/user/2801849" + }, + { + "name": "bradjones1", + "homepage": "https://www.drupal.org/user/405824" + }, + { + "name": "e0ipso", + "homepage": "https://www.drupal.org/user/550110" + }, + { + "name": "pcambra", + "homepage": "https://www.drupal.org/user/122101" + } + ], + "description": "The Simple OAuth module for Drupal", + "homepage": "https://www.drupal.org/project/simple_oauth", + "support": { + "source": "https://git.drupalcode.org/project/simple_oauth" + } + }, { "name": "drupal/test_session", "version": "1.2.64", @@ -4981,6 +5164,144 @@ }, "time": "2022-04-13T08:02:27+00:00" }, + { + "name": "lcobucci/clock", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "infection/infection": "^0.26", + "lcobucci/coding-standard": "^9.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-deprecation-rules": "^1.1.1", + "phpstan/phpstan-phpunit": "^1.3.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.27" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2022-12-19T15:00:24+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-sodium": "*", + "lcobucci/clock": "^2.0 || ^3.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.21", + "lcobucci/coding-standard": "^6.0", + "mikey179/vfsstream": "^1.6.7", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/php-invoker": "^3.1", + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/4.3.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2023-01-02T13:28:00+00:00" + }, { "name": "league/container", "version": "4.2.0", @@ -5063,6 +5384,320 @@ ], "time": "2021-11-16T10:29:06+00:00" }, + { + "name": "league/event", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/event.git", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "^2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Event\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Event package", + "keywords": [ + "emitter", + "event", + "listener" + ], + "support": { + "issues": "https://github.com/thephpleague/event/issues", + "source": "https://github.com/thephpleague/event/tree/master" + }, + "time": "2018-11-26T11:52:41+00:00" + }, + { + "name": "league/oauth2-server", + "version": "8.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git", + "reference": "43cd4d406906c6be5c8de2cee9bd3ad3753544ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/43cd4d406906c6be5c8de2cee9bd3ad3753544ef", + "reference": "43cd4d406906c6be5c8de2cee9bd3ad3753544ef", + "shasum": "" + }, + "require": { + "defuse/php-encryption": "^2.3", + "ext-json": "*", + "ext-openssl": "*", + "lcobucci/clock": "^2.2 || ^3.0", + "lcobucci/jwt": "^4.3 || ^5.0", + "league/event": "^2.2", + "league/uri": "^6.7", + "php": "^8.0", + "psr/http-message": "^1.0.1" + }, + "replace": { + "league/oauth2server": "*", + "lncd/oauth2": "*" + }, + "require-dev": { + "laminas/laminas-diactoros": "^2.24.0", + "phpstan/phpstan": "^0.12.57", + "phpstan/phpstan-phpunit": "^0.12.16", + "phpunit/phpunit": "^9.6.6", + "roave/security-advisories": "dev-master" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\OAuth2\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", + "role": "Developer" + }, + { + "name": "Andy Millington", + "email": "andrew@noexceptions.io", + "homepage": "https://www.noexceptions.io", + "role": "Developer" + } + ], + "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", + "homepage": "https://oauth2.thephpleague.com/", + "keywords": [ + "Authentication", + "api", + "auth", + "authorisation", + "authorization", + "oauth", + "oauth 2", + "oauth 2.0", + "oauth2", + "protect", + "resource", + "secure", + "server" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth2-server/issues", + "source": "https://github.com/thephpleague/oauth2-server/tree/8.5.1" + }, + "funding": [ + { + "url": "https://github.com/sephster", + "type": "github" + } + ], + "time": "2023-04-04T10:20:16+00:00" + }, + { + "name": "league/uri", + "version": "6.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/a700b4656e4c54371b799ac61e300ab25a2d1d39", + "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39", + "shasum": "" + }, + "require": { + "ext-json": "*", + "league/uri-interfaces": "^2.3", + "php": "^8.1", + "psr/http-message": "^1.0.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.9.5", + "nyholm/psr7": "^1.5.1", + "php-http/psr7-integration-tests": "^1.1.1", + "phpbench/phpbench": "^1.2.6", + "phpstan/phpstan": "^1.8.5", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.4.3", + "phpunit/phpunit": "^9.5.24", + "psr/http-factory": "^1.0.1" + }, + "suggest": { + "ext-fileinfo": "Needed to create Data URI from a filepath", + "ext-intl": "Needed to improve host validation", + "league/uri-components": "Needed to easily manipulate URI objects", + "psr/http-factory": "Needed to use the URI factory" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri/issues", + "source": "https://github.com/thephpleague/uri/tree/6.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2022-09-13T19:58:47+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.19", + "phpstan/phpstan": "^0.12.90", + "phpstan/phpstan-phpunit": "^0.12.19", + "phpstan/phpstan-strict-rules": "^0.12.9", + "phpunit/phpunit": "^8.5.15 || ^9.5" + }, + "suggest": { + "ext-intl": "to use the IDNA feature", + "symfony/intl": "to use the IDNA feature via Symfony Polyfill" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interface for URI representation", + "homepage": "http://github.com/thephpleague/uri-interfaces", + "keywords": [ + "rfc3986", + "rfc3987", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/thephpleague/uri-interfaces/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2021-06-28T04:27:21+00:00" + }, { "name": "masterminds/html5", "version": "2.7.6", @@ -5576,6 +6211,56 @@ }, "time": "2023-05-19T20:20:00+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, { "name": "pear/archive_tar", "version": "1.4.14", @@ -7065,6 +7750,54 @@ }, "time": "2021-02-03T23:26:27+00:00" }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -8887,6 +9620,51 @@ }, "time": "2023-02-22T23:07:41+00:00" }, + { + "name": "steverhoades/oauth2-openid-connect-server", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/steverhoades/oauth2-openid-connect-server.git", + "reference": "23381585ebb410ffa11ca9eb0fdba3895fb23119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/steverhoades/oauth2-openid-connect-server/zipball/23381585ebb410ffa11ca9eb0fdba3895fb23119", + "reference": "23381585ebb410ffa11ca9eb0fdba3895fb23119", + "shasum": "" + }, + "require": { + "lcobucci/jwt": "4.1.5|^4.2", + "league/oauth2-server": "^5.1|^6.0|^7.0|^8.0" + }, + "require-dev": { + "laminas/laminas-diactoros": "^1.3.2", + "phpunit/phpunit": "^5.0|^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "OpenIDConnectServer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Steve Rhoades", + "email": "sedonami@gmail.com" + } + ], + "description": "An OpenID Connect Server that sites on The PHP League's OAuth2 Server", + "support": { + "issues": "https://github.com/steverhoades/oauth2-openid-connect-server/issues", + "source": "https://github.com/steverhoades/oauth2-openid-connect-server/tree/v2.5.0" + }, + "time": "2023-01-19T16:49:09+00:00" + }, { "name": "symfony/browser-kit", "version": "v6.3.0", diff --git a/apps/silverback-drupal/config/sync/core.extension.yml b/apps/silverback-drupal/config/sync/core.extension.yml index 0b2e19f97..3fe89807b 100644 --- a/apps/silverback-drupal/config/sync/core.extension.yml +++ b/apps/silverback-drupal/config/sync/core.extension.yml @@ -9,6 +9,7 @@ module: ckeditor: 0 config_filter: 0 config_split: 0 + consumers: 0 dblog: 0 default_content: 0 dynamic_page_cache: 0 @@ -49,6 +50,7 @@ module: silverback_gutenberg: 0 silverback_iframe: 0 silverback_translations: 0 + simple_oauth: 0 sqlite: 0 system: 0 taxonomy: 0 diff --git a/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.access_token.yml b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.access_token.yml new file mode 100644 index 000000000..87dd19c66 --- /dev/null +++ b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.access_token.yml @@ -0,0 +1,2 @@ +label: Zugriffs-Token +description: 'Der Typ des Zugriffstokens.' diff --git a/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.auth_code.yml b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.auth_code.yml new file mode 100644 index 000000000..01bc5f23b --- /dev/null +++ b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.auth_code.yml @@ -0,0 +1,2 @@ +label: Auth-Code +description: 'Der Auth-Code-Typ.' diff --git a/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.refresh_token.yml b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.refresh_token.yml new file mode 100644 index 000000000..c8fcf0116 --- /dev/null +++ b/apps/silverback-drupal/config/sync/language/de/simple_oauth.oauth2_token.bundle.refresh_token.yml @@ -0,0 +1,2 @@ +label: Refresh-Token +description: 'Der Refresh-Token-Typ.' diff --git a/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.access_token.yml b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.access_token.yml new file mode 100644 index 000000000..5e5595dd5 --- /dev/null +++ b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.access_token.yml @@ -0,0 +1,10 @@ +uuid: b8577c7e-fad7-44bb-aa11-8d44b409d2ac +langcode: en +status: true +dependencies: { } +_core: + default_config_hash: z9ULI9nj9yt73YKI3ZE8v9yXhkVfvQsDJToEDzijcxY +id: access_token +label: 'Access Token' +description: 'The access token type.' +locked: true diff --git a/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.auth_code.yml b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.auth_code.yml new file mode 100644 index 000000000..ee90d8f7c --- /dev/null +++ b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.auth_code.yml @@ -0,0 +1,10 @@ +uuid: ab4d5349-bedf-42df-9513-df73aa82a982 +langcode: en +status: true +dependencies: { } +_core: + default_config_hash: zYKaSl4QZrKMFj7aIhSGDRcBy4SoNjvY2EZlT7amrBk +id: auth_code +label: 'Auth code' +description: 'The auth code type.' +locked: true diff --git a/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.refresh_token.yml b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.refresh_token.yml new file mode 100644 index 000000000..43ffbee5b --- /dev/null +++ b/apps/silverback-drupal/config/sync/simple_oauth.oauth2_token.bundle.refresh_token.yml @@ -0,0 +1,10 @@ +uuid: 6b068bd1-065c-4309-a566-72bd9c57be5f +langcode: en +status: true +dependencies: { } +_core: + default_config_hash: YWMv3Do9fsPFhylyFkOwcqcFP4jSU6DLRootOlgrC0M +id: refresh_token +label: 'Refresh token' +description: 'The refresh token type.' +locked: true diff --git a/apps/silverback-drupal/config/sync/simple_oauth.settings.yml b/apps/silverback-drupal/config/sync/simple_oauth.settings.yml new file mode 100644 index 000000000..dfb3a3a2b --- /dev/null +++ b/apps/silverback-drupal/config/sync/simple_oauth.settings.yml @@ -0,0 +1,11 @@ +_core: + default_config_hash: KsPFWSp6mgXIQgjBJEShfKUGn6VLRlbpIJ2EysXvXWM +access_token_expiration: 300 +authorization_code_expiration: 300 +refresh_token_expiration: 1209600 +token_cron_batch_size: 0 +public_key: ../keys/public.key +private_key: ../keys/private.key +remember_clients: true +use_implicit: false +disable_openid_connect: false diff --git a/apps/silverback-drupal/config/sync/system.action.user_add_role_action.publisher.yml b/apps/silverback-drupal/config/sync/system.action.user_add_role_action.publisher.yml new file mode 100644 index 000000000..88df506ab --- /dev/null +++ b/apps/silverback-drupal/config/sync/system.action.user_add_role_action.publisher.yml @@ -0,0 +1,14 @@ +uuid: 5640103b-8039-47d1-be2e-493c04b3c76f +langcode: en +status: true +dependencies: + config: + - user.role.publisher + module: + - user +id: user_add_role_action.publisher +label: 'Add the Publisher role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: publisher diff --git a/apps/silverback-drupal/config/sync/system.action.user_remove_role_action.publisher.yml b/apps/silverback-drupal/config/sync/system.action.user_remove_role_action.publisher.yml new file mode 100644 index 000000000..d0ab4e630 --- /dev/null +++ b/apps/silverback-drupal/config/sync/system.action.user_remove_role_action.publisher.yml @@ -0,0 +1,14 @@ +uuid: daab69f2-55d9-4bdf-961c-02d580f13674 +langcode: en +status: true +dependencies: + config: + - user.role.publisher + module: + - user +id: user_remove_role_action.publisher +label: 'Remove the Publisher role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: publisher diff --git a/apps/silverback-drupal/config/sync/user.role.anonymous.yml b/apps/silverback-drupal/config/sync/user.role.anonymous.yml index 62402cca0..a48a36d55 100644 --- a/apps/silverback-drupal/config/sync/user.role.anonymous.yml +++ b/apps/silverback-drupal/config/sync/user.role.anonymous.yml @@ -8,7 +8,7 @@ _core: default_config_hash: j5zLMOdJBqC0bMvSdth5UebkprJB8g_2FXHqhfpJzow id: anonymous label: 'Anonymous user' -weight: 0 +weight: -10 is_admin: false permissions: - 'execute extra persisted graphql requests' diff --git a/apps/silverback-drupal/config/sync/user.role.authenticated.yml b/apps/silverback-drupal/config/sync/user.role.authenticated.yml index 4c8eccfe1..da0249b64 100644 --- a/apps/silverback-drupal/config/sync/user.role.authenticated.yml +++ b/apps/silverback-drupal/config/sync/user.role.authenticated.yml @@ -4,13 +4,15 @@ status: true dependencies: module: - graphql + - simple_oauth _core: default_config_hash: dJ0L2DNSj5q6XVZAGsuVDpJTh5UeYkIPwKrUOOpr8YI id: authenticated label: 'Authenticated user' -weight: 1 +weight: -9 is_admin: false permissions: - 'execute extra persisted graphql requests' - 'execute silverback_gatsby persisted graphql requests' - 'execute silverback_gatsby_preview persisted graphql requests' + - 'grant simple_oauth codes' diff --git a/apps/silverback-drupal/config/sync/user.role.gatsby_build.yml b/apps/silverback-drupal/config/sync/user.role.gatsby_build.yml index 0d03f19b9..95092561c 100644 --- a/apps/silverback-drupal/config/sync/user.role.gatsby_build.yml +++ b/apps/silverback-drupal/config/sync/user.role.gatsby_build.yml @@ -10,7 +10,7 @@ dependencies: - system id: gatsby_build label: 'Gatsby Build' -weight: 3 +weight: -6 is_admin: null permissions: - 'access content' diff --git a/apps/silverback-drupal/config/sync/user.role.gatsby_preview.yml b/apps/silverback-drupal/config/sync/user.role.gatsby_preview.yml index b5993a17c..84763be5b 100644 --- a/apps/silverback-drupal/config/sync/user.role.gatsby_preview.yml +++ b/apps/silverback-drupal/config/sync/user.role.gatsby_preview.yml @@ -11,7 +11,7 @@ dependencies: - system id: gatsby_preview label: 'Gatsby Preview' -weight: 2 +weight: -7 is_admin: null permissions: - 'access content' diff --git a/apps/silverback-drupal/config/sync/user.role.publisher.yml b/apps/silverback-drupal/config/sync/user.role.publisher.yml new file mode 100644 index 000000000..cdee69c86 --- /dev/null +++ b/apps/silverback-drupal/config/sync/user.role.publisher.yml @@ -0,0 +1,12 @@ +uuid: fe13f7b9-0da3-4091-bb08-7abf2230d294 +langcode: en +status: true +dependencies: + module: + - silverback_gatsby +id: publisher +label: Publisher +weight: -8 +is_admin: null +permissions: + - 'access publisher' diff --git a/apps/silverback-drupal/web/modules/custom/silverback_default_content/content/consumer/853581a6-575a-4f99-b3aa-d852fc1abf26.yml b/apps/silverback-drupal/web/modules/custom/silverback_default_content/content/consumer/853581a6-575a-4f99-b3aa-d852fc1abf26.yml new file mode 100644 index 000000000..d8239a8cd --- /dev/null +++ b/apps/silverback-drupal/web/modules/custom/silverback_default_content/content/consumer/853581a6-575a-4f99-b3aa-d852fc1abf26.yml @@ -0,0 +1,38 @@ +_meta: + version: '1.0' + entity_type: consumer + uuid: 853581a6-575a-4f99-b3aa-d852fc1abf26 + default_langcode: en +default: + owner_id: + - + target_id: 1 + client_id: + - + value: publisher + label: + - + value: Publisher + third_party: + - + value: true + is_default: + - + value: false + secret: + - + value: $S$EiU1sw9l5HjS7TNLxhIZ7n4pn/2p0BgXpOb5hOt19YUfwp4IfJ1s + existing: '' + pre_hashed: false + confidential: + - + value: true + roles: + - + target_id: publisher + redirect: + - + value: 'http://localhost:7777/oauth/callback' + pkce: + - + value: false diff --git a/packages/composer/amazeelabs/silverback_gatsby/silverback_gatsby.routing.yml b/packages/composer/amazeelabs/silverback_gatsby/silverback_gatsby.routing.yml index 28cf49d99..5fcdf89a8 100644 --- a/packages/composer/amazeelabs/silverback_gatsby/silverback_gatsby.routing.yml +++ b/packages/composer/amazeelabs/silverback_gatsby/silverback_gatsby.routing.yml @@ -14,3 +14,15 @@ silverback_gatsby.build: _controller: '\Drupal\silverback_gatsby\Controller\BuildController::build' requirements: _permission: 'trigger a gatsby build' +publisher.access: + path: '/publisher/access' + defaults: + _controller: '\Drupal\silverback_gatsby\Controller\PublisherController::hasAccess' + methods: [ POST ] + requirements: + # Required for the refresh token. + _access: 'TRUE' + _format: 'json' + options: + _auth: [ 'oauth2' ] + no_cache: TRUE diff --git a/packages/composer/amazeelabs/silverback_gatsby/src/Controller/PublisherController.php b/packages/composer/amazeelabs/silverback_gatsby/src/Controller/PublisherController.php new file mode 100644 index 000000000..4b3bde961 --- /dev/null +++ b/packages/composer/amazeelabs/silverback_gatsby/src/Controller/PublisherController.php @@ -0,0 +1,34 @@ +currentUser(); + // Verify permission against User entity. + $userEntity = User::load($userAccount->id()); + if ($userEntity->hasPermission('access publisher')) { + return new JsonResponse([ + 'access' => TRUE, + ], 200); + } + else { + return new JsonResponse([ + 'access' => FALSE, + ], 403); + } + } + +} diff --git a/packages/npm/@amazeelabs/publisher-ui/favicon.ico b/packages/npm/@amazeelabs/publisher-ui/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ea9d05eef423503525a81302c41db7d48dba067 GIT binary patch literal 15406 zcmeHOUx*b|7#~ZbAW8-Mm>-JhaT#sdI>TTBEttGg9NAuy%12O$v6S`p1GVej61=kB_D*Xyo3{eCm|TxZUm8RyKOdovt3&YW}4 z_kF+bJKy=vcg|TgZI*VkHfN58cdz!^Y)yMq)3n}Rr@myarVXI2udng@Vof_TU(=SL z4@f}awBr@&G4l)hDn@Qgxu6fB)Ei}pZTu~W$zLCJ-&QH;{bfVHQZafhzheJ}KJ4q} z!+I&NAM&H|YXhc3ZXT5D*DtgUG{iui{4h_Or>)BNCBAx)FKL9W{N&7BnGU6QXdFAo zrH38tF$$ue_~kuo;_wE$`1NUwZQbuT;-5TjSd%9{wfOk;Y0$$rTF2Yb|9;Ed*%wA{ z`&AHqb@vLZy62fddf}6P<2P0Q-I}hPY8F|B7(en{R#0rohG_Xx&niiO{e zwgUUGZ&G=JespWsqH-bk31mzJjazHGK0zAN3O=fDC-&twLBGqb{9EUhUmwzz^0`g2 zPhAVkaG`r)C9fa%;~A?ByvXxfa`}64i@p?oS&SveC*BA?uO1AMd? zWCxB>sx}X@1;)b9ALu7doI$iHwNsXR9PBw3(a-CD{$O1`f6y{_Jm91vJvmFeyZy~T|Hwl7nX|(FUpQ9-=2g% z|0v6kX@BORi~%g8gU>aQD9LZ;E$a3+UE@zI;!%-L|BF5U(vXk2@8ooy(O=|>apLdT z{+F$>Z=biz#RF@E`4#4*6Mwk|#94ou0;P|r<1f}9%2!!`FP$E=>Sy)^mMHS&^_Lhr znSW4zr}Hmj$U6T-tPRXRDW8v-*ZbHn$~da@Ay4M^j+F3!X@^vEVTJvNKxX?xLI04x zs-ma6FKOfKzXS%p?YWt6|NhgBf!`um6giWfJJ`0-FY`OA{kM$c|5oQY2@g+SK}qAB z1Z-L!3#_Y!?s=mFU5juw_N-~--mesL-(k%Dz&cSS{P^C@Z&~pcH=x?E$|Hj*Wd2>742KUKw9XzZe&}}BjlMeY@2;)Yj+pq?m`)c zO=HIpp(FTkjEaaSpPBjGeOc*nam(Fzm5ton@Q+a;JN0)#AH!Maddi}2rlm{SSnycM z$bAnx)lqMPlypE>Y#$ZoVR_Z)_LrW{Ts%il8@#~oHx+- zpZ^T@#&`fznb^YOQl)?HopziFxzp^FUYyg!#@HI?$b_vh>h!mAO6bb zd-No0Q|;G}t=h3|c1e1M8)_58LwTKM?g8xmp>!>A!Fx6`Qy*{c_^V$%t#IDp1<6abJ40}~@2KDU({u1`nz;iMPlS;b>|L2dl z#r}x-L$E*g3F>QzOykBse)wJM;(<3pi%cJ<-Zjl2L;ofYUYW*?-}H$;yc2UjGJTwS$v&&hVEt+ne)}wSpl4a?`9quV z^US!&{4Lh`t9Q+4yZ-<)&%HCrpW9%6kw0S#gZ+!X7WpXtcGGK9mAc#h6GuO=CVqa$ zQ)sH{4XDWUDs^BVcHdd1y?+mY>}giPEBEDH zfqVbXeXui+b5*%-)cW{O>#gx48zPsed|UeA{(*NW#4JA*oY`V*67Az#GB0A| z9g2)w)UWsRL+Zi17OV&7W!*bnhwV$mCTtz{uH<`Of)3f;bE*0i&J1}E6oy&;4ft16 z=T6%lIF#=%sEZR*_0^pm2iUL1dm!Fr$@Yy}Z}`%A config; export default defineConfig({ publisherPort: 3000, + basicAuth: { + username: 'test', + password: 'test', + }, + // When several authentication methods are configured, + // oAuth2 takes precedence. + oAuth2: { + clientId: process.env.OAUTH2_CLIENT_ID || 'publisher', + clientSecret: process.env.OAUTH2_CLIENT_ID || 'publisher', + scope: process.env.OAUTH2_SCOPE || 'publisher', + tokenHost: process.env.OAUTH2_TOKEN_HOST || 'http://localhost:8888', + tokenPath: process.env.OAUTH2_TOKEN_PATH || '/oauth/token', + authorizePath: + process.env.OAUTH2_AUTHORIZE_PATH || + '/oauth/authorize?response_type=code', + sessionSecret: process.env.OAUTH2_SESSION_SECRET || 'banana', + environmentType: process.env.OAUTH2_ENVIRONMENT_TYPE || 'development', + grantType: 0, // AuthorizationCode + }, commands: { clean: 'echo "clean starting"; sleep 1; echo "cleaned 50%"; sleep 1; echo "clean done"', diff --git a/packages/npm/@amazeelabs/publisher/src/core/tools/authentication.ts b/packages/npm/@amazeelabs/publisher/src/core/tools/authentication.ts new file mode 100644 index 000000000..0ebb232b4 --- /dev/null +++ b/packages/npm/@amazeelabs/publisher/src/core/tools/authentication.ts @@ -0,0 +1,68 @@ +import { NextFunction, Request, RequestHandler, Response } from 'express'; +import basicAuth from 'express-basic-auth'; + +import { getConfig, PublisherConfig } from './config'; +import { + oAuth2AuthCodeMiddleware, + oAuth2ResourceOwnerPasswordMiddleware, +} from './oAuth2'; +import { OAuth2GrantTypes } from './oAuth2GrantTypes'; + +/** + * Returns the Express authentication middleware based on the configuration. + * + * Favours OAuth2, then Basic Auth, then falling back to no auth + * if not configured (= grant access). + */ +export const getAuthenticationMiddleware = ( + config: PublisherConfig, +): RequestHandler => + ((): RequestHandler => { + const skipAuthentication = + process.env.PUBLISHER_SKIP_AUTHENTICATION === 'true'; + if (skipAuthentication) { + return (req: Request, res: Response, next: NextFunction): void => next(); + } + + const oAuth2Config = config.oAuth2; + if (oAuth2Config) { + if (oAuth2Config.grantType === OAuth2GrantTypes.AuthorizationCode) { + return oAuth2AuthCodeMiddleware; + } else if ( + oAuth2Config.grantType === OAuth2GrantTypes.ResourceOwnerPassword + ) { + return oAuth2ResourceOwnerPasswordMiddleware; + } else { + console.error( + 'Only the AuthorizationCode and ResourceOwnerPassword grant types are currently supported.', + ); + } + } + + const basicAuthConfig = getConfig().basicAuth; + if (basicAuthConfig) { + return basicAuth({ + users: { [basicAuthConfig.username]: basicAuthConfig.password }, + challenge: true, + }); + } + + return (req: Request, res: Response, next: NextFunction): void => next(); + })(); + +/** + * Checks if a session is required based on the configuration. + */ +export const isSessionRequired = (): boolean => { + let result = false; + if (getConfig().oAuth2) { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + if (oAuth2Config.grantType === OAuth2GrantTypes.AuthorizationCode) { + result = true; + } + } + return result; +}; diff --git a/packages/npm/@amazeelabs/publisher/src/core/tools/config.ts b/packages/npm/@amazeelabs/publisher/src/core/tools/config.ts index 09403321d..cf3d865bb 100644 --- a/packages/npm/@amazeelabs/publisher/src/core/tools/config.ts +++ b/packages/npm/@amazeelabs/publisher/src/core/tools/config.ts @@ -1,3 +1,5 @@ +import { OAuth2GrantTypes } from './oAuth2GrantTypes'; + export type PublisherConfig = { /** * Port on which the publisher server will be running. @@ -93,6 +95,21 @@ export type PublisherConfig = { username: string; password: string; }; + /** + * Enables OAuth2. + */ + oAuth2?: { + clientId: string; + clientSecret: string; + scope: string; + tokenHost: string; + tokenPath: string; + grantType: OAuth2GrantTypes; + // Use for Authorization Code grant type only. + authorizePath?: string; + sessionSecret?: string; + environmentType?: string; // 'development' | 'production'; + }; /** * Specific CORS settings. * diff --git a/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2.ts b/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2.ts new file mode 100644 index 000000000..b4e70d810 --- /dev/null +++ b/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2.ts @@ -0,0 +1,400 @@ +import cookieParser from 'cookie-parser'; +import crypto from 'crypto'; +import { + Express, + NextFunction, + Request, + RequestHandler, + Response, +} from 'express'; +import session from 'express-session'; +import createMemoryStore from 'memorystore'; +import fetch from 'node-fetch'; +import { + AccessToken, + AuthorizationCode, + ModuleOptions, + ResourceOwnerPassword, +} from 'simple-oauth2'; + +import { getConfig } from './config'; + +declare module 'express-session' { + interface SessionData { + tokenString: string; + state: string; + } +} + +// In seconds +export const SESSION_MAX_AGE = 300; +export const ACCESS_TOKEN_EXPIRATION_TIME = 300; + +const ENCRYPTION_KEY = + process.env.ENCRYPTION_KEY || crypto.randomBytes(32).toString('hex'); + +/** + * Returns the Authorization Code middleware. + * + * This should be favoured in most cases when using OAuth2. + */ +export const oAuth2AuthCodeMiddleware: RequestHandler = ((): RequestHandler => { + return async (req: Request, res: Response, next: NextFunction) => { + if (await isAuthenticated(req)) { + const accessPublisher = await hasPublisherAccess(req); + if (accessPublisher) { + return next(); + } else { + res + .status(403) + .send( + 'Your user account does not have Publisher access. You might contact your site administrator.', + ); + } + } else { + res.cookie('origin', req.originalUrl).redirect('/oauth'); + } + }; +})(); + +/** + * Returns the Resource Owner Password middleware. + * + * This can be used as a minimal implementation of OAuth2 if the challenge + * is to be exposed in the client / the backend is only accessible + * from the client and not the end user. + * + * Refresh tokens are not implemented. + */ +export const oAuth2ResourceOwnerPasswordMiddleware: RequestHandler = + ((): RequestHandler => { + return async (req: Request, res: Response, next: NextFunction) => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('OAuth2 configuration is missing.'); + } + + // As an MVP, we are using the www-authenticate header to send the challenge. + // This allows to have a lightweight implementation of the UI, and we + // don't need to handle any session. + const base64Auth = (req.headers.authorization || '').split(' ')[1] || ''; + const [wwwLogin, wwwPassword] = Buffer.from(base64Auth, 'base64') + .toString() + .split(':'); + + const oAuth2ModuleOptions: ModuleOptions = { + client: { + id: oAuth2Config.clientId, + secret: oAuth2Config.clientSecret, + }, + auth: { + tokenHost: oAuth2Config.tokenHost, + tokenPath: oAuth2Config.tokenPath, + }, + }; + const oAuth2Client = new ResourceOwnerPassword(oAuth2ModuleOptions); + let errorMessage: string | null = null; + + if (wwwLogin && wwwPassword) { + const tokenParams = { + username: wwwLogin, + password: wwwPassword, + scope: oAuth2Config.scope, + }; + + try { + const accessToken = await oAuth2Client.getToken(tokenParams); + if (accessToken) { + const publisherAuthentication = await fetch( + `${oAuth2ModuleOptions.auth.tokenHost}/publisher/access`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken.token.access_token}`, + }, + }, + ); + + if (publisherAuthentication.status === 200) { + return next(); + } else if ( + publisherAuthentication.status === 403 || + publisherAuthentication.status === 401 + ) { + errorMessage = 'Publisher authentication failed.'; + } else if (publisherAuthentication.status === 500) { + errorMessage = 'Internal server error.'; + } else { + errorMessage = 'Unknown error.'; + } + } + } catch (data) { + errorMessage = 'OAuth2 authentication failed.'; + } + } + + // In case of failure, just send a 401 with the www-authenticate header. + res.set('WWW-Authenticate', 'Basic realm="401"'); + if (errorMessage) { + console.error(errorMessage); + res.status(401).send(errorMessage); + } else { + res.status(401).send('Authentication required.'); + } + }; + })(); + +export const initializeSession = (server: Express): void => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + server.use(cookieParser()); + + const sessionMaxAgeInMilliseconds = SESSION_MAX_AGE * 1000; + const MemoryStore = createMemoryStore(session); + + const config = { + secret: + oAuth2Config.sessionSecret || crypto.randomBytes(64).toString('hex'), + resave: true, // seems to be needed for MemoryStore + saveUninitialized: false, + cookie: { maxAge: sessionMaxAgeInMilliseconds }, + // Keep it simple, use production safe memory store, + // not the one provided by express-session. + // Other available stores + // https://expressjs.com/en/resources/middleware/session.html#compatible-session-stores + store: new MemoryStore({ + checkPeriod: sessionMaxAgeInMilliseconds, // prune expired entries + }), + }; + + if (oAuth2Config.environmentType === 'production') { + server.set('trust proxy', 1); // trust first proxy + // @ts-ignore + config.cookie.secure = true; // serve secure cookies + } + + server.use(session(config)); +}; + +export const oAuth2AuthorizationCodeClient = (): AuthorizationCode | null => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + return null; + } + return new AuthorizationCode({ + client: { + id: oAuth2Config.clientId, + secret: oAuth2Config.clientSecret, + }, + auth: { + tokenHost: oAuth2Config.tokenHost, + tokenPath: oAuth2Config.tokenPath, + authorizePath: oAuth2Config.authorizePath, + }, + }); +}; + +export const persistAccessToken = (token: AccessToken, req: Request): void => { + req.session.tokenString = encrypt(JSON.stringify(token)); +}; + +export const getPersistedAccessToken = (req: Request): AccessToken | null => { + const client = oAuth2AuthorizationCodeClient(); + if (!client) { + throw new Error('Missing OAuth2 client.'); + } + if (req.session.tokenString) { + const decryptedToken = decrypt(req.session.tokenString); + if (!decryptedToken) { + throw new Error('Failed to decrypt token.'); + } + return client.createToken(JSON.parse(decryptedToken)); + } else { + return null; + } +}; + +const encrypt = (text: string): string => { + if (!ENCRYPTION_KEY) { + throw new Error('Missing encryption key.'); + } + + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + + try { + const iv = crypto.randomBytes(16); + const key = crypto + .createHash('sha256') + .update(ENCRYPTION_KEY) + .digest('base64') + .substring(0, 32); + const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); + let encrypted = cipher.update(text); + encrypted = Buffer.concat([encrypted, cipher.final()]); + return iv.toString('hex') + ':' + encrypted.toString('hex'); + } catch (error) { + throw new Error('Encryption failed.'); + } +}; + +const decrypt = (encryptedText: string): string => { + if (!ENCRYPTION_KEY) { + throw new Error('Missing encryption key.'); + } + + try { + const textParts = encryptedText.split(':'); + // @ts-ignore + const iv = Buffer.from(textParts.shift(), 'hex'); + + const encryptedData = Buffer.from(textParts.join(':'), 'hex'); + const key = crypto + .createHash('sha256') + .update(ENCRYPTION_KEY) + .digest('base64') + .substring(0, 32); + const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); + + const decrypted = decipher.update(encryptedData); + const decryptedText = Buffer.concat([decrypted, decipher.final()]); + return decryptedText.toString(); + } catch (error) { + throw new Error('Decryption failed.'); + } +}; + +export const getOAuth2AuthorizeUrl = ( + client: AuthorizationCode, + req: Request, +): string => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + + const state = crypto.randomBytes(32).toString('hex'); + persistState(state, req); + const encodedState = Buffer.from(state).toString('base64'); + return client.authorizeURL({ + // Set on the OAuth2 provider. + //redirect_uri: callbackUrl, + scope: oAuth2Config.scope, + // https://auth0.com/docs/secure/attack-protection/state-parameters + state: encodedState, + }); +}; + +export const persistState = (state: string, req: Request): void => { + req.session.state = state; +}; + +export const stateMatches = (req: Request): boolean => { + const persistedState = req.session.state; + if (persistedState === undefined) { + throw new Error('Missing state.'); + } + const encodedState = req.query.state as string; + if (encodedState === undefined) { + throw new Error('Missing state.'); + } + const decodedState = Buffer.from(encodedState, 'base64').toString('ascii'); + return persistedState === decodedState; +}; + +export const isAuthenticated = async (req: Request): Promise => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + + let result = false; + let accessToken = getPersistedAccessToken(req); + if (accessToken) { + if (!accessToken.expired(ACCESS_TOKEN_EXPIRATION_TIME)) { + result = true; + } else { + try { + const refreshParams = { + grant_type: 'refresh_token', + scope: oAuth2Config.scope, + }; + accessToken = await accessToken.refresh(refreshParams); + persistAccessToken(accessToken, req); + result = true; + } catch (error) { + console.error('Error refreshing access token: ', error); + } + } + } else { + console.log('No access token.'); + } + + return result; +}; + +export const hasPublisherAccess = async (req: Request): Promise => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + + const accessToken = getPersistedAccessToken(req); + if (!accessToken) { + throw new Error('Missing access token.'); + } + + const publisherAccess = await fetch( + `${oAuth2Config.tokenHost}/publisher/access`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken.token.access_token}`, + }, + }, + ); + + const status = await publisherAccess.status; + return status === 200; +}; + +/** + * User info. + * + * Can be used for debugging purposes. + */ +export const getUserInfo = async (req: Request): Promise => { + const accessToken = getPersistedAccessToken(req); + if (!accessToken) { + throw new Error('Missing access token.'); + } + try { + const userInfoResponse = await fetch( + 'http://localhost:8888/oauth/userinfo', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken.token.access_token}`, + }, + }, + ); + const status = await userInfoResponse.status; + console.debug('User info status', status); + if (status === 200) { + const json = await userInfoResponse.json(); + console.debug('User info', json); + } + return status === 200; + } catch (error) { + console.error('Error fetching user info', error); + } + + return false; +}; diff --git a/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2GrantTypes.ts b/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2GrantTypes.ts new file mode 100644 index 000000000..1807555ab --- /dev/null +++ b/packages/npm/@amazeelabs/publisher/src/core/tools/oAuth2GrantTypes.ts @@ -0,0 +1,4 @@ +export enum OAuth2GrantTypes { + AuthorizationCode, + ResourceOwnerPassword, +} diff --git a/packages/npm/@amazeelabs/publisher/src/server.ts b/packages/npm/@amazeelabs/publisher/src/server.ts index 6e70d5af6..e15e7b045 100644 --- a/packages/npm/@amazeelabs/publisher/src/server.ts +++ b/packages/npm/@amazeelabs/publisher/src/server.ts @@ -1,12 +1,6 @@ import { ApplicationState } from '@amazeelabs/publisher-shared'; import cors from 'cors'; -import express, { - NextFunction, - Request, - RequestHandler, - Response, -} from 'express'; -import basicAuth from 'express-basic-auth'; +import express from 'express'; import expressWs from 'express-ws'; import { createProxyMiddleware, @@ -20,29 +14,40 @@ import { map, shareReplay, Subject } from 'rxjs'; import { fileURLToPath } from 'url'; import { core } from './core/core'; +import { + getAuthenticationMiddleware, + isSessionRequired, +} from './core/tools/authentication'; import { getConfig } from './core/tools/config'; import { getDatabase } from './core/tools/database'; +import { + getOAuth2AuthorizeUrl, + getPersistedAccessToken, + hasPublisherAccess, + initializeSession, + isAuthenticated, + oAuth2AuthorizationCodeClient, + persistAccessToken, + stateMatches, +} from './core/tools/oAuth2'; import { stateNotify } from './notify'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const runServer = async (): Promise => { - const ews = expressWs(express()); - const { app } = ews; + const expressServer = express(); + const expressWsInstance = expressWs(expressServer); + const { app } = expressWsInstance; app.locals.isReady = false; - // Basic Authentication - const authMiddleware = ((): RequestHandler => { - const credentials = getConfig().basicAuth; - return credentials - ? basicAuth({ - users: { [credentials.username]: credentials.password }, - challenge: true, - }) - : (req: Request, res: Response, next: NextFunction): void => next(); - })(); + // A session is only needed for OAuth2 Authorization Code grant type. + if (isSessionRequired()) { + initializeSession(expressServer); + } + // Authentication middleware based on the configuration. + const authMiddleware = getAuthenticationMiddleware(getConfig()); // Allow cross-origin requests // @TODO see if we need to lock this down @@ -137,12 +142,6 @@ const runServer = async (): Promise => { ), ); - app.use('/___status', authMiddleware); - app.use( - '/___status', - express.static(path.resolve(__dirname, '../../publisher-ui/dist')), - ); - getConfig().proxy?.forEach(({ prefix, target }) => { app.use( prefix, @@ -154,6 +153,108 @@ const runServer = async (): Promise => { ); }); + // --------------------------------------------------------------------------- + // OAuth2 routes + // --------------------------------------------------------------------------- + + app.use('/___status', authMiddleware); + app.use( + '/___status', + express.static(path.resolve(__dirname, '../../publisher-ui/dist')), + ); + + // Fallback route for login. Is used if there is no origin cookie. + app.get('/oauth/login', async (req, res) => { + if (await isAuthenticated(req)) { + const accessPublisher = await hasPublisherAccess(req); + if (accessPublisher) { + res.send( + 'Publisher access is granted. View status', + ); + } else { + res.send( + 'Publisher access is not granted. Contact your site administrator. Log out', + ); + } + } else { + res.cookie('origin', req.path).send('Log in'); + } + }); + + // Redirects to authentication provider. + app.get('/oauth', (req, res) => { + const client = oAuth2AuthorizationCodeClient(); + if (!client) { + throw new Error('Missing OAuth2 client.'); + } + const authorizationUri = getOAuth2AuthorizeUrl(client, req); + res.redirect(authorizationUri); + }); + + // Callback from authentication provider. + app.get('/oauth/callback', async (req, res) => { + const oAuth2Config = getConfig().oAuth2; + if (!oAuth2Config) { + throw new Error('Missing OAuth2 configuration.'); + } + + const client = oAuth2AuthorizationCodeClient(); + if (!client) { + throw new Error('Missing OAuth2 client.'); + } + + // Check if the state matches. + if (!stateMatches(req)) { + return res.status(500).json('State does not match.'); + } + + const { code } = req.query; + const options = { + code, + scope: oAuth2Config.scope, + // Do not include redirect_uri, makes Drupal simple_oauth fail. + // Returns 400 Bad Request. + //redirect_uri: 'http://127.0.0.1:7777/callback', + }; + + try { + // @ts-ignore options due to missing redirect_uri. + const accessToken = await client.getToken(options); + console.log('/oauth/callback accessToken', accessToken); + persistAccessToken(accessToken, req); + + if (req.cookies.origin) { + res.redirect(req.cookies.origin); + } else { + res.redirect('/oauth/login'); + } + } catch (error) { + console.error(error); + return ( + res + .status(500) + // @ts-ignore + .json(`Authentication failed with error: ${error.message}`) + ); + } + }); + + // Removes the session. + app.get('/oauth/logout', async (req, res) => { + const accessToken = getPersistedAccessToken(req); + if (!accessToken) { + return res.status(401).send('No token found.'); + } + + // Requires this Drupal patch + // https://www.drupal.org/project/simple_oauth/issues/2945273 + // await accessToken.revokeAll(); + req.session.destroy(function (err) { + console.log('Remove session', err); + }); + res.redirect('/oauth/login'); + }); + app.get('*', (req, res, next) => { if (!req.app.locals.isReady) { if (req.accepts('text/html')) { @@ -168,7 +269,7 @@ const runServer = async (): Promise => { app.use( '/', - authMiddleware, + //authMiddleware, createProxyMiddleware(() => app.locals.isReady, { target: `http://127.0.0.1:${getConfig().commands.serve.port}`, selfHandleResponse: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ebf96dc7..6d5855352 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,9 +1,5 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - overrides: '@graphql-tools/load': ^7.8.14 @@ -395,7 +391,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@amazeelabs/eslint-config': specifier: 1.4.43 @@ -427,7 +423,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@amazeelabs/bridge': specifier: workspace:* @@ -465,7 +461,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@amazeelabs/bridge': specifier: workspace:* @@ -515,7 +511,7 @@ importers: version: 5.1.3 vitest: specifier: 0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) packages/npm/@amazeelabs/codegen-gatsby-fragments: dependencies: @@ -531,7 +527,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@amazeelabs/eslint-config': specifier: 1.4.43 @@ -596,7 +592,7 @@ importers: version: 4.3.9(@types/node@18.16.2) vitest: specifier: 0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) packages/npm/@amazeelabs/gatsby-fragments: devDependencies: @@ -671,7 +667,7 @@ importers: version: 8.42.0 gatsby: specifier: 5.10.0 - version: 5.10.0(babel-eslint@10.1.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) + version: 5.10.0(babel-eslint@10.1.0)(esbuild@0.18.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) prettier: specifier: 2.8.8 version: 2.8.8 @@ -683,7 +679,7 @@ importers: version: 4.3.9(@types/node@16.18.36) vitest: specifier: 0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) packages/npm/@amazeelabs/gatsby-source-silverback: dependencies: @@ -999,7 +995,7 @@ importers: version: 4.3.9(@types/node@18.16.2) vitest: specifier: 0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) packages/npm/@amazeelabs/publisher: dependencies: @@ -1015,6 +1011,9 @@ importers: '@slack/webhook': specifier: ^6.1.0 version: 6.1.0 + cookie-parser: + specifier: 1.4.6 + version: 1.4.6 cors: specifier: ^2.8.5 version: 2.8.5 @@ -1024,6 +1023,9 @@ importers: express-basic-auth: specifier: ^1.2.1 version: 1.2.1 + express-session: + specifier: 1.17.3 + version: 1.17.3 express-ws: specifier: 5.0.2 version: 5.0.2(express@4.18.2) @@ -1036,6 +1038,12 @@ importers: http-terminator: specifier: 3.2.0 version: 3.2.0 + memorystore: + specifier: 1.6.7 + version: 1.6.7 + node-fetch: + specifier: ^3.3.1 + version: 3.3.1 referrer-policy: specifier: ^1.2.0 version: 1.2.0 @@ -1045,6 +1053,9 @@ importers: sequelize: specifier: ^6.32.0 version: 6.32.0(sqlite3@5.1.6) + simple-oauth2: + specifier: 5.0.0 + version: 5.0.0 sqlite3: specifier: ^5.1.6 version: 5.1.6 @@ -1067,12 +1078,18 @@ importers: '@amazeelabs/prettier-config': specifier: 1.1.3 version: 1.1.3(prettier@2.8.8) + '@types/cookie-parser': + specifier: 1.4.3 + version: 1.4.3 '@types/cors': specifier: 2.8.13 version: 2.8.13 '@types/express': specifier: 4.17.17 version: 4.17.17 + '@types/express-session': + specifier: 1.17.7 + version: 1.17.7 '@types/express-ws': specifier: 3.0.1 version: 3.0.1 @@ -1082,6 +1099,9 @@ importers: '@types/node': specifier: 16.18.36 version: 16.18.36 + '@types/simple-oauth2': + specifier: 5.0.4 + version: 5.0.4 esbuild: specifier: 0.18.2 version: 0.18.2 @@ -1111,7 +1131,7 @@ importers: version: 5.1.3 vitest: specifier: 0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) packages/npm/@amazeelabs/publisher-elements: devDependencies: @@ -1396,7 +1416,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@swc/cli': specifier: 0.1.62 @@ -1505,7 +1525,7 @@ importers: version: 5.1.3 vitest: specifier: ^0.32.0 - version: 0.32.0 + version: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) devDependencies: '@amazeelabs/eslint-config': specifier: 1.4.43 @@ -1529,7 +1549,7 @@ importers: dependencies: gatsby: specifier: ^4.0.0 || ^5.0.0 - version: 5.10.0(babel-eslint@10.1.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) + version: 5.10.0(babel-eslint@10.1.0)(esbuild@0.18.2)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) packages/npm/verdaccio-git: dependencies: @@ -6004,6 +6024,24 @@ packages: dependencies: graphql: 16.6.0 + /@hapi/boom@10.0.1: + resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==} + dependencies: + '@hapi/hoek': 11.0.2 + dev: false + + /@hapi/bourne@3.0.0: + resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} + dev: false + + /@hapi/hoek@10.0.1: + resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==} + dev: false + + /@hapi/hoek@11.0.2: + resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==} + dev: false + /@hapi/hoek@9.3.0: resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -6012,6 +6050,14 @@ packages: dependencies: '@hapi/hoek': 9.3.0 + /@hapi/wreck@18.0.1: + resolution: {integrity: sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg==} + dependencies: + '@hapi/boom': 10.0.1 + '@hapi/bourne': 3.0.0 + '@hapi/hoek': 11.0.2 + dev: false + /@headlessui/react@1.7.15(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-OTO0XtoRQ6JPB1cKNFYBZv2Q0JMqMGNhYP1CjPvcJvjz8YGokz8oAj89HIYZGN0gZzn/4kk9iUpmMF4Q21Gsqw==} engines: {node: '>=10'} @@ -8275,7 +8321,7 @@ packages: react-refresh: 0.14.0 schema-utils: 3.1.2 source-map: 0.7.4 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /@pnpm/config.env-replace@1.1.0: resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} @@ -8297,7 +8343,6 @@ packages: /@polka/url@1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} - dev: true /@pwrs/lit-css@2.0.0: resolution: {integrity: sha512-Yb2Q+7ZlCfdCbQ4tvlpQ9uzwB2yc340fdEoeUu2FdO3w6z4+YLPQAPerV1XA8uFxQtSn88nCW4kH+J0TVL3Iyg==} @@ -10364,6 +10409,12 @@ packages: dependencies: '@types/node': 18.16.2 + /@types/cookie-parser@1.4.3: + resolution: {integrity: sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==} + dependencies: + '@types/express': 4.17.17 + dev: true + /@types/cookie@0.4.1: resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} @@ -10437,6 +10488,12 @@ packages: '@types/range-parser': 1.2.4 '@types/send': 0.17.1 + /@types/express-session@1.17.7: + resolution: {integrity: sha512-L25080PBYoRLu472HY/HNCxaXY8AaGgqGC8/p/8+BYMhG0RDOLQ1wpXOpAzr4Gi5TGozTKyJv5BVODM5UNyVMw==} + dependencies: + '@types/express': 4.17.17 + dev: true + /@types/express-ws@3.0.1: resolution: {integrity: sha512-VguRXzcpPBF0IggIGpUoM65cZJDfMQxoc6dKoCz1yLzcwcXW7ft60yhq3ygKhyEhEIQFtLrWjyz4AJ1qjmzCFw==} dependencies: @@ -10756,6 +10813,10 @@ packages: '@types/mime': 3.0.1 '@types/node': 18.16.2 + /@types/simple-oauth2@5.0.4: + resolution: {integrity: sha512-4SvTfmAa1fGUa1d07j9vIiC4o92bGh0ihPXmtS05udMMmNwVIaU2nZ706cC4wI8cJxOlHD4P/d5tzqvWYd+KxA==} + dev: true + /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} @@ -11039,7 +11100,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.11(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.59.11(supports-color@9.3.1)(typescript@5.1.3) '@typescript-eslint/utils': 5.59.11(eslint@8.36.0)(typescript@4.9.5) debug: 4.3.4(supports-color@9.3.1) eslint: 8.36.0 @@ -11059,7 +11120,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.59.11(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 5.59.11(supports-color@9.3.1)(typescript@5.1.3) '@typescript-eslint/utils': 5.59.11(eslint@8.36.0)(typescript@5.0.2) debug: 4.3.4(supports-color@9.3.1) eslint: 8.36.0 @@ -11178,48 +11239,6 @@ packages: transitivePeerDependencies: - supports-color - /@typescript-eslint/typescript-estree@5.59.11(typescript@4.9.5): - resolution: {integrity: sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.59.11 - '@typescript-eslint/visitor-keys': 5.59.11 - debug: 4.3.4(supports-color@9.3.1) - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.1 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/typescript-estree@5.59.11(typescript@5.0.2): - resolution: {integrity: sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.59.11 - '@typescript-eslint/visitor-keys': 5.59.11 - debug: 4.3.4(supports-color@9.3.1) - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.1 - tsutils: 3.21.0(typescript@5.0.2) - typescript: 5.0.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/utils@5.59.11(eslint@8.36.0)(typescript@4.9.5): resolution: {integrity: sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -11231,7 +11250,7 @@ packages: '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.59.11 '@typescript-eslint/types': 5.59.11 - '@typescript-eslint/typescript-estree': 5.59.11(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.59.11(supports-color@9.3.1)(typescript@5.1.3) eslint: 8.36.0 eslint-scope: 5.1.1 semver: 7.5.1 @@ -11251,7 +11270,7 @@ packages: '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.59.11 '@typescript-eslint/types': 5.59.11 - '@typescript-eslint/typescript-estree': 5.59.11(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 5.59.11(supports-color@9.3.1)(typescript@5.1.3) eslint: 8.36.0 eslint-scope: 5.1.1 semver: 7.5.1 @@ -11566,7 +11585,6 @@ packages: picocolors: 1.0.0 sirv: 2.0.3 vitest: 0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3) - dev: true /@vitest/utils@0.32.0: resolution: {integrity: sha512-53yXunzx47MmbuvcOPpLaVljHaeSu1G2dHdmy7+9ngMnQIkBQcvwOcoclWFnxDMxFbnq8exAfh3aKSZaK71J5A==} @@ -13054,7 +13072,7 @@ packages: loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /babel-loader@9.1.2(@babel/core@7.22.5)(webpack@5.81.0): resolution: {integrity: sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==} @@ -15760,9 +15778,22 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + /cookie-parser@1.4.6: + resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==} + engines: {node: '>= 0.8.0'} + dependencies: + cookie: 0.4.1 + cookie-signature: 1.0.6 + dev: false + /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + /cookie@0.4.1: + resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==} + engines: {node: '>= 0.6'} + dev: false + /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} @@ -16124,7 +16155,7 @@ packages: postcss-value-parser: 4.2.0 schema-utils: 3.1.2 semver: 7.5.1 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /css-loader@6.8.1(webpack@5.81.0): resolution: {integrity: sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==} @@ -16163,7 +16194,7 @@ packages: schema-utils: 3.1.2 serialize-javascript: 5.0.1 source-map: 0.6.1 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} @@ -17978,7 +18009,7 @@ packages: micromatch: 4.0.5 normalize-path: 3.0.0 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /eslint@4.19.1: resolution: {integrity: sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==} @@ -18431,6 +18462,22 @@ packages: resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==} dev: true + /express-session@1.17.3: + resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==} + engines: {node: '>= 0.8.0'} + dependencies: + cookie: 0.4.2 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + on-headers: 1.0.2 + parseurl: 1.3.3 + safe-buffer: 5.2.1 + uid-safe: 2.1.5 + transitivePeerDependencies: + - supports-color + dev: false + /express-ws@5.0.2(express@4.18.2): resolution: {integrity: sha512-0uvmuk61O9HXgLhGl3QhNSEtRsQevtmbL94/eILaliEADZBHZOQUAiHFrGPrgsjikohyrmSG5g+sCfASTt0lkQ==} engines: {node: '>=4.5.0'} @@ -18799,7 +18846,6 @@ packages: /fflate@0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} - dev: true /figgy-pudding@3.5.2: resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} @@ -18870,7 +18916,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /file-match@1.0.2: resolution: {integrity: sha512-g9p6bZV3HlSUM35QPvFWiP/PckDVe5jLPDhx6PfMuy06o+htesJTyDu7zRdXnOm3BY8pXmxb+QY5qIcsoWMGNg==} @@ -19242,7 +19288,7 @@ packages: semver: 7.5.1 tapable: 1.1.3 typescript: 5.1.3 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /fork-ts-checker-webpack-plugin@6.5.3(eslint@8.42.0)(typescript@5.1.3)(webpack@4.46.0): resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} @@ -20396,207 +20442,6 @@ packages: - webpack-hot-middleware - webpack-plugin-serve - /gatsby@5.10.0(babel-eslint@10.1.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3): - resolution: {integrity: sha512-/CsCBskAzrit4olmzzN58v6ayvUYUwVRwQVxkHTDb8b9bGRy0VBG9Ntsq/IvGtEYRvYd6VrWpj/U0Xfcf+pnDg==} - engines: {node: '>=18.0.0'} - hasBin: true - requiresBuild: true - peerDependencies: - react: ^18.0.0 || ^0.0.0 - react-dom: ^18.0.0 || ^0.0.0 - dependencies: - '@babel/code-frame': 7.22.5 - '@babel/core': 7.22.5 - '@babel/eslint-parser': 7.21.3(@babel/core@7.22.5)(eslint@7.32.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/parser': 7.22.5 - '@babel/runtime': 7.21.0 - '@babel/traverse': 7.22.5 - '@babel/types': 7.22.5 - '@builder.io/partytown': 0.7.6 - '@gatsbyjs/reach-router': 2.0.1(react-dom@18.2.0)(react@18.2.0) - '@gatsbyjs/webpack-hot-middleware': 2.25.3 - '@graphql-codegen/add': 3.2.3(graphql@16.6.0) - '@graphql-codegen/core': 2.6.8(graphql@16.6.0) - '@graphql-codegen/plugin-helpers': 2.7.2(graphql@16.6.0) - '@graphql-codegen/typescript': 2.8.8(graphql@16.6.0) - '@graphql-codegen/typescript-operations': 2.5.13(graphql@16.6.0) - '@graphql-tools/code-file-loader': 7.3.23(@babel/core@7.22.5)(graphql@16.6.0) - '@graphql-tools/load': 7.8.14(graphql@16.6.0) - '@jridgewell/trace-mapping': 0.3.18 - '@nodelib/fs.walk': 1.2.8 - '@parcel/cache': 2.8.3(@parcel/core@2.8.3) - '@parcel/core': 2.8.3 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(react-refresh@0.14.0)(webpack@5.81.0) - '@types/http-proxy': 1.17.11 - '@typescript-eslint/eslint-plugin': 5.59.11(@typescript-eslint/parser@5.59.1)(eslint@8.42.0)(typescript@5.1.3) - '@typescript-eslint/parser': 5.59.1(eslint@8.42.0)(typescript@5.1.3) - '@vercel/webpack-asset-relocator-loader': 1.7.3 - acorn-loose: 8.3.0 - acorn-walk: 8.2.0 - address: 1.2.2 - anser: 2.1.1 - autoprefixer: 10.4.14(postcss@8.4.24) - axios: 0.21.4(debug@4.3.4) - babel-jsx-utils: 1.1.0 - babel-loader: 8.3.0(@babel/core@7.22.5)(webpack@5.81.0) - babel-plugin-add-module-exports: 1.0.4 - babel-plugin-dynamic-import-node: 2.3.3 - babel-plugin-lodash: 3.3.4 - babel-plugin-remove-graphql-queries: 5.10.0(@babel/core@7.22.5)(gatsby@5.10.0) - babel-preset-gatsby: 3.10.0(@babel/core@7.22.5)(core-js@3.30.2) - better-opn: 2.1.1 - bluebird: 3.7.2 - browserslist: 4.21.5 - cache-manager: 2.11.1 - chalk: 4.1.2 - chokidar: 3.5.3 - common-tags: 1.8.2 - compression: 1.7.4 - cookie: 0.5.0 - core-js: 3.30.2 - cors: 2.8.5 - css-loader: 5.2.7(webpack@5.81.0) - css-minimizer-webpack-plugin: 2.0.0(webpack@5.81.0) - css.escape: 1.5.1 - date-fns: 2.30.0 - debug: 4.3.4(supports-color@9.3.1) - deepmerge: 4.3.1 - detect-port: 1.5.1 - devcert: 1.2.2 - dotenv: 8.6.0 - enhanced-resolve: 5.13.0 - error-stack-parser: 2.1.4 - eslint: 7.32.0 - eslint-config-react-app: 6.0.0(@typescript-eslint/eslint-plugin@5.59.11)(@typescript-eslint/parser@5.59.1)(babel-eslint@10.1.0)(eslint-plugin-flowtype@5.10.0)(eslint-plugin-import@2.27.5)(eslint-plugin-jsx-a11y@6.7.1)(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.32.2)(eslint@7.32.0)(typescript@5.1.3) - eslint-plugin-flowtype: 5.10.0(eslint@8.42.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.59.1)(eslint@8.42.0) - eslint-plugin-jsx-a11y: 6.7.1(eslint@8.42.0) - eslint-plugin-react: 7.32.2(eslint@8.42.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.42.0) - eslint-webpack-plugin: 2.7.0(eslint@7.32.0)(webpack@5.81.0) - event-source-polyfill: 1.0.31 - execa: 5.1.1 - express: 4.18.2 - express-http-proxy: 1.6.3 - fastest-levenshtein: 1.0.16 - fastq: 1.15.0 - file-loader: 6.2.0(webpack@5.81.0) - find-cache-dir: 3.3.2 - fs-exists-cached: 1.0.0 - fs-extra: 11.1.1 - gatsby-cli: 5.10.0 - gatsby-core-utils: 4.10.0 - gatsby-graphiql-explorer: 3.10.0 - gatsby-legacy-polyfills: 3.10.0 - gatsby-link: 5.10.0(@gatsbyjs/reach-router@2.0.1)(react-dom@18.2.0)(react@18.2.0) - gatsby-page-utils: 3.10.0 - gatsby-parcel-config: 1.10.0(@parcel/core@2.8.3) - gatsby-plugin-page-creator: 5.10.0(gatsby@5.10.0)(graphql@16.6.0) - gatsby-plugin-typescript: 5.10.0(gatsby@5.10.0) - gatsby-plugin-utils: 4.10.0(gatsby@5.10.0)(graphql@16.6.0) - gatsby-react-router-scroll: 6.10.0(@gatsbyjs/reach-router@2.0.1)(react-dom@18.2.0)(react@18.2.0) - gatsby-script: 2.10.0(@gatsbyjs/reach-router@2.0.1)(react-dom@18.2.0)(react@18.2.0) - gatsby-telemetry: 4.10.0 - gatsby-worker: 2.10.0 - glob: 7.2.3 - globby: 11.1.0 - got: 11.8.6 - graphql: 16.6.0 - graphql-compose: 9.0.10(graphql@16.6.0) - graphql-http: 1.18.0(graphql@16.6.0) - graphql-tag: 2.12.6(graphql@16.6.0) - hasha: 5.2.2 - invariant: 2.2.4 - is-relative: 1.0.0 - is-relative-url: 3.0.0 - joi: 17.9.2 - json-loader: 0.5.7 - latest-version: 7.0.0 - lmdb: 2.5.3 - lodash: 4.17.21 - meant: 1.0.3 - memoizee: 0.4.15 - micromatch: 4.0.5 - mime: 3.0.0 - mini-css-extract-plugin: 1.6.2(webpack@5.81.0) - mitt: 1.2.0 - moment: 2.29.4 - multer: 1.4.5-lts.1 - node-fetch: 2.6.11 - node-html-parser: 5.4.2 - normalize-path: 3.0.0 - null-loader: 4.0.1(webpack@5.81.0) - opentracing: 0.14.7 - p-defer: 3.0.0 - parseurl: 1.3.3 - physical-cpu-count: 2.0.0 - platform: 1.3.6 - postcss: 8.4.24 - postcss-flexbugs-fixes: 5.0.2(postcss@8.4.24) - postcss-loader: 5.3.0(postcss@8.4.24)(webpack@5.81.0) - prompts: 2.4.2 - prop-types: 15.8.1 - query-string: 6.14.1 - raw-loader: 4.0.2(webpack@5.81.0) - react: 18.2.0 - react-dev-utils: 12.0.1(eslint@7.32.0)(typescript@5.1.3)(webpack@5.81.0) - react-dom: 18.2.0(react@18.2.0) - react-refresh: 0.14.0 - react-server-dom-webpack: 0.0.0-experimental-c8b778b7f-20220825(react@18.2.0)(webpack@5.81.0) - redux: 4.2.1 - redux-thunk: 2.4.2(redux@4.2.1) - resolve-from: 5.0.0 - semver: 7.5.1 - shallow-compare: 1.2.2 - signal-exit: 3.0.7 - slugify: 1.6.6 - socket.io: 4.6.1 - socket.io-client: 4.6.1 - stack-trace: 0.0.10 - string-similarity: 1.2.2 - strip-ansi: 6.0.1 - style-loader: 2.0.0(webpack@5.81.0) - terser-webpack-plugin: 5.3.7(webpack@5.81.0) - tmp: 0.2.1 - true-case-path: 2.2.1 - type-of: 2.0.1 - url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.81.0) - uuid: 8.3.2 - webpack: 5.81.0 - webpack-dev-middleware: 4.3.0(webpack@5.81.0) - webpack-merge: 5.8.0 - webpack-stats-plugin: 1.1.1 - webpack-virtual-modules: 0.5.0 - xstate: 4.37.2 - yaml-loader: 0.8.0 - optionalDependencies: - gatsby-sharp: 1.10.0 - transitivePeerDependencies: - - '@swc/core' - - '@types/webpack' - - babel-eslint - - bufferutil - - clean-css - - csso - - encoding - - esbuild - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - eslint-plugin-jest - - eslint-plugin-testing-library - - sockjs-client - - supports-color - - type-fest - - typescript - - uglify-js - - utf-8-validate - - vue-template-compiler - - webpack-cli - - webpack-dev-server - - webpack-hot-middleware - - webpack-plugin-serve - /gatsby@5.9.0(babel-eslint@10.1.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3): resolution: {integrity: sha512-XjKwjlscSgOZqqXCY1+Y3VX9+AyMBZMGer2xt6BxpXAz+uEHomdiVpToncka5BlrxgDYkDmx83yIBZKN9uAwiw==} engines: {node: '>=18.0.0'} @@ -20758,13 +20603,13 @@ packages: string-similarity: 1.2.2 strip-ansi: 6.0.1 style-loader: 2.0.0(webpack@5.81.0) - terser-webpack-plugin: 5.3.7(webpack@5.81.0) + terser-webpack-plugin: 5.3.7(esbuild@0.17.19)(webpack@5.81.0) tmp: 0.2.1 true-case-path: 2.2.1 type-of: 2.0.1 url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.81.0) uuid: 8.3.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) webpack-dev-middleware: 4.3.0(webpack@5.81.0) webpack-merge: 5.8.0 webpack-stats-plugin: 1.1.1 @@ -21515,7 +21360,6 @@ packages: webidl-conversions: 7.0.0 whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 - dev: true /har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} @@ -25369,6 +25213,16 @@ packages: readable-stream: 2.3.8 dev: true + /memorystore@1.6.7: + resolution: {integrity: sha512-OZnmNY/NDrKohPQ+hxp0muBcBKrzKNtHr55DbqSx9hLsYVNnomSAMRAtI7R64t3gf3ID7tHQA7mG4oL3Hu9hdw==} + engines: {node: '>=0.10'} + dependencies: + debug: 4.3.4(supports-color@9.3.1) + lru-cache: 4.1.5 + transitivePeerDependencies: + - supports-color + dev: false + /meow@5.0.0: resolution: {integrity: sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==} engines: {node: '>=6'} @@ -25796,7 +25650,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) webpack-sources: 1.4.3 /minimalistic-assert@1.0.1: @@ -26094,7 +25948,6 @@ packages: /mrmime@1.0.1: resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} engines: {node: '>=10'} - dev: true /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -26944,7 +26797,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -28172,7 +28025,7 @@ packages: klona: 2.0.6 postcss: 8.4.24 semver: 7.5.1 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /postcss-markdown@0.36.0(postcss-syntax@0.36.2)(postcss@7.0.39): resolution: {integrity: sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==} @@ -29053,7 +28906,6 @@ packages: /random-bytes@1.0.0: resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} engines: {node: '>= 0.8'} - dev: true /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -29097,7 +28949,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} @@ -29153,7 +29005,7 @@ packages: strip-ansi: 6.0.1 text-table: 0.2.0 typescript: 5.1.3 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) transitivePeerDependencies: - eslint - supports-color @@ -29326,7 +29178,7 @@ packages: loose-envify: 1.4.0 neo-async: 2.6.2 react: 18.2.0 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /react-string-replace@0.4.4: resolution: {integrity: sha512-FAMkhxmDpCsGTwTZg7p/2v+/GTmxAp73so3fbSvlAcBBX36ujiGRNEaM/1u+jiYQrArhns+7eE92g2pi5E5FUA==} @@ -30761,6 +30613,17 @@ packages: - supports-color dev: false + /simple-oauth2@5.0.0: + resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==} + dependencies: + '@hapi/hoek': 10.0.1 + '@hapi/wreck': 18.0.1 + debug: 4.3.4(supports-color@9.3.1) + joi: 17.9.2 + transitivePeerDependencies: + - supports-color + dev: false + /simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} dependencies: @@ -30780,7 +30643,6 @@ packages: '@polka/url': 1.0.0-next.21 mrmime: 1.0.1 totalist: 3.0.1 - dev: true /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -31708,7 +31570,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /style-loader@3.3.3(webpack@5.81.0): resolution: {integrity: sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==} @@ -32252,7 +32114,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.17.1 webpack: 5.81.0(esbuild@0.17.19) - dev: true /terser-webpack-plugin@5.3.7(esbuild@0.18.2)(webpack@5.81.0): resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} @@ -32278,29 +32139,6 @@ packages: terser: 5.17.1 webpack: 5.81.0(esbuild@0.18.2) - /terser-webpack-plugin@5.3.7(webpack@5.81.0): - resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - dependencies: - '@jridgewell/trace-mapping': 0.3.18 - jest-worker: 27.5.1 - schema-utils: 3.1.2 - serialize-javascript: 6.0.1 - terser: 5.17.1 - webpack: 5.81.0 - /terser@4.8.1: resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} engines: {node: '>=6.0.0'} @@ -32551,7 +32389,6 @@ packages: /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - dev: true /touch@3.1.0: resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} @@ -33017,7 +32854,6 @@ packages: engines: {node: '>= 0.8'} dependencies: random-bytes: 1.0.0 - dev: true /ulid@2.3.0: resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==} @@ -33385,7 +33221,7 @@ packages: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} @@ -33704,27 +33540,6 @@ packages: - supports-color - terser - /vite-node@0.32.0(@types/node@18.16.2): - resolution: {integrity: sha512-220P/y8YacYAU+daOAqiGEFXx2A8AwjadDzQqos6wSukjvvTWNqleJSwoUn0ckyNdjHIKoxn93Nh1vWBqEKr3Q==} - engines: {node: '>=v14.18.0'} - hasBin: true - dependencies: - cac: 6.7.14 - debug: 4.3.4(supports-color@9.3.1) - mlly: 1.2.0 - pathe: 1.1.0 - picocolors: 1.0.0 - vite: 4.3.9(@types/node@18.16.2) - transitivePeerDependencies: - - '@types/node' - - less - - sass - - stylus - - sugarss - - supports-color - - terser - dev: true - /vite-plugin-dts@2.3.0(@types/node@18.16.2)(vite@4.3.9): resolution: {integrity: sha512-WbJgGtsStgQhdm3EosYmIdTGbag5YQpZ3HXWUAPCDyoXI5qN6EY0V7NXq0lAmnv9hVQsvh0htbYcg0Or5Db9JQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -33846,70 +33661,6 @@ packages: fsevents: 2.3.2 dev: true - /vitest@0.32.0: - resolution: {integrity: sha512-SW83o629gCqnV3BqBnTxhB10DAwzwEx3z+rqYZESehUB+eWsJxwcBQx7CKy0otuGMJTYh7qCVuUX23HkftGl/Q==} - engines: {node: '>=v14.18.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - playwright: '*' - safaridriver: '*' - webdriverio: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true - dependencies: - '@types/chai': 4.3.5 - '@types/chai-subset': 1.3.3 - '@types/node': 18.16.18 - '@vitest/expect': 0.32.0 - '@vitest/runner': 0.32.0 - '@vitest/snapshot': 0.32.0 - '@vitest/spy': 0.32.0 - '@vitest/utils': 0.32.0 - acorn: 8.8.2 - acorn-walk: 8.2.0 - cac: 6.7.14 - chai: 4.3.7 - concordance: 5.0.4 - debug: 4.3.4(supports-color@9.3.1) - local-pkg: 0.4.3 - magic-string: 0.30.0 - pathe: 1.1.0 - picocolors: 1.0.0 - std-env: 3.3.2 - strip-literal: 1.0.1 - tinybench: 2.5.0 - tinypool: 0.5.0 - vite: 4.3.9(@types/node@18.16.18) - vite-node: 0.32.0(@types/node@18.16.18) - why-is-node-running: 2.2.2 - transitivePeerDependencies: - - less - - sass - - stylus - - sugarss - - supports-color - - terser - /vitest@0.32.0(@vitest/ui@0.32.0)(happy-dom@9.20.3): resolution: {integrity: sha512-SW83o629gCqnV3BqBnTxhB10DAwzwEx3z+rqYZESehUB+eWsJxwcBQx7CKy0otuGMJTYh7qCVuUX23HkftGl/Q==} engines: {node: '>=v14.18.0'} @@ -33943,7 +33694,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 18.16.2 + '@types/node': 18.16.18 '@vitest/expect': 0.32.0 '@vitest/runner': 0.32.0 '@vitest/snapshot': 0.32.0 @@ -33965,8 +33716,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.5.0 tinypool: 0.5.0 - vite: 4.3.9(@types/node@18.16.2) - vite-node: 0.32.0(@types/node@18.16.2) + vite: 4.3.9(@types/node@18.16.18) + vite-node: 0.32.0(@types/node@18.16.18) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -33975,7 +33726,6 @@ packages: - sugarss - supports-color - terser - dev: true /vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} @@ -34095,7 +33845,6 @@ packages: /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - dev: true /webpack-assets-manifest@5.1.0(webpack@5.81.0): resolution: {integrity: sha512-kPuTMEjBrqZQVJ5M6yXNBCEdFbQQn7p+loNXt8NOeDFaAbsNFWqqwR0YL1mfG5LbwhK5FLXWXpuK3GuIIZ46rg==} @@ -34110,7 +33859,7 @@ packages: lodash.has: 4.5.2 schema-utils: 3.1.2 tapable: 2.2.1 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) dev: false /webpack-dev-middleware@4.3.0(webpack@5.81.0): @@ -34125,7 +33874,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 3.1.2 - webpack: 5.81.0 + webpack: 5.81.0(esbuild@0.17.19) /webpack-dev-middleware@5.3.3(webpack@5.81.0): resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} @@ -34216,45 +33965,6 @@ packages: - supports-color dev: true - /webpack@5.81.0: - resolution: {integrity: sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - dependencies: - '@types/eslint-scope': 3.7.4 - '@types/estree': 1.0.1 - '@webassemblyjs/ast': 1.11.5 - '@webassemblyjs/wasm-edit': 1.11.5 - '@webassemblyjs/wasm-parser': 1.11.5 - acorn: 8.8.2 - acorn-import-assertions: 1.8.0(acorn@8.8.2) - browserslist: 4.21.5 - chrome-trace-event: 1.0.3 - enhanced-resolve: 5.13.0 - es-module-lexer: 1.2.1 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.1.2 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.7(webpack@5.81.0) - watchpack: 2.4.0 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - /webpack@5.81.0(@swc/core@1.3.64): resolution: {integrity: sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==} engines: {node: '>=10.13.0'} @@ -34332,7 +34042,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /webpack@5.81.0(esbuild@0.18.2): resolution: {integrity: sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==} @@ -34387,7 +34096,6 @@ packages: engines: {node: '>=12'} dependencies: iconv-lite: 0.6.3 - dev: true /whatwg-fetch@2.0.4: resolution: {integrity: sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==} @@ -34396,7 +34104,6 @@ packages: /whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} - dev: true /whatwg-url@11.0.0: resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} @@ -35045,3 +34752,7 @@ packages: - eslint-import-resolver-webpack - supports-color dev: false + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false