Authentification JWT sur le backend super-graph #8
2
Makefile
2
Makefile
|
@ -17,7 +17,7 @@ down:
|
|||
docker-compose down -v --remove-orphans
|
||||
|
||||
db-shell:
|
||||
docker-compose exec postgres psql -Usupergraph
|
||||
docker-compose exec postgres psql -Udaddy
|
||||
|
||||
hydra-shell:
|
||||
docker-compose exec hydra /bin/sh
|
|
@ -26,13 +26,15 @@ Les services suivants devraient être disponibles après démarrage de l'environ
|
|||
|Service|Type|Accès|Description|
|
||||
|-------|----|-----|-----------|
|
||||
|Application React|HTTP (UI)|http://localhost:8081/|Page d'accueil de l'application React (serveur Webpack)|
|
||||
|Interface Web GraphQL|HTTP (UI)|http://localhost:8080/|Interface Web de développement de l'API GraphQL|
|
||||
|Interface Web GraphQL|HTTP (UI)|http://localhost:8080/|Interface Web de développement de l'API GraphQL **\***|
|
||||
|Serveur GraphQL|HTTP (GraphQL)|http://localhost:8080/api/v1/graphql|Point d'entrée de l'API GraphQL|
|
||||
|Serveur Hydra|HTTP (ReST)|http://localhost:4444|Point d'entrée pour l'API OAuth2 d'[Hydra](https://www.ory.sh/hydra/docs/)|
|
||||
|Serveur Hydra Passwordless|HTTP|http://localhost:3000|Point d'entrée pour la ["Login/Consent App"](https://www.ory.sh/hydra/docs/implementing-consent) [hydra-passwordless](https://forge.cadoles.com/wpetit/hydra-passwordless)|
|
||||
|Serveur FakeSMTP|HTTP|http://localhost:8082|Interface web du serveur [FakeSMTP](https://forge.cadoles.com/wpetit/fake-smtp)
|
||||
|Serveur PostgreSQL|TCP/IP (PostgreSQL)|`127.0.0.1:5432`|Port de connexion à la base de données PostgreSQL de développement|
|
||||
|
||||
**\*** Pensez à passer l'attribut `auth_fail_block: false` dans le fichier `backend/config/dev.yml` si vous voulez pouvoir utiliser cette interface sans avoir à définir l'entête `Authorization`.
|
||||
|
||||
#### Fichiers/répertoires notables
|
||||
|
||||
|Chemin|Description|
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* fetchUser */
|
||||
|
||||
variables {
|
||||
"email": ""
|
||||
}
|
||||
|
||||
|
||||
query fetchUser {
|
||||
user(where: {email: {eq: $email}}) {
|
||||
id
|
||||
created_at
|
||||
updated_at
|
||||
email,
|
||||
full_name
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
app_name: "Test Development"
|
||||
app_name: "Daddy Dev"
|
||||
host_port: 0.0.0.0:8080
|
||||
web_ui: true
|
||||
|
||||
# debug, error, warn, info
|
||||
log_level: "info"
|
||||
log_level: debug
|
||||
|
||||
# enable or disable http compression (uses gzip)
|
||||
http_compress: true
|
||||
|
@ -15,7 +15,7 @@ http_compress: true
|
|||
production: false
|
||||
|
||||
# Throw a 401 on auth failure for queries that need auth
|
||||
auth_fail_block: false
|
||||
auth_fail_block: true
|
||||
|
||||
# Latency tracing for database queries and remote joins
|
||||
# the resulting latency information is returned with the
|
||||
|
@ -42,6 +42,8 @@ secret_key: supercalifajalistics
|
|||
# An origin may contain a wildcard (*) to replace 0 or more
|
||||
# characters (i.e.: http://*.domain.com).
|
||||
cors_allowed_origins: ["*"]
|
||||
cors_allowed_headers: ["Authorization", "Content-Type", "Mode"]
|
||||
cors_allowed_methods: ["POST"]
|
||||
|
||||
# Debug Cross Origin Resource Sharing requests
|
||||
cors_debug: false
|
||||
|
@ -65,18 +67,16 @@ cors_debug: false
|
|||
auth:
|
||||
# Can be 'rails', 'jwt' or 'header'
|
||||
type: jwt
|
||||
cookie: _supergraph_session
|
||||
#cookie: _supergraph_session
|
||||
|
||||
# Comment this out if you want to disable setting
|
||||
# the user_id via a header for testing.
|
||||
# Disable in production
|
||||
creds_in_header: true
|
||||
#creds_in_header: false
|
||||
|
||||
# jwt:
|
||||
# provider: auth0
|
||||
# secret: abc335bfcfdb04e50db5bb0a4d67ab9
|
||||
# public_key_file: /secrets/public_key.pem
|
||||
# public_key_type: ecdsa #rsa
|
||||
jwt:
|
||||
provider: hydra
|
||||
jwks_url: http://hydra:4444/.well-known/jwks.json
|
||||
|
||||
# header:
|
||||
# name: dnt
|
||||
|
@ -87,16 +87,16 @@ auth:
|
|||
# In this example actions using this auth can only be
|
||||
# called from the Google Appengine Cron service that
|
||||
# sets a special header to all it's requests
|
||||
auths:
|
||||
- name: from_taskqueue
|
||||
type: header
|
||||
header:
|
||||
name: X-Appengine-Cron
|
||||
exists: true
|
||||
# auths:
|
||||
# - name: from_taskqueue
|
||||
# type: header
|
||||
# header:
|
||||
# name: X-Appengine-Cron
|
||||
# exists: true
|
||||
|
||||
database:
|
||||
type: postgres
|
||||
host: db
|
||||
host: localhost
|
||||
port: 5432
|
||||
dbname: daddy
|
||||
user: daddy
|
||||
|
@ -105,19 +105,19 @@ database:
|
|||
#schema: "public"
|
||||
#pool_size: 10
|
||||
#max_retries: 0
|
||||
#log_level: "debug"
|
||||
log_level: "debug"
|
||||
|
||||
# Set session variable "user.id" to the user id
|
||||
# Enable this if you need the user id in triggers, etc
|
||||
set_user_id: false
|
||||
set_user_id: true
|
||||
|
||||
# database ping timeout is used for db health checking
|
||||
ping_timeout: 1m
|
||||
|
||||
# Define additional variables here to be used with filters
|
||||
variables:
|
||||
#admin_account_id: "5"
|
||||
admin_account_id: "sql:select id from users where admin = true limit 1"
|
||||
# admin_account_id: "5"
|
||||
# admin_account_id: "sql:select id from users where admin = true limit 1"
|
||||
|
||||
|
||||
# Field and table names that you wish to block
|
||||
|
@ -135,67 +135,89 @@ database:
|
|||
# which in this case refreshes a materialized view in the database.
|
||||
# The auth_name is from one of the configured auths
|
||||
actions:
|
||||
- name: refresh_leaderboard_users
|
||||
sql: REFRESH MATERIALIZED VIEW CONCURRENTLY "leaderboard_users"
|
||||
auth_name: from_taskqueue
|
||||
# - name: refresh_leaderboard_users
|
||||
# sql: REFRESH MATERIALIZED VIEW CONCURRENTLY "leaderboard_users"
|
||||
# auth_name: from_taskqueue
|
||||
|
||||
tables:
|
||||
- name: customers
|
||||
remotes:
|
||||
- name: payments
|
||||
id: stripe_id
|
||||
url: http://rails_app:3000/stripe/$id
|
||||
path: data
|
||||
# debug: true
|
||||
pass_headers:
|
||||
- cookie
|
||||
set_headers:
|
||||
- name: Host
|
||||
value: 0.0.0.0
|
||||
# - name: customers
|
||||
# remotes:
|
||||
# - name: payments
|
||||
# id: stripe_id
|
||||
# url: http://rails_app:3000/stripe/$id
|
||||
# path: data
|
||||
# # debug: true
|
||||
# pass_headers:
|
||||
# - cookie
|
||||
# set_headers:
|
||||
# - name: Host
|
||||
# value: 0.0.0.0
|
||||
# - name: Authorization
|
||||
# value: Bearer <stripe_api_key>
|
||||
|
||||
- # You can create new fields that have a
|
||||
# real db table backing them
|
||||
name: me
|
||||
table: users
|
||||
# - # You can create new fields that have a
|
||||
# # real db table backing them
|
||||
# name: me
|
||||
# table: users
|
||||
|
||||
|
||||
#roles_query: "SELECT * FROM users WHERE id = $user_id"
|
||||
roles_query: "select * from users where users.email = $user_id"
|
||||
|
||||
roles:
|
||||
# Rôle par défaut si l'utilisateur n'existe pas dans la table `users`
|
||||
- name: anon
|
||||
tables:
|
||||
- name: users
|
||||
query:
|
||||
limit: 10
|
||||
# insert:
|
||||
# block: true
|
||||
# query:
|
||||
# block: true
|
||||
# update:
|
||||
# block: true
|
||||
# delete:
|
||||
# block: true
|
||||
|
||||
# Rôle par défaut si l'utilisateur existe dans la table `users`
|
||||
# mais que la valeur de la colonne `role` n'est pas définie
|
||||
- name: user
|
||||
tables:
|
||||
- name: users
|
||||
query:
|
||||
filters: ["{ id: { _eq: $user_id } }"]
|
||||
|
||||
- name: products
|
||||
query:
|
||||
limit: 50
|
||||
filters: ["{ user_id: { eq: $user_id } }"]
|
||||
disable_functions: false
|
||||
|
||||
insert:
|
||||
filters: ["{ user_id: { eq: $user_id } }"]
|
||||
presets:
|
||||
- user_id: "$user_id"
|
||||
- created_at: "now"
|
||||
|
||||
block: true
|
||||
query:
|
||||
filters: ["{ email: { _eq: $user_id } }"]
|
||||
update:
|
||||
filters: ["{ user_id: { eq: $user_id } }"]
|
||||
presets:
|
||||
- updated_at: "now"
|
||||
|
||||
columns:
|
||||
- full_name
|
||||
filters: ["{ email: { _eq: $user_id } }"]
|
||||
delete:
|
||||
block: true
|
||||
|
||||
- name: admin
|
||||
match: role = 'admin'
|
||||
tables:
|
||||
- name: users
|
||||
|
||||
# - name: products
|
||||
# query:
|
||||
# limit: 50
|
||||
# filters: ["{ user_id: { eq: $user_id } }"]
|
||||
# disable_functions: false
|
||||
|
||||
# insert:
|
||||
# filters: ["{ user_id: { eq: $user_id } }"]
|
||||
# presets:
|
||||
# - user_id: "$user_id"
|
||||
# - created_at: "now"
|
||||
|
||||
# update:
|
||||
# filters: ["{ user_id: { eq: $user_id } }"]
|
||||
# presets:
|
||||
# - updated_at: "now"
|
||||
|
||||
# delete:
|
||||
# block: true
|
||||
|
||||
# - name: admin
|
||||
# match: id = 1000
|
||||
# tables:
|
||||
|
|
|
@ -5,7 +5,8 @@ CREATE TABLE public.users (
|
|||
full_name text,
|
||||
email text UNIQUE NOT NULL CHECK (length(email) < 255),
|
||||
created_at timestamptz NOT NULL NOT NULL DEFAULT NOW(),
|
||||
updated_at timestamptz NOT NULL NOT NULL DEFAULT NOW()
|
||||
updated_at timestamptz NOT NULL NOT NULL DEFAULT NOW(),
|
||||
role varchar(64)
|
||||
);
|
||||
|
||||
---- create above / drop below ----
|
||||
|
@ -14,4 +15,3 @@ CREATE TABLE public.users (
|
|||
-- then delete the separator line above.
|
||||
|
||||
DROP TABLE public.users
|
||||
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
// Example script to seed database
|
||||
// Voir https://supergraph.dev/docs/seed
|
||||
|
||||
var users = [];
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
var data = {
|
||||
full_name: fake.name(),
|
||||
email: fake.email()
|
||||
var users = [
|
||||
{
|
||||
full_name: 'Admin',
|
||||
email: 'admin@cadoles.com',
|
||||
role: 'admin',
|
||||
},
|
||||
{
|
||||
full_name: 'User 1',
|
||||
email: 'user1@cadoles.com',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
full_name: 'User 2',
|
||||
email: 'user2@cadoles.com',
|
||||
role: 'user',
|
||||
},
|
||||
{
|
||||
full_name: 'User 3',
|
||||
email: 'user3@cadoles.com',
|
||||
role: 'user',
|
||||
}
|
||||
];
|
||||
|
||||
for (var user, i = 0; (user = users[i]); i++) {
|
||||
var res = graphql(" \
|
||||
mutation { \
|
||||
user(insert: $data) { \
|
||||
id \
|
||||
} \
|
||||
}", { data: data })
|
||||
|
||||
users.push(res.user)
|
||||
}", { data: user });
|
||||
}
|
|
@ -50,6 +50,7 @@ services:
|
|||
HYDRA_ADMIN_URL: http://localhost:4445
|
||||
SERVE_PUBLIC_CORS_ENABLED: "true"
|
||||
SERVE_PUBLIC_CORS_ALLOWED_ORIGINS: http://localhost:8081
|
||||
WEBFINGER_JWKS_BROADCAST_KEYS: hydra.openid.id-token,hydra.jwt.access-token
|
||||
ports:
|
||||
- 4444:4444
|
||||
command: hydra serve all --dangerous-force-http
|
||||
|
|
|
@ -1093,6 +1093,49 @@
|
|||
"integrity": "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg==",
|
||||
"dev": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
||||
"integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "2.0.3",
|
||||
"run-parallel": "^1.1.9"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.stat": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
|
||||
"integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
|
||||
"dev": true
|
||||
},
|
||||
"@nodelib/fs.walk": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
|
||||
"integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.scandir": "2.1.3",
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@npmcli/move-file": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
|
||||
"integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mkdirp": "^1.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
|
||||
|
@ -1585,6 +1628,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"aggregate-error": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
|
||||
"integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clean-stack": "^2.0.0",
|
||||
"indent-string": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"indent-string": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
|
||||
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
|
||||
|
@ -3272,6 +3333,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"clean-stack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
|
||||
"dev": true
|
||||
},
|
||||
"clean-webpack-plugin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
|
||||
|
@ -3542,6 +3609,258 @@
|
|||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
||||
"dev": true
|
||||
},
|
||||
"copy-webpack-plugin": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.0.2.tgz",
|
||||
"integrity": "sha512-9Gm8X0c6eXlKnmltMPFCBeGOKjtcRIyTt4VaO3k1TkNgVTe5Ov2lYsYVuyLp0kp8DItO3apewflM+1GYgh6V2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^15.0.4",
|
||||
"fast-glob": "^3.2.2",
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"glob-parent": "^5.1.1",
|
||||
"globby": "^11.0.1",
|
||||
"loader-utils": "^2.0.0",
|
||||
"normalize-path": "^3.0.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"schema-utils": "^2.7.0",
|
||||
"serialize-javascript": "^3.1.0",
|
||||
"webpack-sources": "^1.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true
|
||||
},
|
||||
"cacache": {
|
||||
"version": "15.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.4.tgz",
|
||||
"integrity": "sha512-YlnKQqTbD/6iyoJvEY3KJftjrdBYroCbxxYXzhOzsFLWlp6KX4BOlEf4mTx0cMUfVaTS3ENL2QtDWeRYoGLkkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@npmcli/move-file": "^1.0.1",
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"glob": "^7.1.4",
|
||||
"infer-owner": "^1.0.4",
|
||||
"lru-cache": "^5.1.1",
|
||||
"minipass": "^3.1.1",
|
||||
"minipass-collect": "^1.0.2",
|
||||
"minipass-flush": "^1.0.5",
|
||||
"minipass-pipeline": "^1.2.2",
|
||||
"mkdirp": "^1.0.3",
|
||||
"p-map": "^4.0.0",
|
||||
"promise-inflight": "^1.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ssri": "^8.0.0",
|
||||
"tar": "^6.0.2",
|
||||
"unique-filename": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"dev": true
|
||||
},
|
||||
"find-cache-dir": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
|
||||
"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commondir": "^1.0.1",
|
||||
"make-dir": "^3.0.2",
|
||||
"pkg-dir": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"globby": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
|
||||
"integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.1.1",
|
||||
"ignore": "^5.1.4",
|
||||
"merge2": "^1.3.0",
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aggregate-error": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
|
||||
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-up": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"ssri": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz",
|
||||
"integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"tar": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz",
|
||||
"integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^3.0.0",
|
||||
"minizlib": "^2.1.0",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
|
||||
|
@ -3965,6 +4284,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
|
@ -4622,6 +4958,74 @@
|
|||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
|
||||
"integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.0",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.2",
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.0.5"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
|
@ -4634,6 +5038,15 @@
|
|||
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
|
||||
"dev": true
|
||||
},
|
||||
"fastq": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz",
|
||||
"integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"faye-websocket": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
|
||||
|
@ -4850,6 +5263,15 @@
|
|||
"readable-stream": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fs-write-stream-atomic": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
|
||||
|
@ -5077,6 +5499,11 @@
|
|||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||
"dev": true
|
||||
},
|
||||
"graphql-request": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-2.0.0.tgz",
|
||||
"integrity": "sha512-Ww3Ax+G3l2d+mPT8w7HC9LfrKjutnCKtnDq7ZZp2ghVk5IQDjwAk3/arRF1ix17Ky15rm0hrSKVKxRhIVlSuoQ=="
|
||||
},
|
||||
"handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
|
@ -5498,6 +5925,12 @@
|
|||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"import-local": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
|
||||
|
@ -6208,6 +6641,12 @@
|
|||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
|
||||
"dev": true
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
|
@ -6340,6 +6779,68 @@
|
|||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
|
||||
"integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"minipass-collect": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
|
||||
"integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-flush": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
|
||||
"integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-pipeline": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz",
|
||||
"integrity": "sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz",
|
||||
"integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mississippi": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||
|
@ -8015,6 +8516,12 @@
|
|||
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
|
||||
"dev": true
|
||||
},
|
||||
"reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true
|
||||
},
|
||||
"rework": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz",
|
||||
|
@ -8058,6 +8565,12 @@
|
|||
"inherits": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"run-parallel": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
|
||||
"integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"run-queue": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"@types/uuid": "^7.0.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^6.0.2",
|
||||
"css-loader": "^1.0.1",
|
||||
"extract-loader": "^3.1.0",
|
||||
"file-loader": "^2.0.0",
|
||||
|
@ -53,6 +54,7 @@
|
|||
"@types/qs": "^6.9.3",
|
||||
"bulma": "^0.7.2",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"graphql-request": "^2.0.0",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"qs": "^6.9.4",
|
||||
"react": "^16.12.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Page } from '../Page';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { RootState } from '../../store/reducers/root';
|
||||
|
||||
export function HomePage() {
|
||||
|
@ -14,8 +14,8 @@ export function HomePage() {
|
|||
<div className="column is-4 is-offset-4">
|
||||
<div className="box">
|
||||
{
|
||||
currentUser ?
|
||||
<p>Bonjour <span className="has-text-weight-bold">{currentUser.email}</span> !</p> :
|
||||
currentUser && currentUser.full_name ?
|
||||
<p>Bonjour <span className="has-text-weight-bold">{currentUser.full_name}</span> !</p> :
|
||||
<p>Veuillez vous authentifier.</p>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,8 @@ export const Config = {
|
|||
oauth2AuthorizeURL: get<string>("oauth2AuthorizeURL", "http://localhost:4444/oauth2/auth"),
|
||||
oauth2TokenURL: get<string>("oauth2TokenURL", "http://localhost:4444/oauth2/token"),
|
||||
oauth2LogoutURL: get<string>("oauth2LogoutURL", "http://localhost:4444/oauth2/sessions/logout"),
|
||||
oauth2PostLogoutRedirectURI: get<string>("oauth2PostLogoutRedirectURI", "http://localhost:8081")
|
||||
oauth2PostLogoutRedirectURI: get<string>("oauth2PostLogoutRedirectURI", "http://localhost:8081"),
|
||||
graphQLEndpoint: get<string>("graphQLEndpoint", "http://localhost:8080/api/v1/graphql")
|
||||
};
|
||||
|
||||
function get<T>(key: string, defaultValue: T):T {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// Use this file to customize client configuration.
|
||||
// See frontend/src/config.ts for more informations.
|
||||
window['__CONFIG__'] = {};
|
|
@ -0,0 +1,19 @@
|
|||
import { Action } from "redux";
|
||||
import { User } from "../../types/user";
|
||||
|
||||
export const FETCH_PROFILE_REQUEST = 'FETCH_PROFILE_REQUEST';
|
||||
export const FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS';
|
||||
export const FETCH_PROFILE_FAILURE = 'FETCH_PROFILE_FAILURE';
|
||||
|
||||
export interface fetchProfileRequestAction extends Action {
|
||||
|
||||
}
|
||||
|
||||
export interface fetchProfileSuccessAction extends Action {
|
||||
profile: User
|
||||
}
|
||||
|
||||
|
||||
export function fetchProfile(): fetchProfileRequestAction {
|
||||
return { type: FETCH_PROFILE_REQUEST }
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { Action } from "redux";
|
||||
import { User } from "../../types/user";
|
||||
import { SET_CURRENT_USER, setCurrentUserAction, LOGOUT } from "../actions/auth";
|
||||
import { FETCH_PROFILE_SUCCESS, fetchProfileSuccessAction } from "../actions/profile";
|
||||
|
||||
export interface AuthState {
|
||||
isAuthenticated: boolean
|
||||
|
@ -18,6 +19,9 @@ export function authReducer(state = defaultState, action: Action): AuthState {
|
|||
return handleSetCurrentUser(state, action as setCurrentUserAction);
|
||||
case LOGOUT:
|
||||
return handleLogout(state);
|
||||
case FETCH_PROFILE_SUCCESS:
|
||||
return handleFetchProfileSuccess(state, action as fetchProfileSuccessAction);
|
||||
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
@ -38,4 +42,14 @@ function handleLogout(state: AuthState): AuthState {
|
|||
isAuthenticated: false,
|
||||
currentUser: null,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function handleFetchProfileSuccess(state: AuthState, { profile }: fetchProfileSuccessAction): AuthState {
|
||||
return {
|
||||
...state,
|
||||
isAuthenticated: true,
|
||||
currentUser: {
|
||||
...profile,
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import { all, put } from "redux-saga/effects";
|
||||
import { getSavedAccessGrant } from "../../util/auth";
|
||||
import { parseIdToken } from "../actions/auth";
|
||||
|
||||
export function* initRootSaga() {
|
||||
yield all([
|
||||
retrieveSessionSaga(),
|
||||
]);
|
||||
}
|
||||
|
||||
export function* retrieveSessionSaga() {
|
||||
console.log("Checking session status...");
|
||||
|
||||
const accessGrant = getSavedAccessGrant();
|
||||
if (!accessGrant) return;
|
||||
|
||||
yield put(parseIdToken(accessGrant.id_token));
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
import { all } from 'redux-saga/effects';
|
||||
import { failureRootSaga } from './failure';
|
||||
import { authRootSaga } from './auth';
|
||||
import { initRootSaga } from './init';
|
||||
import { usersRootSaga } from './users';
|
||||
|
||||
export function* rootSaga() {
|
||||
yield all([
|
||||
initRootSaga(),
|
||||
failureRootSaga(),
|
||||
authRootSaga(),
|
||||
usersRootSaga(),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { DaddyClient } from "../../util/daddy";
|
||||
import { Config } from "../../config";
|
||||
import { getSavedAccessGrant } from "../../util/auth";
|
||||
import { all, takeLatest, put, select } from "redux-saga/effects";
|
||||
import { FETCH_PROFILE_REQUEST, fetchProfile, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS } from "../actions/profile";
|
||||
import { SET_CURRENT_USER } from "../actions/auth";
|
||||
import { RootState } from "../reducers/root";
|
||||
import { User } from "../../types/user";
|
||||
|
||||
export function* usersRootSaga() {
|
||||
yield all([
|
||||
takeLatest(SET_CURRENT_USER, onCurrentUserChangeSaga),
|
||||
takeLatest(FETCH_PROFILE_REQUEST, fetchProfileSaga),
|
||||
]);
|
||||
}
|
||||
|
||||
export function* onCurrentUserChangeSaga() {
|
||||
yield put(fetchProfile());
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function* fetchProfileSaga() {
|
||||
const grant = getSavedAccessGrant();
|
||||
const client = new DaddyClient(Config.graphQLEndpoint, grant.id_token);
|
||||
|
||||
let profile: User;
|
||||
try {
|
||||
const currentUser: User = yield select((state: RootState) => state.auth.currentUser);
|
||||
profile = yield client.fetchUser(currentUser.email).then(result => result.user);
|
||||
} catch(err) {
|
||||
yield put({ type: FETCH_PROFILE_FAILURE, err });
|
||||
return;
|
||||
}
|
||||
|
||||
yield put({type: FETCH_PROFILE_SUCCESS, profile });
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
export interface User {
|
||||
email: string
|
||||
full_name?: string
|
||||
updated_at?: Date
|
||||
created_at?: Date
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
import { GraphQLClient } from 'graphql-request'
|
||||
import { Config } from "../config";
|
||||
|
||||
export class UnauthorizedError extends Error {
|
||||
constructor(...args: any[]) {
|
||||
super(...args)
|
||||
|
@ -7,16 +10,35 @@ export class UnauthorizedError extends Error {
|
|||
|
||||
export class DaddyClient {
|
||||
|
||||
assertOk(res: any) {
|
||||
if (!res.ok) return Promise.reject(new Error('Request failed'));
|
||||
return res;
|
||||
gql: GraphQLClient
|
||||
|
||||
constructor(endpoint: string, idToken: string) {
|
||||
this.gql = new GraphQLClient(endpoint, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${idToken}`,
|
||||
mode: 'cors',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
assertAuthorization(res: any) {
|
||||
if (res.status === 401 || res.status === 404) return Promise.reject(new UnauthorizedError());
|
||||
return res;
|
||||
fetchUser(email: string) {
|
||||
return this.gql.rawRequest(`
|
||||
query fetchUser {
|
||||
user(where: {email: {eq: $email}}) {
|
||||
id
|
||||
created_at
|
||||
updated_at
|
||||
email,
|
||||
full_name
|
||||
}
|
||||
}
|
||||
`, { email })
|
||||
.then(this.assertAuthorization)
|
||||
}
|
||||
|
||||
assertAuthorization({ status, data }: any) {
|
||||
if (status === 401) return Promise.reject(new UnauthorizedError());
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const daddy = new DaddyClient();
|
|
@ -4,6 +4,7 @@ const path = require('path');
|
|||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const env = process.env;
|
||||
|
||||
|
@ -72,5 +73,10 @@ module.exports = {
|
|||
inject: false,
|
||||
favicon: "./src/resources/favicon.png",
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: './src/resources/config.sample.js', to: 'config.js' },
|
||||
],
|
||||
}),
|
||||
]
|
||||
}
|
|
@ -12,4 +12,5 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
|
|||
CREATE USER daddy WITH ENCRYPTED PASSWORD 'daddy';
|
||||
CREATE DATABASE daddy;
|
||||
GRANT ALL PRIVILEGES ON DATABASE daddy TO daddy;
|
||||
ALTER DATABASE daddy OWNER TO daddy;
|
||||
EOSQL
|
|
@ -5,12 +5,12 @@ ARG HTTPS_PROXY=
|
|||
ARG http_proxy=
|
||||
ARG https_proxy=
|
||||
|
||||
ARG SUPERGRAPH_VERSION=v0.14.17
|
||||
ARG SUPERGRAPH_VERSION=88ba105b70c60b2c7467dc1f76f041cec2614a04
|
||||
ARG WAITFORIT_VERSION=v2.4.1
|
||||
|
||||
RUN apk add --no-cache go make git curl bash ca-certificates
|
||||
|
||||
RUN git clone https://github.com/dosco/super-graph \
|
||||
RUN git clone https://forge.cadoles.com/wpetit/super-graph.git \
|
||||
&& export PATH="$PATH:/root/go/bin" \
|
||||
&& export CGO_ENABLED=0 \
|
||||
&& cd super-graph \
|
||||
|
|
Loading…
Reference in New Issue