diff --git a/.env_dist b/.env_dist index 246780d828c247bfb433096964e6172618996d6d..f79e0a2147032a51edc9bb453163f00d50bdcebd 100644 --- a/.env_dist +++ b/.env_dist @@ -1,6 +1,6 @@ # Modele du fichier '.env', definissant variables "d'environnement" utilisees dans divers fichiers de src/ et de db/. # (Ces variables sont chargees par le package dotenv dans `process.env`, dans les fichiers .js et .ts ou dotenv.config() est appele) -# Copier ce fichier en le renommant '.env', (le placer a la racine du repo,) et modifier les champs comme il faut. +#Copier et renommer .env TARGET_ENV=development PORT=3000 diff --git a/.eslintrc.json b/.eslintrc.json index eb8ccc675167e07c62c62873ac622b57eb1af79d..705be3165200e9112c02446561cad30da4422c99 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,8 @@ { "env": { "es6": true, - "node": true + "node": true, + "mocha": true }, "extends": "eslint:recommended", "parserOptions": { diff --git a/.gitignore b/.gitignore index 569d2145ad83c2e513bdc93362ead6639959f2b1..5e522f55230586043cddad095cc97aaa28902fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,6 @@ bower_components # node-waf configuration .lock-wscript -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - # Dependency directories node_modules/ jspm_packages/ @@ -69,6 +66,7 @@ typings/ # Generated files doc/ build/ +tsbuild/ # Config files ldap_credentials.json diff --git a/README.md b/README.md index 5ea57f73551ebbb14a3db649cf7a819be43c7924..93b08d0fe2f945b6270e5eb6778600d73cacb055 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Ce dépôt contient le _backend_ de Sigma, le successeur de Frankiz, un site ét Le but des lignes qui suivent est de permettre au lecteur de rapidement mettre en place et lancer un sigma local et se familiariser avec son administration. Comment obtenir la documentation détaillée du projet est expliqué à la fin de ce document. +Pour avoir un guide détaillé de l'installation de l'environnement de dev, voir [ce carnet]() + Pour obtenir une copie du projet, cloner le dépôt par : ```bash git clone git@gitlab.binets.fr:br/sigma-backend.git @@ -16,9 +18,7 @@ git clone git@gitlab.binets.fr:br/sigma-backend.git git clone https://gitlab.binets.fr/br/sigma-backend.git ``` -## Démarrer le serveur (en mode développement) - -### Installer les dépendances *npm* +## Installer les dépendances *npm* On utilise un serveur node.js avec [express.js](https://expressjs.com/). [^server] Utiliser Node.js permet d'utiliser facilement [*npm*](https://www.npmjs.com/) (Node Package Manager). Une "dépendance" est un package utilisé dans le projet. @@ -48,7 +48,77 @@ Et une dépendance supplémentaire, PostgreSQL (linux est supposé) : sudo apt install postgresql ``` -### Setup la BDD PostgreSQL +## Configuration +L'API est conçue pour êtes modulaire et pour fonctionner dans plusieurs environnements. + +On peut donc le configurer via des fichiers ou des variables d'environnement. En deux mots : + +* [`jsdoc_config.json`](../jsdoc_config.json), [`Dockerfile`](../Dockerfile), [`.dockerignore`](../.dockerignore), [`.gitignore`](../.gitignore), [`.eslintignore`](../.eslintignore), [`webpack.config.js`](../webpack.config.js) : transparents +* [`ldap_config.json`](../ldap_config.json) : noms champs du LDAP +* [`ldap_credentials.json`](../ldap_credentials.json) : paramètres de connexion secrets au LDAP +* [`.estlintrc.json`](../.eslintrc.json) : ESLINT ou à quel point cancériser le développeur +* [`.gitattributes`](../.gitattributes) : terminaison de fichiers +* [`.gitlab-ci.yml`](../.gitlab-ci.yml) : pipeline gitlab +* [`package.json`](../package.json) et [`package-lock.json`](../package-lock.json) : gestion des dépendances usuel +* [`tsconfig.json`](../tsconfig.json) : configure la compilation de fichiers Typescript en Javascript +* [`tslint.json`](../tslint.json) : configure tslint, utilisé plutôt que tsc dans le projet final +* [`.env`](../.env) : définit les variables d'environnement et ports utilisés... + +Certains de ces fichiers de configurations ont une version "distribution" en "_dist" qui permet de les partager (le reste du temps ils sont dans le .gitignore), quitte à les renommer et à les modifier en local. + +### Configuration LDAP +L'API de Sigma nécessite de se connecter au LDAP Frankiz, à la fois pour obtenir des données et pour l'authentification des utilisateurs. Cela est fait à l'aide de la librairie [ldapjs](http://ldapjs.org) pour faire les requêtes au LDAP et [passportJS](http://www.passportjs.org/) pour l'authentification. + +* La configuration LDAP de base se situe dans [ldap_config.json](../ldap_config.json). +* Les identifiants utilisés pour authentifier le serveur au LDAP sont dans [ldap_credentials.json](../ldap_credentials.json). Ils prennent la forme suivante: +```json +{ + "dn": "uid=<username>,ou=eleves,dc=frankiz,dc=net", + "passwd": "<password>" +} +``` +On peut s'inspirer de [ldap_credentials_dist.json](../ldap_credentials_dist.json). +* Elle est importée dans l'application depuis [src/ldap/internal/config.ts](../src/ldap/internal/config.ts). +* Si la variable d'environnement `LDAP_URI` est définie, l'adresse où trouver le LDAP est remplacée. + +Le LDAP de Frankiz est sous OpenLDAP, qui a l'avantage d'être largement utilisée, documentée sur Internet, compatible avec des lecteurs génériques comme [JXplorer](http://jxplorer.org/) et gérant ses propres logs (voir [ce blog](https://www.vincentliefooghe.net/content/openldap-gestion-des-logs)). + +**Exemple** + +Si on développe en dehors du plâtal et qu'on ouvre un proxy SSH avec _port forwarding_ du LDAP de Frankiz (<frankiz.polytechnique.fr:389>) vers <localhost:8389>, on s'y connecte en définissant : `LDAP_URI=ldap://localhost:8389`, soit en faisant `export LDAP_URI=...`, soit en écrivant un fichier `.env`. Le fichier `config.js` s'occupe du reste. + +### Variables d'environnement + +| **Variable** | **Description** | **Défaut** | +| ------ | ------ | ----- | +| NODE_ENV | Type de l'environnement pour node | `development` | +| TARGET_ENV | Type de l'environnement ciblé : `development`, `staging` ou `production` | [.env](../.env) | +| LDAP_URI | URI vers le serveur LDAP. | [ldap_config.json](../ldap_config.json) | +| HOST | Addresse sur laquelle le serveur écoute des requêtes. | [index.ts](../src/index.ts) | +| DB_HOST | Addresse de la base de données. | [.env](../.env) | +| DB_PASSWD | Mot de passe de la BDD | [.env](../.env) | + +Certaines variables doivent etre définies dans un fichier `.env`. On peut se contenter de recopier [.env_dist](../.env_dist) avec `cp .env_dist .env`. + +Par ailleurs, on peut définir ces variables d'environnement, **dans l'ordre décroissant de priorité :** + +* dans sa session de terminal (équivalent à `docker run -e KEY=value`) : + ```bash + export KEY=value + ``` +* au moment de lancer l'application : + ```bash + KEY=value npm start + ``` +* dans un fichier [`.env`](https://www.npmjs.com/package/dotenv) : + ```dotenv + KEY1=value1 + KEY2=value2 + ... + ``` + + +## Setup la BDD PostgreSQL La BDD PostgreSQL est utilisée pour stocker permissions, écoles des utilisateurs, annonces et événements. Créer un rôle PostgreSQL "sigma" : @@ -63,10 +133,13 @@ Créer une base de données PostgreSQL "sigma_dev" : createdb sigma_dev -U sigma -W ``` - Si vous n'arrivez pas à vous connecter (`createdb: could not connect to database template1: FATAL: Peer authentication failed for user`) : mettre à jour votre fichier `pg_hba.conf`. - - voir https://stackoverflow.com/questions/1471571/how-to-configure-postgresql-for-the-first-time -- Si vous souhaitez utiliser d'autres noms que "sigma" et "sigma_dev" : ça ne pose pas de problème, il vous faudra simplement modifier `../db/knexfile.js` et `../db/knex_init.js`. + - `sudo nano /etc/postgresql/<version>/main/pg_hba.conf` (en tant qu'utilisateur normal) + - remplacer tous les `peer` par `md5` + - redémarrer le serveur postgres : `sudo /etc/init.d/postgresql restart` +- Si vous souhaitez utiliser d'autres noms que "sigma" et "sigma_dev" : ça ne pose pas de problème, il vous faudra simplement modifier [.env](../.env). +- Sortir de l'utilisateur `postgres` avec CTRL + d -Exécuter les *migrations* et les *seeds* de knex : +Exécuter les *migrations* et les *seeds* de knex (dans le dossier `db`) : ```bash # construire le schéma de la BDD, i.e. définir les tables et leur structure. knex migrate:latest @@ -77,7 +150,7 @@ knex seed:run Voilà , vous avez une base de données à jour ! -### Démarrer le serveur +## Démarrer le serveur Dire à webpack de build le projet (build le bundle `../build/bundle.js`) : ```bash npm run dev # en mode developpement @@ -119,65 +192,19 @@ Les plus importants sont détaillées ci-dessous : - `npm run dev` : idem, mais en mode développement - `npm run watch` : idem, mais retranspile automatiquement dès que le code est modifié. - `npm run start` : lancer un serveur Node avec nodemon +- `npm run start_prod` : lancer le serveur avec Node - `npm run doc` : générer la doc JSDoc -- `npm run lint` : vérifier la syntaxe de tous les fichiers .js et .ts du dossier src/ +- `npm run lint` : discontinué +- `npm run eslint` : vérifier la syntaxe de tous les fichiers .js du dossier src/ +- `npm run tslint` : vérifier la syntaxe de tous les fichiers .ts du dossier src/ +- `npm run tsfix` : vérifie et corrige +- `npm run tsc` : compile le code TypeScript +- `npm run test` : démarre les tests unitaires `npm run start` démarre en fait le serveur buildé [`build/bundle.js`](../build/bundle.js) avec [nodemon](https://nodemon.io/), un outil de dév qui le redémarre automatiquement après toute modification *du bundle*. Donc, lancer `npm run watch` dans un terminal et `npm run start` dans un autre permet de rebuilder **et** relancer automatiquement le serveur, après toute modification *du code source*. -## Configuration -L'API est conçue pour êtes modulaire et pour fonctionner dans plusieurs environnements. - -On peut donc le configurer via des fichiers ou des variables d'environnement. - -### Configuration LDAP -L'API de Sigma nécessite de se connecter au LDAP Frankiz, à la fois pour obtenir des données et pour l'authentification des utilisateurs. Cela est fait à l'aide de la librairie [ldapjs](http://ldapjs.org) pour faire les requêtes au LDAP et [passportJS](http://www.passportjs.org/) pour l'authentification. - -* La configuration LDAP de base se situe dans [ldap_config.json](../ldap_config.json). -* Les identifiants utilisés que authentifier le serveur au LDAP sont dans [ldap_credentials.json](../ldap_credentials.json). Ils prennent la forme suivante: -```json -{ - "dn": "uid=<username>,ou=eleves,dc=frankiz,dc=net", - "passwd": "<password>" -} -``` -* Elle est importée dans l'application depuis [src/ldap/internal/config.ts](../src/ldap/internal/config.ts). -* Si la variable d'environnement `LDAP_URI` est définie, l'adresse où trouver le LDAP est remplacée. - -Le LDAP de Frankiz est sous OpenLDAP, qui a l'avantage d'être largement utilisée, documentée sur Internet, compatible avec des lecteurs génériques comme [JXplorer](http://jxplorer.org/) et gérant ses propres logs (voir [ce blog](https://www.vincentliefooghe.net/content/openldap-gestion-des-logs)). - -**Exemple** - -Si on développe en dehors du plâtal et qu'on ouvre un proxy SSH avec _port forwarding_ du LDAP de Frankiz (<frankiz.polytechnique.fr:389>) vers <localhost:8389>, on s'y connecte en définissant : `LDAP_URI=ldap://localhost:8389`, soit en faisant `export LDAP_URI=...`, soit en écrivant un fichier `.env`. Le fichier `config.js` s'occupe du reste. - -### Variables d'environnement - -| **Variable** | **Description** | **Défaut** (`ldap_config.json`) | -| ------ | ------ | ----- | -| LDAP_URI | URI vers le serveur LDAP. | <ldap://frankiz.eleves.polytechnique.fr:389> | -| TARGET_ENV | Type de l'environnement ciblé : `development`, `staging` ou `production` | `development` | -| HOST | Addresse sur laquelle le serveur écoute des requêtes. | `localhost` en développement, `0.0.0.0` en staging/prod. | -| DB_HOST | Addresse de la base de données. | `localhost` ou `129.104.201.10` en staging/prod. | -| DB_PASSWD | Mot de passe de la BDD | `password` | - -On peut définir ces variables d'environnement, **dans l'ordre décroissant de priorité :** - -* dans sa session de terminal (équivalent à `docker run -e KEY=value`) : - ```bash - export KEY=value - ``` -* au moment de lancer l'application : - ```bash - KEY=value npm start - ``` -* dans un fichier [`.env`](https://www.npmjs.com/package/dotenv) : - ```dotenv - KEY1=value1 - KEY2=value2 - ... - ``` - ## Panneau d'administration Il est accessible par navigateur au path [/adminview/admin](localhost:3000/adminview/admin) ; n'importe quel path devrait rediriger dessus. diff --git a/assets/LDAPGroup.png b/assets/LDAPGroup.png new file mode 100644 index 0000000000000000000000000000000000000000..539fb1b637a38e70f129af814dba580734e52fc7 Binary files /dev/null and b/assets/LDAPGroup.png differ diff --git a/assets/LDAPUseCase.PNG b/assets/LDAPUseCase.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6aae00183835ea38cf8255669f30f7450fd0ef5b Binary files /dev/null and b/assets/LDAPUseCase.PNG differ diff --git a/assets/LDAPUser.png b/assets/LDAPUser.png new file mode 100644 index 0000000000000000000000000000000000000000..69296169c96a45c9edd7c76be9d625fb341e14e6 Binary files /dev/null and b/assets/LDAPUser.png differ diff --git a/assets/LDAP_API.png b/assets/LDAP_API.png new file mode 100644 index 0000000000000000000000000000000000000000..af9bd2dccb790afa275c2d0d36f544c75974d940 Binary files /dev/null and b/assets/LDAP_API.png differ diff --git a/ldap_config.json b/ldap_config.json index 0539f061aca1d0c35435c72eb7293360f6fc65e9..ba56ad7d85030d2c3f9098bdd84dd5e40f25b067 100644 --- a/ldap_config.json +++ b/ldap_config.json @@ -8,51 +8,51 @@ "server_dev": "ldap://ldap.eleves.polytechnique.fr:389", "comment_2": "Noms de domaines dans LDAP ; le niv d'après est en uid=, voir Wikipedia", - "dn_groups":"ou=groups,dc=frankiz,dc=net", - "dn_users": "ou=eleves,dc=frankiz,dc=net", - "key_id": "uid", + "dn":{ + "group":"ou=groups,dc=frankiz,dc=net", + "user": "ou=eleves,dc=frankiz,dc=net" + }, "comment_3": "Placeholders et indications de contenu de certains champs du LDAP généré par frankiz pour les utilisateurs", "user": { "uid": "uid", - "photo": "jpegPhoto", + "password": "userPassword", "givenName": "givenName", "lastName": "sn", - "fullName": "cn", - "cleanFullName": "gecos", - "nickname": "displayName", - "birthdate": "brBirthdate", - "nationality": "country", - "promotion": "brPromo", + "nickname": "pseudonym", + "gender": "gender", + "photo": "urlPhoto", "phone": "telephoneNumber", - "adress": "brRoom", - "id": "uidNumber", - "password": "userPassword", - "idNum": "gidNumber", - "directory": "homeDirectory", + "adress": "roomNumber", + "mail": "email", + "birthdate": "birthdate", + "nationality": "nationality", "login": "loginShell", - "readPerm": "brNewsReadAccess", - "writePerm": "brNewsPostAccess", - "mail": "mail", - "ips": "brIP", - "forlifes": "brAlias", - "groups": "brMemberOf", - "classes": "objectClass" + "directory": "homeDirectory", + "classes": "objectClass", + "id": "uidNumber", + "cleanFullName": "gecos", + "admins": "adminOf", + "speakers": "speakerOf", + "members": "memberOf", + "followers": "followerOf" }, - "comment_4": "Placeholders et indications de contenu de certains champs du LDAP généré par frankiz pour les groupes", + "comment_4": "Placeholders et indications de contenu de certains champs du LDAP généré par frankiz pour les groupes (childs TBA)", "group": { - "gid": "uid", - "name": "brAlias", - "type": "brNS", - "members": "restrictedMemberUid", - "admins": "memberUid", + "gid": "cn", + "name": "sn", + "site": "website", + "description": "description", + "category": "groupCategory", + "admins": "admin", + "speakers": "speaker", + "members": "member", + "followers": "follower", "adress":"cn", - "idNumber": "uidNumber", - "idNumber2": "gidNumber", - "login": "loginShell", + "idNumber": "gidNumber", "password": "userPassword", - "directory": "homeDirectory", - "cleanFullName": "gecos", - "classes": "objectClass" + "logo": "urlPhoto", + "classes": "objectClass", + "parents": "parent" } } \ No newline at end of file diff --git a/ldap_credentials_dist.json b/ldap_credentials_dist.json index 7702f747c3cc08179cb62b7f8b204910749bcde4..46253a9513b3bbbdf5bee96aea662eb9bba46c7e 100644 --- a/ldap_credentials_dist.json +++ b/ldap_credentials_dist.json @@ -1,5 +1,5 @@ { - "README": "Modele du fichier 'ldap_credentials.json', requis par src/ldap/. Copier ce fichier en le renommant 'ldap_credentials.json', (le placer a la racine du repo,) et modifier les champs comme il faut.", + "README": "Modele du fichier 'ldap_credentials.json', requis par src/ldap/. Copier ce fichier en le renommant 'ldap_credentials.json' (le placer a la racine du repo). A copier et renommer en local.", "dn": "uid=sigma,ou=services,dc=frankiz,dc=net", "passwd": "&vH}x%7;FK3j53eX" diff --git a/notes/CONTRIBUTING.md b/notes/CONTRIBUTING.md index c61002fed3ae236348023c56a0a65f9e51acada4..a75a55eba3e3bb6b8f83414805e114ab988ababd 100644 --- a/notes/CONTRIBUTING.md +++ b/notes/CONTRIBUTING.md @@ -15,9 +15,10 @@ Ainsi, l'idée est de conserver le LDAP Frankiz mais pas sa BDD, inutilisable ca ### L'idée Il s'agit de reprendre un nouveau Frankiz plus moderne et clairement documenté, mais pas seulement. Plusieurs fonctionnalités intéressantes sont envisageables : -- gestion des inscriptions (notamment avec nombre de places limité), -- inscription par trigramme, -- minimodules ou des greffons à étudier +- fil d'actualité avec filtre personnalisable +- gestion des inscriptions (notamment avec nombre de places limité) +- inscription par trigramme +- minimodules ou greffons à étudier - intégration des événements d'autres écoles ## Description et actualité des branches @@ -61,13 +62,9 @@ Certaines anciennes branches, fraîchement mergées, sont décrites ci-dessous. - branche sur laquelle akka vodol fait tout son travail : implémentation des resolvers pour le nouveau schéma propre (le schéma "_wish_list"). Comme ça, il peut faire d'éventuelles modifications du schéma sans faire chier les autres, et ensuite on valide ensemble pour merge. -#### LDAP-refacto - -Branche obsolète à supprimer. - #### unit-tests -- TODO (@akka vodol tu peux expliquer ici a quoi sert cette branche ? et le cas échéant, la merge dans master ?) +- branche de test-unitaires ## Structure du dossier @@ -259,4 +256,4 @@ Le BR dispose de plusieurs Virtual Machines (VM) pour faire tourner les outils e Le BR 2016, plus particulièrement Wilson Jallet, Guillaume Wang, Quentin Chevalier et Anatole Romon -Le BR 2017, plus particulièrement Olivér Facklam, Grégoire Grzeckowicz et Hadrien Renaud +Le BR 2017, plus particulièrement Olivér Facklam, Grégoire Grzeckowicz et Hadrien Renaud \ No newline at end of file diff --git a/notes/hist.json b/notes/hist.json new file mode 100644 index 0000000000000000000000000000000000000000..57723b6c4ed07d8642134189816ad96249cb9540 --- /dev/null +++ b/notes/hist.json @@ -0,0 +1,8 @@ +{ + "title": "Historiques", + "children": [ + "hist_graphql", + "hist_ldap", + "hist_rights" + ] +} \ No newline at end of file diff --git a/notes/hist.md b/notes/hist.md new file mode 100644 index 0000000000000000000000000000000000000000..84ddc0088c8613dda92fcdb0776e8546cc6f5956 --- /dev/null +++ b/notes/hist.md @@ -0,0 +1,4 @@ +Historiques +=== + +Le projet sigma a un passif. C'est le travail accumulé de plusieurs promotions qui ont été obligé de faire un certain nombre de choix techniques ou purement esthétiques. Avant de pourrir leur travail conscrit, lis ces quelques lignes. \ No newline at end of file diff --git a/notes/hist_graphql.json b/notes/hist_graphql.json new file mode 100644 index 0000000000000000000000000000000000000000..17834f602fbd2873a6c2c8b66454aaacee9cbb5d --- /dev/null +++ b/notes/hist_graphql.json @@ -0,0 +1,4 @@ +{ + "title": "Historique GraphQL, ou comment gérer les relations de couple entre front et back-end", + "children": [] +} \ No newline at end of file diff --git a/notes/memo_sigma_graphql.md b/notes/hist_graphql.md similarity index 97% rename from notes/memo_sigma_graphql.md rename to notes/hist_graphql.md index d3366e0b9fd04b49a4f2128f7b8a861708140d78..f23b5ba184fe1ab4b4f54a1a85f211df05deac9b 100644 --- a/notes/memo_sigma_graphql.md +++ b/notes/hist_graphql.md @@ -1,11 +1,8 @@ -Implémentation du schéma et des resolvers GraphQL sur sigma-backend -=== - Remarques sur *l'implémentation*, explication de choix de design... Pour des commentaires sur la définition du schéma, se reporter plutôt aux commentaires en en-tête des fichiers `actions.graphql` et `objects.graphql`. -Pour des explications plus high-level sur la gestion des droits et les authorizations sur Sigma, voir le memo idoine (`memo_sigma_rights.md`). +Pour des explications plus high-level sur la gestion des droits et les authorizations sur Sigma, voir le memo idoine {@tutorial hist_rights}. ## Structure du dossier `src/graphql` diff --git a/notes/hist_ldap.json b/notes/hist_ldap.json new file mode 100644 index 0000000000000000000000000000000000000000..cbe5b98108928441e56bb2810c66c0813a4c1a2a --- /dev/null +++ b/notes/hist_ldap.json @@ -0,0 +1,4 @@ +{ + "title": "Historique de l'API LDAP", + "children": [] +} \ No newline at end of file diff --git a/notes/hist_ldap.md b/notes/hist_ldap.md new file mode 100644 index 0000000000000000000000000000000000000000..52c0f8bbbc8bbb8c937216b428f08e3ecf1e4ce6 --- /dev/null +++ b/notes/hist_ldap.md @@ -0,0 +1,39 @@ +## Sur le LDAP Frankiz + +A l'origine Frankiz, le prédécesseur de sigma, avait sa propre base de données qu'il importait toutes les 3h dans un LDAP énorme et sale, qui contenait le strict minimum. Ce LDAP s'est révélé très utile à différents sites binets qui ont fait un usage très libre de cette ressource. + +De sorte que quand il fallut remplacer Frankiz, la destruction du LDAP n'était pas possible sans revoir plusieurs sites binets (à voir, le CAS était peut-être une solution suffisante). On a donc choisi de tuer la BDD Frankiz, mais seulement après avoir considérablement enrichi le LDAP pour en faire la BDD utilisateurs et groupes principale de sigma. + +Une documentation vieillissante est disponible sur le [`wikix`](https://wikibr.binets.fr/Admin:LDAP) par rapport au LDAP de Frankiz. + +Le BR2017 a mené un gros travail de réorganisation du LDAP donc beaucoup d'informations sur le wikix ne seront plus valides. + +### Nouvelle organisation du LDAP + +Le LDAP a été significativement enrichi depuis Frankiz, puisqu'il contient la majeure partie des données utilisateurs et groupes de sigma. Les champs parent et child permettent aux resolvers afférents de faire descendre les admins et remonter les membres, mais n'a pas d'influence à l'intérieur de l'API LDAP. + + + + + + + +#### Configuration + +L'équivalence pratique entre champs du LDAP et champs du code est dans le fichier de configuration [`ldap_config`](../ldap_config.json). Idéalement, ce .json serait ensuite porté en une calsse dynamique dans le code. En atendant une structure pareille, on se contentera des structures de données décrites dans [`config`](../src/ldap/internal/config.ts). + +#### Une structure particulière + +Les admins et membres sont de deux types ; les admins et membres stricts, acceptés par un administrateur dans le groupe, et les admins et membres hérités, qui ont rejoint ce groupe en remontant ou en descendant la structure de parenté ; voir {@tutorial hist_rights}. + +### Etat de l'API + +Cette API est voulue comme la plus simple et la plus minimaliste possible ; en effet, elle sera à réimplémenter sur toutes les instances différentes de sigma pour s'adapter aux structures de données des différentes écoles qui choisissent d'adopter sigma. On peut administrer des groupes depuis sigma, mais pour s'interfacer d'instances à instances seules deux fonctions sont indispensables ; peek et search. + +Cette API, bien que relativement naïve, doit être capable de garder la syn,chronisation entre les deux arbres du LDAP et ainsi que les problèmes de récursion posées par le choix de la structure en admin descendant et membres montant. + + + +Le détail de chaque fonction est disponible dans la documentation JSDOC : ([`User`](../doc/LDAP.User.html) et [`Group`](../doc/LDAP.Group.html)). + +La lutte contre les injections est faite au plus bas niveau possible en utilisant [`ldapEscape`](https://www.npmjs.com/package/ldap-escape) directement dans la classe [`Basics`](../doc/LDAP.Basics.html). En effet, les injections LDAP sont relativement voyantes et ne peuvent pas se faire avec des caractères usuels. \ No newline at end of file diff --git a/notes/hist_rights.json b/notes/hist_rights.json new file mode 100644 index 0000000000000000000000000000000000000000..0dd11135e2bb0f6720478e71058fbd07da9996b9 --- /dev/null +++ b/notes/hist_rights.json @@ -0,0 +1,4 @@ +{ + "title": "Bilan des droits sur sigma", + "children": [] +} \ No newline at end of file diff --git a/notes/memo_sigma_rights.md b/notes/hist_rights.md similarity index 98% rename from notes/memo_sigma_rights.md rename to notes/hist_rights.md index 84574f12b02330ad37a30e0aba0262302ccf710d..cab6b0fde8f85f30a991025645658d6862190b3a 100644 --- a/notes/memo_sigma_rights.md +++ b/notes/hist_rights.md @@ -1,6 +1,3 @@ -Gestion des droits sur Sigma -=== - ## Overview Chaque utilisateur a un certain niveau de droit sur chaque groupe. Ce niveau de droit indique ce qu'il a le droit de savoir et de faire. @@ -48,7 +45,7 @@ Détaillons ici les conditions exactes pour avoir un niveau de droit donné. #### Pour les méta-groupes - Un user est membre d'un méta-groupe G s'il est membre (hérité) d'un groupe simple dans G. -- Un user est speaker d'un méta-groupe G s'il est admin strict d'un groupe simple dans G. +- Un user est speaker d'un méta-groupe G s'il est speaker d'un groupe simple dans G. - Un user est admin d'un méta-groupe G s'il est admin (hérité) d'un groupe simple dans G. - Un user est viewer d'un méta-groupe G s'il est viewer d'un groupe simple dans G. diff --git a/notes/memo_jsdoc.json b/notes/memo_jsdoc.json index fc059053cd902176e1fa0a1e40aa52282e034375..0aefcd8dc1bcd6a07381c95944b4ac886d6b95fa 100644 --- a/notes/memo_jsdoc.json +++ b/notes/memo_jsdoc.json @@ -1,4 +1,4 @@ { - "title": "Memo JSDoc", + "title": "Memo JSDoc, le meilleur ami du newbie", "children": [] } \ No newline at end of file diff --git a/notes/memo_jsdoc.md b/notes/memo_jsdoc.md index 547eadb3011566674f921674e1e9946a0033aab0..e9ac628c289d2a2faa567fb9a017025a3e5e7ae8 100644 --- a/notes/memo_jsdoc.md +++ b/notes/memo_jsdoc.md @@ -1,4 +1,4 @@ -JSDoc, c'est l'outil de génération automatique de documentation. Il transforme des commentaires et des fichiers Markdown comme celui-ci en une masse de pages web lisibles même par un autiste semi-aveugle à quiil manquerait un module de sémantique. +JSDoc, c'est l'outil de génération automatique de documentation. Il transforme des commentaires et des fichiers Markdown comme celui-ci en une masse de pages web lisibles même par un autiste semi-aveugle à qui il manquerait un module de sémantique. La doc de JSDoc, paradoxalement un peu aride : [`Use JSDoc`](http://usejsdoc.org/) @@ -41,4 +41,6 @@ La factorisation de code dans des classes étant en soit une bonne pratique et p ### Les fichiers. md -JSDoc a deux façons simples d'intégrer des fichiers Mardown dans la doc ; un README en page d'accueil, ou un tutoriel comme celui-ci. Tous les tutoriels doivent être mis dans le même dossier avec des fichiers de config .json pour définir une arborescence de tutoriels propres. \ No newline at end of file +JSDoc a deux façons simples d'intégrer des fichiers Mardown dans la doc ; un README en page d'accueil, ou un tutoriel comme celui-ci. Tous les tutoriels doivent être mis dans le même dossier avec des fichiers de config .json pour définir une arborescence de tutoriels propres. + +N'hésitez pas à enrichir la documentation à votre tour, par des fichiers .md ou directement dans votre code ! \ No newline at end of file diff --git a/notes/memo_knexjs.json b/notes/memo_knexjs.json index 887d74bb75b48c0b7860316a35d9489ce39a1f51..e375581b497e4a0f1d9e1d528fc69d714ead8991 100644 --- a/notes/memo_knexjs.json +++ b/notes/memo_knexjs.json @@ -1,4 +1,4 @@ { - "title": "Memo knew.js", + "title": "Memo knew.js ou quand on a la felmme de faire du SQL", "children": [] } \ No newline at end of file diff --git a/notes/memo_knexjs.md b/notes/memo_knexjs.md index d15ec00acf6ad5658382b9eb1c9f3c8a700d0d26..cff213567e7bfb11d394a331402f9c69a68eb8b4 100644 --- a/notes/memo_knexjs.md +++ b/notes/memo_knexjs.md @@ -72,4 +72,4 @@ Solution : spécifier dans le schéma (fichiers migrations) ce qu'il faut faire On a défini les migrations (`./db/migrations/*`) en se basant sur le schéma GraphQL (`typeDefs.js`) (et pas l'inverse), ce qui se voit bien puisqu'on suit presque exactement ce dernier. **[spécifique à shitpost :]** -Un point particulier cependant : comme expliqué en commentaires du migration-file `./db/migrations/[timestamp]_create_comments.js`, on n'a pas déclaré le champ "forMessage" de la table "comments" comme ayant "messages.id" comme foreign key, car ce n'est pas possible avec PostgreSQL v10. +Un point particulier cependant : comme expliqué en commentaires du migration-file `./db/migrations/[timestamp]_create_comments.js`, on n'a pas déclaré le champ "forMessage" de la table "comments" comme ayant "messages.id" comme foreign key, car ce n'est pas possible avec PostgreSQL v10. \ No newline at end of file diff --git a/notes/memo_ldap.json b/notes/memo_ldap.json index e36839dfd17d86106cfb15eee97e1c1eb52c7e9e..a0627ac10cb6d0878bbc835eaaccbc1780875725 100644 --- a/notes/memo_ldap.json +++ b/notes/memo_ldap.json @@ -1,4 +1,4 @@ { - "title": "Memo LDAP", + "title": "Memo LDAP, ni BDD ni annuaire", "children": [] } \ No newline at end of file diff --git a/notes/memo_ldap.md b/notes/memo_ldap.md index a91b3ae7eec309fa9c3d4d31e621435f3df7d0ba..8d5179bebed5c8fe3af2965b948f90e4ae93d31b 100644 --- a/notes/memo_ldap.md +++ b/notes/memo_ldap.md @@ -2,12 +2,20 @@ LDAP signifie Lightweight Directory Access Protocol ; c'est donc un protocole, comme http, et pas une structure de données à proprement parler. Comme http, il fonctionne par chaîne de caractères appelés URI. La structure d'un LDAP est cependant forcément celle d'un arbre, avec une racine à la fin de l'URI et le noeud recherché à la fin. Par exemple "uid=louis.vaneau,ou=eleves,dc=frankiz,dc=net", qui permet d'accéder à la feuille associée à Louis Vaneau dans le LDAP de frankiz. -Il s'agit d'une structure particulièrement rigide mais efficace en lecture. Chaque noeud contient un certain nombre de champs qui ne sont pas nécessairement tous rempli, et qui n'ont pas forcément une seule variable par champ. +Il s'agit d'une structure particulièrement rigide mais efficace en lecture. Chaque noeud contient un certain nombre de champs qui ne sont pas nécessairement tous remplis, et qui n'ont pas forcément une seule variable par champ. Un LDAP est une structure parfaitement adapté à la réalisation d'un annuaire car pensé pour cela dès l'origine ; très efficace en lecture, il brille moins en écriture. -## Sur le LDAP Frankiz +La technologie est ancienne et bien connue. Le LDAP de Frankiz, OpenLDAP, contient beaucoup de fonctionnalités sympathique comme le hashage inclus des mots de passe avec salt conformément à l'état de l'art. -Une documentation vieillissante est disponible sur le [`wikix`](https://wikibr.binets.fr/Admin:LDAP). +### Un wrapper sympathique... -## Un wrapper sympathique +On accède sur un LDAP par des requêtes LDAP, d'où l'intérêt d'une bibliothèque comme [`ldap.js`](http://ldapjs.org/) qui fait office de traducteur javascript/LDAP, un peu comme knex et SQL. On s'intéressera particulièrement à la partie [`client`](http://ldapjs.org/client.html) qui est celle qui permet d'agir sur le LDAP. -On accède sur un LDAP¨par des requêtes LDAP, d'où l'intérêt d'une bibliothèque comme [`ldap.js`](http://ldapjs.org/) qui fait office de traducteur javascript/LDAP, un peu comme knex et SQL. On s'intéressera particulièrement à la partie [`client`](http://ldapjs.org/client.html) qui est celle qui permet d'agir sur le LDAP. \ No newline at end of file +Cette bibliothèque est reprise et re-wrappée dans la classe [`Basics`](../src/ldap/internal/basics.ts). + +### Pas complètement dépourvu de dangers ! + +Comme tous les protocoles, LDAP a ses failles. En particulier, il est possible d'injecter des commandes via un nom de domaine (Domain Name ou DN) ou un filtre (filter). Ces dangers sont adressés par sigma en utilisant la bibliothèque [`ldap-escape`](https://www.npmjs.com/package/ldap-escape). + +### Une interface graphique agréable + +Pour explorer un LDAP, vous pouvez utiliser [`JXplorer`](http://jxplorer.org/). Il s'agit d'un logiciel OpenSource en Java très imparfait mais qui permet de rapidement parcourir les champs d'un LDAP et de mener des petites recherches dessus. \ No newline at end of file diff --git a/notes/memo_postgresql.json b/notes/memo_postgresql.json index 5854303fa10a833546c5fe97ea09c1a1805ddb0b..7634a09c2fdd835ffeabd0d6677adeb6b3ae653b 100644 --- a/notes/memo_postgresql.json +++ b/notes/memo_postgresql.json @@ -1,4 +1,4 @@ { - "title": "Memo PostgreSQL", + "title": "Memo PostgreSQL, ou une technologie de base de données simple", "children": [] } \ No newline at end of file diff --git a/notes/memo_sigma_graphql.json b/notes/memo_sigma_graphql.json deleted file mode 100644 index 59928242a82930bb9527f256ae9bfdbfca2b7a49..0000000000000000000000000000000000000000 --- a/notes/memo_sigma_graphql.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Implémentation du schéma", - "children": [] -} \ No newline at end of file diff --git a/notes/memo_sigma_rights.json b/notes/memo_sigma_rights.json deleted file mode 100644 index 1791d5b687e9f3b8d536000a77faa829be87e866..0000000000000000000000000000000000000000 --- a/notes/memo_sigma_rights.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Gestion des droits sur Sigma", - "children": [] -} \ No newline at end of file diff --git a/notes/memos.md b/notes/memos.md index 1f51b82463da51955169047ac4880058f5f2f2c7..8aab15325d1aeb03e41543b18dab7ee04a6ea0a3 100644 --- a/notes/memos.md +++ b/notes/memos.md @@ -1,4 +1,4 @@ Mémos === -Le projet sigma était assez large et comportant pas mal de facettes avec des technologies pas forcément toujours intuitives ou bien documentées, les mémos de cetten section sont là pour permettre au dev perdu de s'y retrouver rapidement face à une technologie qu'il ne maîtrise pas à fond. \ No newline at end of file +Le projet sigma était assez large et comportant pas mal de facettes avec des technologies pas forcément toujours intuitives ou bien documentées, les mémos de cette section sont là pour permettre au dev perdu de s'y retrouver rapidement face à une technologie qu'il ne maîtrise pas à fond. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e0370a5ff34ec1ffdffa5ba478d6bf914b2d5f42..6b8e5a5d2aa7dbe5c7d9ec91763175794810ed11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@apollographql/apollo-tools": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.3.0.tgz", - "integrity": "sha512-Tg0NVtCFHMQkcSX/dqT0m+BNnK9/lbjo4YFNX9W5g3EwczlC0edrleUM/dC4wXw71DwGrGwFiZxWLxqY1ocU5A==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.3.3.tgz", + "integrity": "sha512-/vLzZjloWB4xzgw2MRs9TUDIdCzS+No1hEClkEKqcnH86c2EgE/W0Dv2nkCTH9WxDrfryziJWbNMurYYkm61Zw==", "requires": { - "apollo-env": "0.3.0" + "apollo-env": "0.3.3" } }, "@apollographql/graphql-playground-html": { @@ -36,31 +36,31 @@ } }, "@babel/code-frame": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", - "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "7.0.0-beta.44" + "@babel/highlight": "^7.0.0" } }, "@babel/core": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.2.2.tgz", - "integrity": "sha512-59vB0RWt09cAct5EIe58+NzGP4TFSD3Bz//2/ELy3ZeTeKF6VTD1AXlH8BGGbCX0PuobZBsIzO7IAI9PH67eKw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", + "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.2.2", + "@babel/parser": "^7.3.4", "@babel/template": "^7.2.2", - "@babel/traverse": "^7.2.2", - "@babel/types": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", "convert-source-map": "^1.1.0", "debug": "^4.1.0", "json5": "^2.1.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" @@ -76,14 +76,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -140,30 +140,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -206,14 +206,14 @@ } }, "@babel/generator": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz", - "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.44", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.2.0", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -228,13 +228,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -251,13 +251,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -284,14 +284,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -348,30 +348,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -399,16 +399,17 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz", - "integrity": "sha512-DUsQNS2CGLZZ7I3W3fvh0YpPDd6BuWJlDl+qmZZpABZHza2ErE3LxtEzLJFHFC1ZwtlAXvHhbFYbtM5o5B0WBw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.4.tgz", + "integrity": "sha512-uFpzw6L2omjibjxa8VGZsJUPL5wJH0zzGKpoz0ccBkzIa6C8kWNUbiBmQ0rgOKWlHJ6qzmfa6lTiGchiV8SC+g==", "dev": true, "requires": { "@babel/helper-function-name": "^7.1.0", "@babel/helper-member-expression-to-functions": "^7.0.0", "@babel/helper-optimise-call-expression": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.2.3" + "@babel/helper-replace-supers": "^7.3.4", + "@babel/helper-split-export-declaration": "^7.0.0" }, "dependencies": { "@babel/code-frame": { @@ -440,6 +441,15 @@ "@babel/types": "^7.0.0" } }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -463,13 +473,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -544,13 +554,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -582,14 +592,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -646,30 +656,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -697,23 +707,23 @@ } }, "@babel/helper-function-name": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz", - "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0-beta.44", - "@babel/template": "7.0.0-beta.44", - "@babel/types": "7.0.0-beta.44" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz", - "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.44" + "@babel/types": "^7.0.0" } }, "@babel/helper-hoist-variables": { @@ -726,13 +736,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -748,13 +758,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -770,13 +780,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -837,13 +847,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -865,13 +875,13 @@ }, "dependencies": { "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } @@ -915,14 +925,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -979,30 +989,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1030,15 +1040,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz", - "integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", + "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.0.0", "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.2.3", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4" }, "dependencies": { "@babel/code-frame": { @@ -1051,14 +1061,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -1115,30 +1125,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1207,13 +1217,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1226,12 +1236,12 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz", - "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { - "@babel/types": "7.0.0-beta.44" + "@babel/types": "^7.0.0" } }, "@babel/helper-wrap-function": { @@ -1256,14 +1266,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -1320,30 +1330,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1391,14 +1401,14 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.4", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" } @@ -1455,30 +1465,30 @@ } }, "@babel/traverse": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz", - "integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.2", + "@babel/generator": "^7.3.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.2.3", - "@babel/types": "^7.2.2", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1506,20 +1516,28 @@ } }, "@babel/highlight": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", - "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } } }, "@babel/parser": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.1.tgz", - "integrity": "sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { @@ -1534,12 +1552,12 @@ } }, "@babel/plugin-proposal-class-properties": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz", - "integrity": "sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.4.tgz", + "integrity": "sha512-lUf8D3HLs4yYlAo8zjuneLvfxN7qfKv1Yzbj5vjqaqMJxgJA3Ipwp4VUJ+OrOdz53Wbww6ahwB8UhB2HQyLotA==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.3.0", + "@babel/helper-create-class-features-plugin": "^7.3.4", "@babel/helper-plugin-utils": "^7.0.0" } }, @@ -1554,9 +1572,9 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz", - "integrity": "sha512-Nmmv1+3LqxJu/V5jU9vJmxR/KIRWFk2qLHmbB56yRRRFhlaSuOVXscX3gUmhaKgUhzA3otOHVubbIEVYsZ0eZg==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", + "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1621,9 +1639,9 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0.tgz", - "integrity": "sha512-5fxmdqiAQVQTIS+KSvYeZuTt91wKtBTYi6JlIkvbQ6hmO+9fZE81ezxmMiFMIsxE7CdRSgzn7nQ1BChcvK9OpA==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", + "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" @@ -1639,9 +1657,9 @@ } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz", - "integrity": "sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz", + "integrity": "sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -1659,19 +1677,19 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz", - "integrity": "sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", + "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "@babel/plugin-transform-classes": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz", - "integrity": "sha512-gEZvgTy1VtcDOaQty1l10T3jQmJKlNVxLDCs+3rCVPr6nMkODLELxViq5X9l+rfxbie3XrfrMCYYY6eX3aOcOQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", + "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.0.0", @@ -1679,7 +1697,7 @@ "@babel/helper-function-name": "^7.1.0", "@babel/helper-optimise-call-expression": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-replace-supers": "^7.3.4", "@babel/helper-split-export-declaration": "^7.0.0", "globals": "^11.1.0" }, @@ -1745,13 +1763,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1773,9 +1791,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz", - "integrity": "sha512-coVO2Ayv7g0qdDbrNiadE4bU7lvCd9H539m2gMknyVjjMdwF/iCOM7R+E8PkntoqLkltO0rk+3axhpp/0v68VQ==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz", + "integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" @@ -1882,13 +1900,13 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -1931,9 +1949,9 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz", - "integrity": "sha512-aYJwpAhoK9a+1+O625WIjvMY11wkB/ok0WClVwmeo3mCjcNRjt+/8gHWrB5i+00mUju0gWsBkQnPpdvQ7PImmQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz", + "integrity": "sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.0.0", @@ -1979,9 +1997,9 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.2.0.tgz", - "integrity": "sha512-kB9+hhUidIgUoBQ0MsxMewhzr8i60nMa2KgeJKQWYrqQpqcBYtnpR+JgkadZVZoaEZ/eKu9mclFaVwhRpLNSzA==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz", + "integrity": "sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw==", "dev": true, "requires": { "@babel/helper-call-delegate": "^7.1.0", @@ -1999,25 +2017,25 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } } } }, "@babel/plugin-transform-regenerator": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz", - "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz", + "integrity": "sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==", "dev": true, "requires": { - "regenerator-transform": "^0.13.3" + "regenerator-transform": "^0.13.4" } }, "@babel/plugin-transform-shorthand-properties": { @@ -2068,13 +2086,13 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.1.0.tgz", - "integrity": "sha512-TOTtVeT+fekAesiCHnPz+PSkYSdOSLyLn42DI45nxg6iCdlQY6LIj/tYqpMB0y+YicoTUiYiXqF8rG6SKfhw6Q==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.3.2.tgz", + "integrity": "sha512-Pvco0x0ZSCnexJnshMfaibQ5hnK8aUHSvjCQhC1JR8eeg+iBwt0AtCO7gWxJ358zZevuf9wPSO5rv+WJcbHPXQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-typescript": "^7.0.0" + "@babel/plugin-syntax-typescript": "^7.2.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -2110,16 +2128,16 @@ } }, "@babel/preset-env": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.1.tgz", - "integrity": "sha512-FHKrD6Dxf30e8xgHQO0zJZpUPfVZg+Xwgz5/RdSWCbza9QLNk4Qbp40ctRoqDxml3O8RMzB1DU55SXeDG6PqHQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", + "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-async-generator-functions": "^7.2.0", "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.1", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", "@babel/plugin-syntax-async-generators": "^7.2.0", @@ -2127,10 +2145,10 @@ "@babel/plugin-syntax-object-rest-spread": "^7.2.0", "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.3.4", "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.2.0", - "@babel/plugin-transform-classes": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.3.4", + "@babel/plugin-transform-classes": "^7.3.4", "@babel/plugin-transform-computed-properties": "^7.2.0", "@babel/plugin-transform-destructuring": "^7.2.0", "@babel/plugin-transform-dotall-regex": "^7.2.0", @@ -2141,13 +2159,13 @@ "@babel/plugin-transform-literals": "^7.2.0", "@babel/plugin-transform-modules-amd": "^7.2.0", "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "@babel/plugin-transform-modules-systemjs": "^7.2.0", + "@babel/plugin-transform-modules-systemjs": "^7.3.4", "@babel/plugin-transform-modules-umd": "^7.2.0", "@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0", "@babel/plugin-transform-new-target": "^7.0.0", "@babel/plugin-transform-object-super": "^7.2.0", "@babel/plugin-transform-parameters": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-regenerator": "^7.3.4", "@babel/plugin-transform-shorthand-properties": "^7.2.0", "@babel/plugin-transform-spread": "^7.2.0", "@babel/plugin-transform-sticky-regex": "^7.2.0", @@ -2161,13 +2179,13 @@ } }, "@babel/preset-typescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.1.0.tgz", - "integrity": "sha512-LYveByuF9AOM8WrsNne5+N79k1YxjNB6gmpCQsnuSBAcV8QUeB+ZUxQzL7Rz7HksPbahymKkq2qBR+o36ggFZA==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz", + "integrity": "sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.1.0" + "@babel/plugin-transform-typescript": "^7.3.2" } }, "@babel/runtime": { @@ -2186,43 +2204,58 @@ } }, "@babel/template": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", - "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.44", - "@babel/types": "7.0.0-beta.44", - "babylon": "7.0.0-beta.44", - "lodash": "^4.2.0" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" } }, "@babel/traverse": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz", - "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.44", - "@babel/generator": "7.0.0-beta.44", - "@babel/helper-function-name": "7.0.0-beta.44", - "@babel/helper-split-export-declaration": "7.0.0-beta.44", - "@babel/types": "7.0.0-beta.44", - "babylon": "7.0.0-beta.44", - "debug": "^3.1.0", + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", "globals": "^11.1.0", - "invariant": "^2.2.0", - "lodash": "^4.2.0" + "lodash": "^4.17.11" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } } }, "@babel/types": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz", - "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==", + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.2.0", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" } }, @@ -2377,9 +2410,9 @@ } }, "@types/bluebird": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.25.tgz", - "integrity": "sha512-yfhIBix+AIFTmYGtkC0Bi+XGjSkOINykqKvO/Wqdz/DuXlAKK7HmhLAXdPIGsV4xzKcL3ev/zYc4yLNo+OvGaw==", + "version": "3.5.26", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.26.tgz", + "integrity": "sha512-aj2mrBLn5ky0GmAg6IPXrQjnN0iB/ulozuJ+oZdrHRAzRbXjGmu4UXsNCjFvPbSaaPZmniocdOzsM392qLOlmQ==", "dev": true }, "@types/body-parser": { @@ -2391,6 +2424,12 @@ "@types/node": "*" } }, + "@types/chai": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "dev": true + }, "@types/connect": { "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", @@ -2450,9 +2489,9 @@ } }, "@types/graphql": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.0.5.tgz", - "integrity": "sha512-bwGYLE0SRy5ZraC91dqI2bxbspfm10kyJ2Yjuvk4OjdGznh7fkoWW+xXZHfFydJaqu9syZi099cpiZw3GlPDiA==", + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.0.7.tgz", + "integrity": "sha512-BoLDjdvLQsXPZLJux3lEZANwGr3Xag56Ngy0U3y8uoRSDdeLcn43H3oBcgZlnd++iOQElBpaRVDHPzEDekyvXQ==", "dev": true }, "@types/jss": { @@ -2465,9 +2504,9 @@ } }, "@types/knex": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@types/knex/-/knex-0.15.1.tgz", - "integrity": "sha512-eMXYxl8Jhg5tBYLtSGTF4acCGHeKO+0HYDocAM5jpYBsKC8w0HwQPF8eqi8TAzex5I4JkVK27p/phvY0wg09aQ==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@types/knex/-/knex-0.15.2.tgz", + "integrity": "sha512-mw8OT8v+FK0SsgDdmio2XSkEM/yLD7ybFtiqW7I65EDTlr2aZtG+p9FhryErpNJDJ2FEXgQhe3JVBG0Gh7YbvQ==", "dev": true, "requires": { "@types/bluebird": "*", @@ -2493,16 +2532,21 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==" }, + "@types/mocha": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", + "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "dev": true + }, "@types/node": { - "version": "10.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" + "version": "11.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.5.tgz", + "integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==" }, "@types/passport": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.0.tgz", "integrity": "sha512-R2FXqM+AgsMIym0PuKj08Ybx+GR6d2rU3b1/8OcHolJ+4ga2pRPX105wboV6hq1AJvMo2frQzYKdqXS5+4cyMw==", - "dev": true, "requires": { "@types/express": "*" } @@ -2548,175 +2592,179 @@ } }, "@webassemblyjs/ast": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", - "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.3.tgz", + "integrity": "sha512-xy3m06+Iu4D32+6soz6zLnwznigXJRuFNTovBX2M4GqVqLb0dnyWLbPnpcXvUSdEN+9DVyDeaq2jyH1eIL2LZQ==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11" + "@webassemblyjs/helper-module-context": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wast-parser": "1.8.3" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz", - "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.3.tgz", + "integrity": "sha512-vq1TISG4sts4f0lDwMUM0f3kpe0on+G3YyV5P0IySHFeaLKRYZ++n2fCFfG4TcCMYkqFeTUYFxm75L3ddlk2xA==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz", - "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.3.tgz", + "integrity": "sha512-BmWEynI4FnZbjk8CaYZXwcv9a6gIiu+rllRRouQUo73hglanXD3AGFJE7Q4JZCoVE0p5/jeX6kf5eKa3D4JxwQ==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz", - "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.3.tgz", + "integrity": "sha512-iVIMhWnNHoFB94+/2l7LpswfCsXeMRnWfExKtqsZ/E2NxZyUx9nTeKK/MEMKTQNEpyfznIUX06OchBHQ+VKi/Q==", "dev": true }, "@webassemblyjs/helper-code-frame": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz", - "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.3.tgz", + "integrity": "sha512-K1UxoJML7GKr1QXR+BG7eXqQkvu+eEeTjlSl5wUFQ6W6vaOc5OwSxTcb3oE9x/3+w4NHhrIKD4JXXCZmLdL2cg==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.7.11" + "@webassemblyjs/wast-printer": "1.8.3" } }, "@webassemblyjs/helper-fsm": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz", - "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.3.tgz", + "integrity": "sha512-387zipfrGyO77/qm7/SDUiZBjQ5KGk4qkrVIyuoubmRNIiqn3g+6ijY8BhnlGqsCCQX5bYKOnttJobT5xoyviA==", "dev": true }, "@webassemblyjs/helper-module-context": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz", - "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==", - "dev": true + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.3.tgz", + "integrity": "sha512-lPLFdQfaRssfnGEJit5Sk785kbBPPPK4ZS6rR5W/8hlUO/5v3F+rN8XuUcMj/Ny9iZiyKhhuinWGTUuYL4VKeQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "mamacro": "^0.0.3" + } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz", - "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.3.tgz", + "integrity": "sha512-R1nJW7bjyJLjsJQR5t3K/9LJ0QWuZezl8fGa49DZq4IVaejgvkbNlKEQxLYTC579zgT4IIIVHb5JA59uBPHXyw==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz", - "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.3.tgz", + "integrity": "sha512-P6F7D61SJY73Yz+fs49Q3+OzlYAZP86OfSpaSY448KzUy65NdfzDmo2NPVte+Rw4562MxEAacvq/mnDuvRWOcg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3" } }, "@webassemblyjs/ieee754": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz", - "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.3.tgz", + "integrity": "sha512-UD4HuLU99hjIvWz1pD68b52qsepWQlYCxDYVFJQfHh3BHyeAyAlBJ+QzLR1nnS5J6hAzjki3I3AoJeobNNSZlg==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz", - "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.3.tgz", + "integrity": "sha512-XXd3s1BmkC1gpGABuCRLqCGOD6D2L+Ma2BpwpjrQEHeQATKWAQtxAyU9Z14/z8Ryx6IG+L4/NDkIGHrccEhRUg==", "dev": true, "requires": { - "@xtuc/long": "4.2.1" + "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz", - "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.3.tgz", + "integrity": "sha512-Wv/WH9Zo5h5ZMyfCNpUrjFsLZ3X1amdfEuwdb7MLdG3cPAjRS6yc6ElULlpjLiiBTuzvmLhr3ENsuGyJ3wyCgg==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz", - "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.3.tgz", + "integrity": "sha512-nB19eUx3Yhi1Vvv3yev5r+bqQixZprMtaoCs1brg9Efyl8Hto3tGaUoZ0Yb4Umn/gQCyoEGFfUxPLp1/8+Jvnw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/helper-wasm-section": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-opt": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", - "@webassemblyjs/wast-printer": "1.7.11" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/helper-wasm-section": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3", + "@webassemblyjs/wasm-opt": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3", + "@webassemblyjs/wast-printer": "1.8.3" } }, "@webassemblyjs/wasm-gen": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz", - "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.3.tgz", + "integrity": "sha512-sDNmu2nLBJZ/huSzlJvd9IK8B1EjCsOl7VeMV9VJPmxKYgTJ47lbkSP+KAXMgZWGcArxmcrznqm7FrAPQ7vVGg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/ieee754": "1.8.3", + "@webassemblyjs/leb128": "1.8.3", + "@webassemblyjs/utf8": "1.8.3" } }, "@webassemblyjs/wasm-opt": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz", - "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.3.tgz", + "integrity": "sha512-j8lmQVFR+FR4/645VNgV4R/Jz8i50eaPAj93GZyd3EIJondVshE/D9pivpSDIXyaZt+IkCodlzOoZUE4LnQbeA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3" } }, "@webassemblyjs/wasm-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz", - "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.3.tgz", + "integrity": "sha512-NBI3SNNtRoy4T/KBsRZCAWUzE9lI94RH2nneLwa1KKIrt/2zzcTavWg6oY05ArCbb/PZDk3OUi63CD1RYtN65w==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-api-error": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/ieee754": "1.8.3", + "@webassemblyjs/leb128": "1.8.3", + "@webassemblyjs/utf8": "1.8.3" } }, "@webassemblyjs/wast-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz", - "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.3.tgz", + "integrity": "sha512-gZPst4CNcmGtKC1eYQmgCx6gwQvxk4h/nPjfPBbRoD+Raw3Hs+BS3yhrfgyRKtlYP+BJ8LcY9iFODEQofl2qbg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/floating-point-hex-parser": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-code-frame": "1.7.11", - "@webassemblyjs/helper-fsm": "1.7.11", - "@xtuc/long": "4.2.1" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/floating-point-hex-parser": "1.8.3", + "@webassemblyjs/helper-api-error": "1.8.3", + "@webassemblyjs/helper-code-frame": "1.8.3", + "@webassemblyjs/helper-fsm": "1.8.3", + "@xtuc/long": "4.2.2" } }, "@webassemblyjs/wast-printer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz", - "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.3.tgz", + "integrity": "sha512-DTA6kpXuHK4PHu16yAD9QVuT1WZQRT7079oIFFmFSjqjLWGXS909I/7kiLTn931mcj7wGsaUNungjwNQ2lGQ3Q==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11", - "@xtuc/long": "4.2.1" + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/wast-parser": "1.8.3", + "@xtuc/long": "4.2.2" } }, "@xtuc/ieee754": { @@ -2726,9 +2774,9 @@ "dev": true }, "@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, "abbrev": { @@ -2747,9 +2795,9 @@ } }, "acorn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", - "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "dev": true }, "acorn-dynamic-import": { @@ -2792,8 +2840,7 @@ "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" }, "ajv-keywords": { "version": "3.1.0", @@ -2829,6 +2876,11 @@ "string-width": "^2.0.0" } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" + }, "ansi-escape-sequences": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.0.0.tgz", @@ -2869,12 +2921,22 @@ } }, "apollo-cache-control": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.4.1.tgz", - "integrity": "sha512-1wGSlIkL1V4S8qmwnWL96F9kq3m4WTeFVUtZ/L2M5BsKkl74YqLa8+UzORJyGE3rfyRbAGa3qg7p21f/DgeezA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.5.2.tgz", + "integrity": "sha512-uehXDUrd3Qim+nzxqqN7XT1YTbNSyumW3/FY5BxbKZTI8d4oPG4eyVQKqaggooSjswKQnOoIQVes3+qg9tGAkw==", "requires": { "apollo-server-env": "2.2.0", - "graphql-extensions": "0.4.2" + "graphql-extensions": "0.5.4" + }, + "dependencies": { + "graphql-extensions": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.5.4.tgz", + "integrity": "sha512-qLThJGVMqcItE7GDf/xX/E40m/aeqFheEKiR5bfra4q5eHxQKGjnIc20P9CVqjOn9I0FkEiU9ypOobfmIf7t6g==", + "requires": { + "@apollographql/apollo-tools": "^0.3.3" + } + } } }, "apollo-codegen": { @@ -3039,47 +3101,48 @@ } }, "apollo-datasource": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.2.2.tgz", - "integrity": "sha512-CB9XnZTQHhP9W7IWZH/bR/7/aelMrRdDJ8uoAz59buXbFlb5ExZa/54FGZg7g6q+JQGeFaquMAR1QZb2kfuC9w==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.3.1.tgz", + "integrity": "sha512-qdEUeonc9pPZvYwXK36h2NZoT7Pddmy0HYOzdV0ON5pcG1YtNmUyyYi83Q60V5wTWjuaCjyJ9hOY6wr0BMvQuA==", "requires": { - "apollo-server-caching": "0.2.2", + "apollo-server-caching": "0.3.1", "apollo-server-env": "2.2.0" } }, "apollo-engine-reporting": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-0.2.1.tgz", - "integrity": "sha512-2HHHMHjSHb4LKf+DRs4NCuDVAVBIg4rU6AtT18Yy+BcxDli0GsUL2OsvHM8E5lha511qXI2rO2dRA+dYOFFwHA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.0.7.tgz", + "integrity": "sha512-mFsXvd+1/o5jSa9tI2RoXYGcvCLcwwcfLwchjSTxqUd4ViB8RbqYKynzEZ+Omji7PBRM0azioBm43f7PSsQPqA==", "requires": { - "apollo-engine-reporting-protobuf": "0.2.0", + "apollo-engine-reporting-protobuf": "0.2.1", + "apollo-graphql": "^0.1.0", + "apollo-server-core": "2.4.8", "apollo-server-env": "2.2.0", "async-retry": "^1.2.1", - "graphql-extensions": "0.4.2", - "lodash": "^4.17.10" + "graphql-extensions": "0.5.7" } }, "apollo-engine-reporting-protobuf": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.2.0.tgz", - "integrity": "sha512-qI+GJKN78UMJ9Aq/ORdiM2qymZ5yswem+/VDdVFocq+/e1QqxjnpKjQWISkswci5+WtpJl9SpHBNxG98uHDKkA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.2.1.tgz", + "integrity": "sha512-5pYR84uWeylRS2OJowtkTczT3bWTwOErWtfnkRKccUi/wZ/AZJBP+D5HKNzM7xoFcz9XvrJyS+wBTz1oBi0Jiw==", "requires": { "protobufjs": "^6.8.6" } }, "apollo-env": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.3.0.tgz", - "integrity": "sha512-L3oDC+q+fpnGaV2ZrcyClrezUbzzwnxDDoTeTaxUfahrfyyV2vyLI7yzEbi0TP5U4Jbb7uqrJKVeaMFe4vVjJA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.3.3.tgz", + "integrity": "sha512-VsUX14bfQCJpKmTyYNBTeLrdeFabjmpSPVQ2y4IKnwqaxVqZuRca3WFE8ercszO1tLwS6HMM7mFw+IIbtQXo/w==", "requires": { - "core-js": "^3.0.0-beta.3", + "core-js": "3.0.0-beta.13", "node-fetch": "^2.2.0" }, "dependencies": { "core-js": { - "version": "3.0.0-beta.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.0-beta.11.tgz", - "integrity": "sha512-Q1gGAIqiFfR8ZqjrJw4gzjDrP2JsLacNQzUKUfqvcpg974bCQrPaT4a+HNbznQm5DabCIKw9fGQotj0dgdsMRg==" + "version": "3.0.0-beta.13", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.0-beta.13.tgz", + "integrity": "sha512-16Q43c/3LT9NyePUJKL8nRIQgYWjcBhjJSMWg96PVSxoS0PeE0NHitPI3opBrs9MGGHjte1KoEVr9W63YKlTXQ==" }, "node-fetch": { "version": "2.3.0", @@ -3088,6 +3151,14 @@ } } }, + "apollo-graphql": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.1.1.tgz", + "integrity": "sha512-UImgDIeB0n0fryYqtdz0CwJ9uDtXwg/3Q6rXzRAqgqBYz46VkmWa7nu2LX9GmDtiXB5VUOVCtyMEnvFwC3o27g==", + "requires": { + "lodash.sortby": "^4.7.0" + } + }, "apollo-link": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.6.tgz", @@ -3098,9 +3169,9 @@ } }, "apollo-server-caching": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.2.2.tgz", - "integrity": "sha512-EYNSR1Vubd14REonCRTJaO/Gr4lkjUTt/45Wp+f1DQtfsAZpHxAtCWafX5fesvq8krdHhSHyEUOTjj2JO8Qi9w==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.3.1.tgz", + "integrity": "sha512-mfxzikYXbB/OoEms77AGYwRh7FF3Oim5v5XWAL+VL49FrkbZt5lopVa4bABi7Mz8Nt3Htl9EBJN8765s/yh8IA==", "requires": { "lru-cache": "^5.0.0" }, @@ -3121,61 +3192,30 @@ } }, "apollo-server-core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.3.2.tgz", - "integrity": "sha512-8sPltNZSKYJJWAsTpu5NiTzsPZEbAOo2ftpepkHP6LxgZ3nkR+6muKUpuPkEQhn7KhVFVqzGkdxJivz/wkdZaw==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.4.8.tgz", + "integrity": "sha512-N+5UOzHhMOnHizEiArJtNvEe/cGhSHQyTn5tlU4RJ36FDBJ/WlYZfPbGDMLISSUCJ6t+aP8GLL4Mnudt9d2PDQ==", "requires": { - "@apollographql/apollo-tools": "^0.3.0", + "@apollographql/apollo-tools": "^0.3.3", "@apollographql/graphql-playground-html": "^1.6.6", "@types/ws": "^6.0.0", - "apollo-cache-control": "0.4.1", - "apollo-datasource": "0.2.2", - "apollo-engine-reporting": "0.2.1", - "apollo-server-caching": "0.2.2", + "apollo-cache-control": "0.5.2", + "apollo-datasource": "0.3.1", + "apollo-engine-reporting": "1.0.7", + "apollo-server-caching": "0.3.1", "apollo-server-env": "2.2.0", - "apollo-server-errors": "2.2.0", - "apollo-server-plugin-base": "0.2.2", - "apollo-tracing": "0.4.1", + "apollo-server-errors": "2.2.1", + "apollo-server-plugin-base": "0.3.7", + "apollo-tracing": "0.5.2", "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "0.4.2", + "graphql-extensions": "0.5.7", "graphql-subscriptions": "^1.0.0", "graphql-tag": "^2.9.2", "graphql-tools": "^4.0.0", "graphql-upload": "^8.0.2", - "lodash": "^4.17.10", + "sha.js": "^2.4.11", "subscriptions-transport-ws": "^0.9.11", "ws": "^6.0.0" - }, - "dependencies": { - "apollo-link": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.6.tgz", - "integrity": "sha512-sUNlA20nqIF3gG3F8eyMD+mO80fmf3dPZX+GUOs3MI9oZR8ug09H3F0UsWJMcpEg6h55Yy5wZ+BMmAjrbenF/Q==", - "requires": { - "apollo-utilities": "^1.0.0", - "zen-observable-ts": "^0.8.13" - } - }, - "graphql-tools": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.4.tgz", - "integrity": "sha512-chF12etTIGVVGy3fCTJ1ivJX2KB7OSG4c6UOJQuqOHCmBQwTyNgCDuejZKvpYxNZiEx7bwIjrodDgDe9RIkjlw==", - "requires": { - "apollo-link": "^1.2.3", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - } - }, - "zen-observable-ts": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.13.tgz", - "integrity": "sha512-WDb8SM0tHCb6c0l1k60qXWlm1ok3zN9U4VkLdnBKQwIYwUoB9psH7LIFgR+JVCCMmBxUgOjskIid8/N02k/2Bg==", - "requires": { - "zen-observable": "^0.8.0" - } - } } }, "apollo-server-env": { @@ -3188,14 +3228,14 @@ } }, "apollo-server-errors": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.2.0.tgz", - "integrity": "sha512-gV9EZG2tovFtT1cLuCTavnJu2DaKxnXPRNGSTo+SDI6IAk6cdzyW0Gje5N2+3LybI0Wq5KAbW6VLei31S4MWmg==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.2.1.tgz", + "integrity": "sha512-wY/YE3iJVMYC+WYIf8QODBjIP4jhI+oc7kiYo9mrz7LdYPKAgxr/he+NteGcqn/0Ea9K5/ZFTGJDbEstSMeP8g==" }, "apollo-server-express": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.3.2.tgz", - "integrity": "sha512-gEAQEtRpeA1POzlXpS/eohISpfYeVeGYpgFH8RaqmJ9CZyu2Nnxx+iE5u42wlUa7LOPS8KqJIfzJ0z8GViA+zg==", + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.4.8.tgz", + "integrity": "sha512-i60l32mfVe33jnKDPNYgUKUKu4Al0xEm2HLOSMgtJ9Wbpe/MbOx5X8M5F27fnHYdM+G5XfAErsakAyRGnQJ48Q==", "requires": { "@apollographql/graphql-playground-html": "^1.6.6", "@types/accepts": "^1.3.5", @@ -3203,7 +3243,7 @@ "@types/cors": "^2.8.4", "@types/express": "4.16.1", "accepts": "^1.3.5", - "apollo-server-core": "2.3.2", + "apollo-server-core": "2.4.8", "body-parser": "^1.18.3", "cors": "^2.8.4", "graphql-subscriptions": "^1.0.0", @@ -3229,50 +3269,40 @@ "@types/express-serve-static-core": "*", "@types/serve-static": "*" } - }, - "apollo-link": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.6.tgz", - "integrity": "sha512-sUNlA20nqIF3gG3F8eyMD+mO80fmf3dPZX+GUOs3MI9oZR8ug09H3F0UsWJMcpEg6h55Yy5wZ+BMmAjrbenF/Q==", - "requires": { - "apollo-utilities": "^1.0.0", - "zen-observable-ts": "^0.8.13" - } - }, - "graphql-tools": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.4.tgz", - "integrity": "sha512-chF12etTIGVVGy3fCTJ1ivJX2KB7OSG4c6UOJQuqOHCmBQwTyNgCDuejZKvpYxNZiEx7bwIjrodDgDe9RIkjlw==", - "requires": { - "apollo-link": "^1.2.3", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - } - }, - "zen-observable-ts": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.13.tgz", - "integrity": "sha512-WDb8SM0tHCb6c0l1k60qXWlm1ok3zN9U4VkLdnBKQwIYwUoB9psH7LIFgR+JVCCMmBxUgOjskIid8/N02k/2Bg==", - "requires": { - "zen-observable": "^0.8.0" - } } } }, "apollo-server-plugin-base": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.2.2.tgz", - "integrity": "sha512-BmvF5WhRFm9BPvdTsK7TfvG/tQb6cSE1MAqhEuPx5VJNrSXzsJzxWVB3T28/SJQwewfMoYPf9Tui5lZs+do5Qw==" + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.3.7.tgz", + "integrity": "sha512-hW1jaLKf9qNOxMTwRq2CSqz3eqXsZuEiCc8/mmEtOciiVBq1GMtxFf19oIYM9HQuPvQU2RWpns1VrYN59L3vbg==" + }, + "apollo-server-testing": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/apollo-server-testing/-/apollo-server-testing-2.4.8.tgz", + "integrity": "sha512-AmNn5pDn9FJ9AJbmc7gwsUFaUt4uf44IFHaCfZow/jkAeY2JZnIozt8LYC8Koidy+Lfb+i/HsjkgbBodElbGMQ==", + "dev": true, + "requires": { + "apollo-server-core": "2.4.8" + } }, "apollo-tracing": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.4.1.tgz", - "integrity": "sha512-XQZjhW5gs0EvZityJJuqskeUdJMiuDCt9e5+NqKWlvNaxVhNBUChUpAT4Lkh1RHai2rfFjrW1oCNMZMfC86Sqw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.5.2.tgz", + "integrity": "sha512-2FdwRvPIq9uuF6OzONroXep6VBGqzHOkP6LlcFQe7SdwxfRP+SD/ycHNSC1acVg2b8d+am9Kzqg2vV54UpOIKA==", "requires": { "apollo-server-env": "2.2.0", - "graphql-extensions": "0.4.2" + "graphql-extensions": "0.5.4" + }, + "dependencies": { + "graphql-extensions": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.5.4.tgz", + "integrity": "sha512-qLThJGVMqcItE7GDf/xX/E40m/aeqFheEKiR5bfra4q5eHxQKGjnIc20P9CVqjOn9I0FkEiU9ypOobfmIf7t6g==", + "requires": { + "@apollographql/apollo-tools": "^0.3.3" + } + } } }, "apollo-utilities": { @@ -3288,6 +3318,12 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, + "arg": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", + "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -3364,11 +3400,6 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -3520,15 +3551,15 @@ } }, "babel-eslint": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz", - "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", + "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0-beta.44", - "@babel/traverse": "7.0.0-beta.44", - "@babel/types": "7.0.0-beta.44", - "babylon": "7.0.0-beta.44", + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", "eslint-scope": "3.7.1", "eslint-visitor-keys": "^1.0.0" } @@ -3560,12 +3591,6 @@ } } }, - "babylon": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", - "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", - "dev": true - }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -3674,7 +3699,8 @@ "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true }, "bn.js": { "version": "4.11.8", @@ -3897,14 +3923,14 @@ } }, "browserslist": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz", - "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz", + "integrity": "sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000929", - "electron-to-chromium": "^1.3.103", - "node-releases": "^1.1.3" + "caniuse-lite": "^1.0.30000939", + "electron-to-chromium": "^1.3.113", + "node-releases": "^1.1.8" } }, "buffer": { @@ -3977,23 +4003,62 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cacache": { - "version": "10.0.4", - "resolved": "http://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" + }, + "dependencies": { + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + }, + "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==", + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } } }, "cache-base": { @@ -4046,9 +4111,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30000932", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz", - "integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==", + "version": "1.0.30000939", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz", + "integrity": "sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg==", "dev": true }, "capture-stack-trace": { @@ -4201,12 +4266,6 @@ "safe-buffer": "^5.0.1" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -4256,17 +4315,6 @@ "restore-cursor": "^2.0.0" } }, - "cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "dev": true, - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - } - }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -4300,11 +4348,6 @@ } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -4561,9 +4604,9 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, "cookie-parser": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", - "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", + "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", "requires": { "cookie": "0.3.1", "cookie-signature": "1.0.6" @@ -4593,18 +4636,40 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "copy-webpack-plugin": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", - "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.0.tgz", + "integrity": "sha512-iiDj+8nnZeW/i8vYJ3+ABSZkOefJnDYIGLojiZKKFDvf1wcEInABXH1+hN7axQMn04qvJxKjgVOee0e14XPtCg==", "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", + "cacache": "^11.3.1", + "find-cache-dir": "^2.0.0", "globby": "^7.1.1", "is-glob": "^4.0.0", "loader-utils": "^1.1.0", "minimatch": "^3.0.4", - "p-limit": "^1.0.0", - "serialize-javascript": "^1.4.0" + "normalize-path": "^3.0.0", + "p-limit": "^2.1.0", + "serialize-javascript": "^1.4.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" + } } }, "core-js": { @@ -4919,11 +4984,10 @@ } }, "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "requires": { - "arrify": "^1.0.1", "path-type": "^3.0.0" } }, @@ -4948,9 +5012,9 @@ } }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -5022,9 +5086,9 @@ } }, "ecdsa-sig-formatter": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", - "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "requires": { "safe-buffer": "^5.0.1" } @@ -5035,9 +5099,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.108", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.108.tgz", - "integrity": "sha512-/QI4hMpAh48a1Sea6PALGv+kuVne9A2EWGd8HrWHMdYhIzGtbhVVHh6heL5fAzGaDnZuPyrlWJRl8WPm4RyiQQ==", + "version": "1.3.113", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", + "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==", "dev": true }, "elliptic": { @@ -5055,6 +5119,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -5159,47 +5229,46 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.1.tgz", - "integrity": "sha512-54NV+JkTpTu0d8+UYSA8mMKAG4XAsaOrozA9rCW7tgneg1mevcL7wIotPC+fZ0SkWwdhNqoXoxnQCTBp7UvTsg==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz", + "integrity": "sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", + "ajv": "^6.9.1", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", - "doctrine": "^2.1.0", + "doctrine": "^3.0.0", "eslint-scope": "^4.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.0", + "espree": "^5.0.1", "esquery": "^1.0.1", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", + "inquirer": "^6.2.2", "js-yaml": "^3.12.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", - "table": "^5.0.2", + "table": "^5.2.3", "text-table": "^0.2.0" }, "dependencies": { @@ -5224,9 +5293,9 @@ } }, "ajv": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", - "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", + "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -5274,9 +5343,9 @@ "dev": true }, "globals": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.10.0.tgz", - "integrity": "sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, "ignore": { @@ -5292,9 +5361,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", + "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -5343,9 +5412,9 @@ } }, "eslint-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz", - "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.2.tgz", + "integrity": "sha512-rA9XiXEOilLYPOIInvVH5S/hYfyTPyxag6DZhoQOduM+3TkghAEQ3VcFO8VnX4J4qg/UIBzp72aOf/xvYmpmsg==", "dev": true, "requires": { "loader-fs-cache": "^1.0.0", @@ -5387,9 +5456,9 @@ } }, "eslint-plugin-import": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.15.0.tgz", - "integrity": "sha512-LEHqgR+RcnpGqYW7h9WMkPb/tP+ekKxWdQDztfTtZeV43IHF+X8lXU+1HOCcR4oXD24qRgEwNSxIweD5uNKGVg==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", + "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", "dev": true, "requires": { "contains-path": "^0.1.0", @@ -5521,12 +5590,12 @@ "dev": true }, "espree": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz", - "integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, "requires": { - "acorn": "^6.0.2", + "acorn": "^6.0.7", "acorn-jsx": "^5.0.0", "eslint-visitor-keys": "^1.0.0" } @@ -5899,8 +5968,7 @@ "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", - "dev": true + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, "figures": { "version": "2.0.0", @@ -5912,22 +5980,21 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" } }, "file-loader": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", - "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", "requires": { "loader-utils": "^1.0.2", - "schema-utils": "^0.4.5" + "schema-utils": "^1.0.0" } }, "file-set": { @@ -6002,13 +6069,61 @@ } }, "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", + "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", "requires": { "commondir": "^1.0.1", "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + } } }, "find-replace": { @@ -6025,6 +6140,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, "requires": { "locate-path": "^2.0.0" } @@ -6067,18 +6183,65 @@ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + } + } + }, "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "flush-write-stream": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", @@ -6089,11 +6252,11 @@ } }, "fmtr": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fmtr/-/fmtr-1.1.0.tgz", - "integrity": "sha1-R1RcTNo3rWkbDSDiaHbQdexz/mg=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fmtr/-/fmtr-1.1.1.tgz", + "integrity": "sha512-nb0b2t9fKK7/Xxh3cv5MNnqaLbT6N67anBsPy0eOwTErTXtz12diKDzDoeqXTN8Ie8/qg2xJEXNBW3Nb2Dd0lQ==", "requires": { - "lodash": "^4.17.4" + "lodash": "^4.17.11" } }, "for-in": { @@ -6142,9 +6305,9 @@ "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" }, "fs-capacitor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.0.tgz", - "integrity": "sha512-CIJZpxbVWhO+qyODeCR55Q+6vj0p2oL8DAWd/DZi3Ev+25PimUoScw07K0fPgluaH3lFoqNvwW13BDYfHWFQJw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.1.tgz", + "integrity": "sha512-kyV2oaG1/pu9NPosfGACmBym6okgzyg6hEtA5LSUq0dGpGLe278MVfMwVnSHDA/OBcTCHkPNqWL9eIwbPN6dDg==" }, "fs-readdir-recursive": { "version": "1.1.0", @@ -6215,14 +6378,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6242,8 +6403,7 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", @@ -6391,7 +6551,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6399,8 +6558,7 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", @@ -6504,8 +6662,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6721,9 +6878,9 @@ "dev": true }, "fuse.js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.3.0.tgz", - "integrity": "sha512-ESBRkGLWMuVkapqYCcNO1uqMg5qbCKkgb+VS6wsy17Rix0/cMS9kSOZoYkjH8Ko//pgJ/EEGu0GTjk2mjX2LGQ==" + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.2.tgz", + "integrity": "sha512-WVbrm+cAxPtyMqdtL7cYhR7aZJPhtOfjNClPya8GKMVukKDYs7pEnPINeRVX1C9WmWgU8MdYGYbUPAP2AJXdoQ==" }, "get-caller-file": { "version": "1.0.3", @@ -6801,12 +6958,6 @@ "resolve-dir": "^1.0.0" } }, - "global-modules-path": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.1.tgz", - "integrity": "sha512-y+shkf4InI7mPRHSo2b/k6ix6+NLDtyccYv86whhxrSGX9wjPX1VMITmrDbE1eh7zkzhiWtW2sHklJYoQ62Cxg==", - "dev": true - }, "global-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", @@ -6886,11 +7037,11 @@ } }, "graphql-extensions": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.4.2.tgz", - "integrity": "sha512-a8SD/dlwkg/ujdcf8WnB1RRqgwheSLtY4/Zf5PFZ/nw42ZvD9m9f+tFovUhy1cw25PqQG/MI4xrfDyMy+J7Log==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.5.7.tgz", + "integrity": "sha512-HrU6APE1PiehZ46scMB3S5DezSeCATd8v+e4mmg2bqszMyCFkmAnmK6hR1b5VjHxhzt5/FX21x1WsXfqF4FwdQ==", "requires": { - "@apollographql/apollo-tools": "^0.3.0" + "@apollographql/apollo-tools": "^0.3.3" } }, "graphql-import": { @@ -6948,17 +7099,22 @@ }, "dependencies": { "http-errors": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz", - "integrity": "sha512-jWEUgtZWGSMba9I1N3gc1HmvpBUaNC9vDdA46yScAdp+C5rdEuKWUBLWTQpW9FwSWSbYYs++b6SDCxf9UEJzfw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "requires": { "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.1.0", + "setprototypeof": "1.1.1", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.0" } }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -6992,9 +7148,9 @@ "dev": true }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", "dev": true, "requires": { "async": "^2.5.0", @@ -7004,12 +7160,12 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "source-map": { @@ -7108,9 +7264,9 @@ } }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "header-case": { @@ -7192,9 +7348,9 @@ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, "ignore": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==" + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" }, "ignore-by-default": { "version": "1.0.1", @@ -7334,21 +7490,21 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", - "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", + "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^3.0.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^6.1.0", + "rxjs": "^6.4.0", "string-width": "^2.1.0", "strip-ansi": "^5.0.0", "through": "^2.3.6" @@ -7360,6 +7516,17 @@ "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", "dev": true }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "strip-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", @@ -7442,15 +7609,6 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", @@ -7904,11 +8062,11 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonwebtoken": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", - "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", + "integrity": "sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA==", "requires": { - "jws": "^3.1.5", + "jws": "^3.2.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -7916,7 +8074,8 @@ "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", - "ms": "^2.1.1" + "ms": "^2.1.1", + "semver": "^5.6.0" }, "dependencies": { "ms": { @@ -8081,21 +8240,21 @@ } }, "jwa": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", - "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.3.0.tgz", + "integrity": "sha512-SxObIyzv9a6MYuZYaSN6DhSm9j3+qkokwvCB0/OTSV5ylPq1wUQiygZQcHT5Qlux0I5kmISx3J86TxKhuefItg==", "requires": { "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.10", + "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "jws": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", - "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.1.tgz", + "integrity": "sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==", "requires": { - "jwa": "^1.1.5", + "jwa": "^1.2.0", "safe-buffer": "^5.0.1" } }, @@ -8230,18 +8389,22 @@ } }, "ldapauth-fork": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-4.1.0.tgz", - "integrity": "sha512-OFz3aJDqYGpgo96gVBKhaIFIO/mc9OFpn9IdINHo22eUmF0leU836HgksIQQ3Ga0Mz48xwEhSZ/rJlWOzaUXJQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ldapauth-fork/-/ldapauth-fork-4.2.0.tgz", + "integrity": "sha512-DFYhOO9UPX/fIUnwAjJ4zCq2osR3pyS9TK24oBRLHj7+iw9OAbckHLcdDkgI//IajUEsF6Ngz0uXod6A88L2HA==", "requires": { "@types/ldapjs": "^1.0.0", "@types/node": "^10.12.12", "bcryptjs": "^2.4.0", "ldapjs": "^1.0.2", - "lru-cache": "^5.1.1", - "moment": "^2.22.2" + "lru-cache": "^5.1.1" }, "dependencies": { + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -8250,11 +8413,6 @@ "yallist": "^3.0.2" } }, - "moment": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", - "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" - }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", @@ -8304,12 +8462,6 @@ "resolve": "^1.1.7" } }, - "lightercollective": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lightercollective/-/lightercollective-0.1.0.tgz", - "integrity": "sha512-J9tg5uraYoQKaWbmrzDDexbG6hHnMcWS1qLYgJSWE+mpA3U5OCSeMUhb+K55otgZJ34oFdR0ECvdIb3xuO5JOQ==", - "dev": true - }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -8401,6 +8553,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" @@ -8486,6 +8639,20 @@ "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -8529,6 +8696,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -8542,6 +8710,12 @@ "pify": "^3.0.0" } }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -8550,6 +8724,12 @@ "kind-of": "^6.0.2" } }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -8716,9 +8896,9 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -8726,10 +8906,21 @@ "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", - "pump": "^2.0.1", + "pump": "^3.0.0", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "mixin-deep": { @@ -8766,77 +8957,304 @@ "dev": true }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.0.2.tgz", + "integrity": "sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "findup-sync": "2.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.12.0", + "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - } - } - }, - "moment": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz", - "integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ==", - "optional": true - }, - "morgan": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", - "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", - "requires": { - "basic-auth": "~2.0.0", - "debug": "2.6.9", - "depd": "~1.1.2", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "ms": "2.1.1", + "node-environment-flags": "1.0.4", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "12.0.5", + "yargs-parser": "11.1.1", + "yargs-unparser": "1.5.0" }, "dependencies": { + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + } + } + }, + "mocha-graphql-register": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mocha-graphql-register/-/mocha-graphql-register-1.0.0.tgz", + "integrity": "sha1-FALzIKxAFLxoya196htZsLe4pp8=", + "dev": true + }, + "moment": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz", + "integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ==", + "optional": true + }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "mute-stream": { "version": "0.0.7", @@ -8942,6 +9360,15 @@ "lower-case": "^1.1.1" } }, + "node-environment-flags": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz", + "integrity": "sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, "node-fetch": { "version": "2.1.2", "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", @@ -8978,6 +9405,12 @@ "vm-browserify": "0.0.4" }, "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -8990,21 +9423,21 @@ } }, "node-releases": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.5.tgz", - "integrity": "sha512-6C2K0x1QlYTz9wCueMN/DVZFcBVg/qsj2k9iV5gV/+OvG4KNrl7Nu7TWbWFQ3/Z2V10qVFQWtj5Xa+VBodcI6g==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.8.tgz", + "integrity": "sha512-gQm+K9mGCiT/NXHy+V/ZZS1N/LOaGGqRAAJJs3X9Ah1g+CIbRcBgNyoNYQ+SEtcyAtB9KqDruu+fF7nWjsqRaA==", "dev": true, "requires": { "semver": "^5.3.0" } }, "nodemon": { - "version": "1.18.9", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.9.tgz", - "integrity": "sha512-oj/eEVTEI47pzYAjGkpcNw0xYwTl4XSTUQv2NPQI6PpN3b75PhpuYk3Vb3U80xHCyM2Jm+1j68ULHXl4OR3Afw==", + "version": "1.18.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.10.tgz", + "integrity": "sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ==", "dev": true, "requires": { - "chokidar": "^2.0.4", + "chokidar": "^2.1.0", "debug": "^3.1.0", "ignore-by-default": "^1.0.1", "minimatch": "^3.0.4", @@ -9014,6 +9447,34 @@ "touch": "^3.1.0", "undefsafe": "^2.0.2", "update-notifier": "^2.5.0" + }, + "dependencies": { + "chokidar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz", + "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } } }, "nopt": { @@ -9026,15 +9487,32 @@ } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } } }, "normalize-path": { @@ -9106,15 +9584,15 @@ "dev": true }, "object-hash": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", - "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", "dev": true }, "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==" }, "object-path": { "version": "0.11.4", @@ -9135,6 +9613,18 @@ "isobject": "^3.0.0" } }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", @@ -9286,15 +9776,16 @@ "dev": true }, "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", "dev": true }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, "requires": { "p-try": "^1.0.0" } @@ -9303,6 +9794,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, "requires": { "p-limit": "^1.1.0" } @@ -9310,7 +9802,8 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, "package-json": { "version": "4.0.1", @@ -9337,9 +9830,9 @@ } }, "packet-reader": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", - "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, "pako": { "version": "1.0.8", @@ -9376,9 +9869,9 @@ } }, "parse-asn1": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.3.tgz", - "integrity": "sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "dev": true, "requires": { "asn1.js": "^4.0.0", @@ -9443,23 +9936,20 @@ } }, "passport-ldapauth": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-2.1.1.tgz", - "integrity": "sha512-DiK9nwZthdCeZE+TRx2AzRk9mg8OeAz4+tZdXC8EPVAVmeW7YSWyK4XCJ8/B7ySWpEZtrN1OcrKtWjpLXFy0/A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/passport-ldapauth/-/passport-ldapauth-2.1.2.tgz", + "integrity": "sha512-V+oYNhJwW/ncYHS1IX3eVN9TUH38OsD15Cwo8w+FIV+GXKFJRtUhZyt5nNwExyU0ujMya8Rtzm04+4d8BjvBUg==", "requires": { - "@types/node": "^10.12.12", - "@types/passport": "^0.4.7", - "ldapauth-fork": "^4.1.0", + "@types/node": "^10.12.26", + "@types/passport": "^1.0.0", + "ldapauth-fork": "^4.2.0", "passport-strategy": "^1.0.0" }, "dependencies": { - "@types/passport": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-0.4.7.tgz", - "integrity": "sha512-EePlxNYx5tf3n0yjdPXX0/zDOv0UCwjMyQo4UkWGlhHteNDItAj7TfDdLttSThVMKQz3uCW7lsGzMuml0f8g9Q==", - "requires": { - "@types/express": "*" - } + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" } } }, @@ -9576,12 +10066,12 @@ } }, "pg": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.8.0.tgz", - "integrity": "sha512-yS3C9YD+ft0H7G47uU0eKajgTieggCXdA+Fxhm5G+wionY6kPBa8BEVDwPLMxQvkRkv3/LXiFEqjZm9gfxdW+g==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.8.1.tgz", + "integrity": "sha512-m9aIrOV4mgfo+1Ze+eNoJwaWZDvpeBz8Kzwi0zzqLC+tQBsQgIuu+FGPqzyRv9HFlS7tHO1I33LKp9gP5g7U4Q==", "requires": { "buffer-writer": "2.0.0", - "packet-reader": "0.3.1", + "packet-reader": "1.0.0", "pg-connection-string": "0.1.3", "pg-pool": "^2.0.4", "pg-types": "~2.0.0", @@ -9660,16 +10150,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, "requires": { "find-up": "^2.1.0" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, "popper.js": { "version": "1.14.4", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz", @@ -9696,9 +10181,9 @@ "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=" }, "postgres-interval": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz", - "integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "requires": { "xtend": "^4.0.0" } @@ -9782,6 +10267,13 @@ "@types/long": "^4.0.0", "@types/node": "^10.1.0", "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + } } }, "proxy-addr": { @@ -9802,7 +10294,8 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "pstree.remy": { "version": "1.1.6", @@ -9966,9 +10459,9 @@ } }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "qs": { @@ -9994,9 +10487,9 @@ "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { "safe-buffer": "^5.1.0" @@ -10038,25 +10531,25 @@ } }, "react": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", - "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.3.tgz", + "integrity": "sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "scheduler": "^0.13.3" } }, "react-dom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", - "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.3.tgz", + "integrity": "sha512-ttMem9yJL4/lpItZAQ2NTFAbV7frotHk5DZEHXUOws2rMmrsvh1Na7ThGT0dTzUIl6pqTOi5tYREfL8AEna3lA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "scheduler": "^0.13.3" } }, "react-event-listener": { @@ -10296,9 +10789,9 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz", - "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", + "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", "dev": true, "requires": { "private": "^0.1.6" @@ -10314,54 +10807,10 @@ } }, "regexp-tree": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.0.tgz", - "integrity": "sha512-rHQv+tzu+0l3KS/ERabas1yK49ahNVxuH40WcPg53CzP5p8TgmmyBgHELLyJcvjhTD0e5ahSY6C76LbEVtr7cg==", - "dev": true, - "requires": { - "cli-table3": "^0.5.0", - "colors": "^1.1.2", - "yargs": "^10.0.3" - }, - "dependencies": { - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yargs": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", - "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^8.1.0" - } - } - } + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz", + "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==", + "dev": true }, "regexpp": { "version": "2.0.1", @@ -10584,9 +11033,9 @@ } }, "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -10617,20 +11066,21 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scheduler": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", - "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", + "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" } }, @@ -10642,8 +11092,7 @@ "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "semver-diff": { "version": "2.1.0", @@ -10770,7 +11219,6 @@ "version": "2.4.11", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -11051,11 +11499,11 @@ "dev": true }, "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { - "safe-buffer": "^5.1.1" + "figgy-pudding": "^3.5.1" } }, "static-extend": { @@ -11285,21 +11733,21 @@ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "table": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.2.tgz", - "integrity": "sha512-f8mJmuu9beQEDkKHLzOv4VxVYlU68NpdzjbGPl69i4Hx0sTopJuNxuzJd17iV2h24dAfa93u794OnDA5jqXvfQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", + "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", "dev": true, "requires": { - "ajv": "^6.6.1", + "ajv": "^6.9.1", "lodash": "^4.17.11", - "slice-ansi": "^2.0.0", - "string-width": "^2.1.1" + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { "ajv": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", - "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", + "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -11308,6 +11756,12 @@ "uri-js": "^4.2.2" } }, + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -11319,6 +11773,26 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true + }, + "string-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", + "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" + } } } }, @@ -11368,14 +11842,14 @@ } }, "terser": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.14.1.tgz", - "integrity": "sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw==", + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", + "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", "dev": true, "requires": { "commander": "~2.17.1", "source-map": "~0.6.1", - "source-map-support": "~0.5.6" + "source-map-support": "~0.5.9" }, "dependencies": { "source-map": { @@ -11387,9 +11861,9 @@ } }, "terser-webpack-plugin": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz", - "integrity": "sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz", + "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==", "dev": true, "requires": { "cacache": "^11.0.2", @@ -11397,7 +11871,7 @@ "schema-utils": "^1.0.0", "serialize-javascript": "^1.4.0", "source-map": "^0.6.1", - "terser": "^3.8.1", + "terser": "^3.16.1", "webpack-sources": "^1.1.0", "worker-farm": "^1.5.2" }, @@ -11789,6 +12263,19 @@ "semver": "^5.0.1" } }, + "ts-node": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.2.tgz", + "integrity": "sha512-MosTrinKmaAcWgO8tqMjMJB22h+sp3Rd1i4fdoWY4mhBDekOwIAKI/bzmRi7IcbCmjquccYg2gcF6NBkLgr0Tw==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -11796,9 +12283,9 @@ "dev": true }, "tslint": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.1.tgz", - "integrity": "sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.0.tgz", + "integrity": "sha512-ECOOQRxXCYnUUePG5h/+Z1Zouobk3KFpIHA9aKBB/nnMxs97S1JJPDGt5J4cGm1y9U9VmVlfboOxA8n1kSNzGw==", "dev": true, "requires": { "babel-code-frame": "^6.22.0", @@ -11809,6 +12296,7 @@ "glob": "^7.1.1", "js-yaml": "^3.7.0", "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", @@ -11860,9 +12348,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", - "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "version": "3.3.3333", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", + "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", "dev": true }, "typical": { @@ -12126,14 +12614,6 @@ "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "urix": { @@ -12160,33 +12640,19 @@ } }, "url-loader": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", - "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", "requires": { - "loader-utils": "^1.0.2", - "mime": "^1.4.1", - "schema-utils": "^0.3.0" + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" }, "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "schema-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", - "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", - "requires": { - "ajv": "^5.0.0" - } + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==" } } }, @@ -12341,15 +12807,15 @@ } }, "webpack": { - "version": "4.29.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.0.tgz", - "integrity": "sha512-pxdGG0keDBtamE1mNvT5zyBdx+7wkh6mh7uzMOo/uRQ/fhsdj5FXkh/j5mapzs060forql1oXqXN9HJGju+y7w==", + "version": "4.29.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.5.tgz", + "integrity": "sha512-DuWlYUT982c7XVHodrLO9quFbNpVq5FNxLrMUfYUTlgKW0+yPimynYf1kttSQpEneAL1FH3P3OLNgkyImx8qIQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/wasm-edit": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-module-context": "1.8.3", + "@webassemblyjs/wasm-edit": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3", "acorn": "^6.0.5", "acorn-dynamic-import": "^4.0.0", "ajv": "^6.1.0", @@ -12365,19 +12831,13 @@ "mkdirp": "~0.5.0", "neo-async": "^2.5.0", "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", + "schema-utils": "^1.0.0", "tapable": "^1.1.0", "terser-webpack-plugin": "^1.1.0", "watchpack": "^1.5.0", "webpack-sources": "^1.3.0" }, "dependencies": { - "acorn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", - "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==", - "dev": true - }, "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", @@ -12387,13 +12847,24 @@ "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } } } }, "webpack-cli": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.1.tgz", - "integrity": "sha512-jeJveHwz/vwpJ3B8bxEL5a/rVKIpRNJDsKggfKnxuYeohNDW4Y/wB9N/XHJA093qZyS0r6mYL+/crLsIol4WKA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.3.tgz", + "integrity": "sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==", "dev": true, "requires": { "chalk": "^2.4.1", @@ -12401,22 +12872,14 @@ "enhanced-resolve": "^4.1.0", "findup-sync": "^2.0.0", "global-modules": "^1.0.0", - "global-modules-path": "^2.3.0", "import-local": "^2.0.0", "interpret": "^1.1.0", - "lightercollective": "^0.1.0", "loader-utils": "^1.1.0", "supports-color": "^5.5.0", "v8-compile-cache": "^2.0.2", "yargs": "^12.0.4" }, "dependencies": { - "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -12500,14 +12963,14 @@ } }, "mem": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", - "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", "dev": true, "requires": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^1.0.0", - "p-is-promise": "^1.1.0" + "p-is-promise": "^2.0.0" } }, "os-locale": { @@ -12583,16 +13046,6 @@ "y18n": "^3.2.1 || ^4.0.0", "yargs-parser": "^11.1.1" } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -12607,6 +13060,22 @@ "pify": "^3.0.0" } }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, "webpack-node-externals": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz", @@ -12650,6 +13119,15 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", @@ -12752,9 +13230,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -12772,9 +13250,9 @@ } }, "ws": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.3.tgz", - "integrity": "sha512-tbSxiT+qJI223AP4iLfQbkbxkwdFcneYinM2+x46Gx2wgvbaOMO36czfdfVUBRTHvzAMRhDd98sA5d/BuWbQdg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", "requires": { "async-limiter": "~1.0.0" } @@ -12804,7 +13282,8 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true }, "yargs": { "version": "3.10.0", @@ -12825,14 +13304,200 @@ } }, "yargs-parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", - "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + } + } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + }, + "dependencies": { + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + } } }, + "yn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz", + "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==", + "dev": true + }, "zen-observable": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.9.tgz", diff --git a/package.json b/package.json index b7b45d8c5fb7577144f0386df6c8075cc434e03f..61b663709b6e62324507aa60059a2db92d5d8528 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "eslint": "eslint --ext .js src/ db/", "tslint": "tslint --project tsconfig.json", "tsfix": "tslint --project tsconfig.json --fix", - "test": "mocha --exit" + "tsc": "tsc --project tsconfig.json", + "test": "mocha --require mocha-graphql-register --require ts-node/register test/**/*.test.ts" }, "repository": { "type": "git", @@ -22,25 +23,25 @@ "author": "Binet Réseau", "license": "ISC", "dependencies": { - "apollo-server-express": "^2.3.2", + "apollo-server-express": "^2.4.8", "body-parser": "^1.18.3", "colors": "^1.3.3", "connect-ensure-login": "^0.1.1", "connect-flash": "^0.1.1", - "cookie-parser": "^1.4.3", - "copy-webpack-plugin": "^4.6.0", + "cookie-parser": "^1.4.4", + "copy-webpack-plugin": "^5.0.0", "cors": "^2.8.5", "dotenv": "^6.2.0", "express": "^4.16.4", "express-jwt": "^5.3.1", "express-session": "^1.15.6", - "file-loader": "^1.1.11", + "file-loader": "^3.0.1", "fs": "0.0.1-security", - "fuse.js": "^3.3.0", + "fuse.js": "^3.4.2", "graphql": "^14.1.1", "graphql-tools": "^4.0.4", "graphql-voyager": "^1.0.0-rc.26", - "jsonwebtoken": "^8.4.0", + "jsonwebtoken": "^8.5.0", "knex": "^0.16.3", "ldap-escape": "^1.1.5", "ldapjs": "^1.0.2", @@ -48,34 +49,37 @@ "morgan": "^1.9.1", "package-lock": "^1.0.0", "passport": "^0.4.0", - "passport-ldapauth": "^2.1.1", + "passport-ldapauth": "^2.1.2", "path": "^0.12.7", - "pg": "^7.8.0", + "pg": "^7.8.1", "pug": "^2.0.3", - "react": "^16.7.0", - "react-dom": "^16.7.0", + "react": "^16.8.3", + "react-dom": "^16.8.3", "serve-favicon": "^2.5.0", - "url-loader": "^0.6.2" + "url-loader": "^1.1.2" }, "devDependencies": { "@babel/cli": "^7.2.3", - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.3.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.1", - "@babel/preset-env": "^7.3.1", - "@babel/preset-typescript": "^7.1.0", + "@babel/core": "^7.3.4", + "@babel/plugin-proposal-class-properties": "^7.3.4", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/preset-env": "^7.3.4", + "@babel/preset-typescript": "^7.3.3", + "@types/chai": "^4.1.7", "@types/connect-ensure-login": "^0.1.4", "@types/connect-flash": "0.0.34", - "@types/graphql": "^14.0.5", - "@types/knex": "^0.15.1", - "@types/node": "^10.12.18", + "@types/graphql": "^14.0.7", + "@types/knex": "^0.15.2", + "@types/mocha": "^5.2.6", + "@types/node": "^11.9.5", "@types/passport": "^1.0.0", - "babel-eslint": "^8.2.6", + "apollo-server-testing": "^2.4.8", + "babel-eslint": "^10.0.1", "chai": "^4.2.0", - "eslint": "^5.12.1", + "eslint": "^5.14.1", "eslint-config-standard": "^12.0.0", - "eslint-loader": "^2.1.1", - "eslint-plugin-import": "^2.15.0", + "eslint-loader": "^2.1.2", + "eslint-plugin-import": "^2.16.0", "eslint-plugin-node": "^8.0.1", "eslint-plugin-promise": "^4.0.1", "eslint-plugin-standard": "^4.0.0", @@ -83,13 +87,15 @@ "jsdoc": "^3.5.5", "jsdoc-babel": "^0.5.0", "jsdoc-to-markdown": "^4.0.1", - "mocha": "^5.2.0", - "nodemon": "^1.18.9", + "mocha": "^6.0.2", + "mocha-graphql-register": "^1.0.0", + "nodemon": "^1.18.10", "ts-loader": "^5.3.3", - "tslint": "^5.12.1", - "typescript": "^3.2.4", - "webpack": "^4.29.0", - "webpack-cli": "^3.2.1", + "ts-node": "^8.0.2", + "tslint": "^5.13.0", + "typescript": "^3.3.3333", + "webpack": "^4.29.5", + "webpack-cli": "^3.2.3", "webpack-graphql-loader": "^1.0.0", "webpack-node-externals": "^1.7.2" } diff --git a/src/adminview/admin_router.ts b/src/adminview/admin_router.ts index 8d68d2920fcd04b1aa059c5b3444f32799fd8253..c8b582ff8560365b8b6561a251062e9757ef773a 100644 --- a/src/adminview/admin_router.ts +++ b/src/adminview/admin_router.ts @@ -39,12 +39,16 @@ dotenv.config(); let port = process.env.PORT; const whitelist = [ - "magi.karp", - "mew.two", - "lippou.tou", + "gregoire.grzeckowicz", + "anatole.romon", + "hadrien.renaud", + "wilson.jallet", + "quentin.chevalier", "guillaume.wang", "oliver.facklam", - "octave.hazard" + "octave.hazard", + "guilhem.roy", + "elia.azar" ]; /** * @function ensureIsAdmin diff --git a/src/app.ts b/src/app.ts index 3ad874843269daddf8d4abef4a5768067fc2eaac..1702ae601e66b59276f9162e75cf9c11a36f722b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -209,7 +209,7 @@ const context = async ({ req }): Promise<Context> => { } } console.log(`Constructing context with uid = ${uid}`); - /*return { + let c = { request: req, user: { uid: uid }, models: { @@ -219,21 +219,9 @@ const context = async ({ req }): Promise<Context> => { message: new MessageModel(uid), request: new RequestModel(uid) } - };*/ - let blah = { - request: req, - user: { uid: uid }, - //models: null - models: { - auth: await AuthorizationModel.create(uid), - user: null,//new UserModel(uid), - group: null,//new GroupModel(uid), - message: null,//new MessageModel(uid), - request: null,//new RequestModel(uid) - } }; console.log("finished constructing context"); - return blah; + return c; }; const server = new ApolloServer({ diff --git a/src/config_passport.js b/src/config_passport.js index d82f49baa4fc2f2431251bee2c1875960558eb8f..342634e2e6dfef1084da804c23c1737f0121495d 100644 --- a/src/config_passport.js +++ b/src/config_passport.js @@ -34,14 +34,16 @@ import passport from 'passport'; import LdapStrategy from 'passport-ldapauth'; import { ldapConfig } from './ldap/internal/config'; +console.log("Configuring passportjs... " + ldapConfig.server + " " + ldapConfig.dn.user); + // specifies options for 'ldapauth' strategy, to customize the behaviour of subsequent passport.authenticate('ldapauth') calls passport.use(new LdapStrategy({ server: { url: ldapConfig.server, //bindDn: '.............', //bindCredentials: '..........', - searchBase: ldapConfig.dn_users, // this field cannot be left empty. - searchFilter: '(uid={{username}})', // this field cannot be left empty. + searchBase: ldapConfig.dn.user, // this field cannot be left empty. + searchFilter: '(uid={{username}}*)', // this field cannot be left empty. searchAttributes: ['uid', 'urlPhoto'], // only fetch the uid, no need for any other field //tlsOptions: '..........', //https://www.npmjs.com/package/passport-ldapauth for more @@ -86,6 +88,6 @@ passport.serializeUser(function (user, done) { * > This user object is attached to the request as req.user making it accessible in our request handling. (available in all subsequent middleware) */ passport.deserializeUser(function (userUid, done) { - // console.log(`passport.deserializeUser(): deserializing user ${userUid}`); // DEBUG + console.log(`passport.deserializeUser(): deserializing user ${userUid}`); // DEBUG done(null, { uid: userUid }); }); diff --git a/src/graphql/models/authorization.ts b/src/graphql/models/authorization.ts index be0a395ba06f54dca5d6d06f986dc22d6de0729f..97a18d7fc2e0cca908d445eac4191fc6a88301f4 100644 --- a/src/graphql/models/authorization.ts +++ b/src/graphql/models/authorization.ts @@ -8,14 +8,13 @@ import { Tools, GroupSet, GroupCollection } from "./tools"; import { User as UT } from '../../ldap/export/user' /* - * There are 7 levels of authorization + * There are 6 levels of authorization * none : doesn't know the group / the user exists * connectedOrOnplatal : knows the group exists, can use TOL * viewer : can see the group * member : part of the group * speaker : allowed to speak for the group * admin : admin of the group - * supervisor : allowed to take control of the group */ export class AuthorizationModel { @@ -55,7 +54,6 @@ export class AuthorizationModel { protected memberOf: GroupCollection; protected speakerOf: GroupCollection; protected adminOf: GroupCollection; - protected supervisorOf: GroupCollection; static PUBLICUSER = "public_user"; static ONPLATALUSER = "public_onplatal_user"; @@ -70,13 +68,13 @@ export class AuthorizationModel { console.log("calling UT.peek from ldap connector (User Tool)...") let data = await UT.peek(this.uid); console.log("UT.peek returned with data:"); - console.log(data); + //console.log(data); - this.viewerOf = await Tools.viewerOf(data); this.memberOf = await Tools.memberOf(data); - this.speakerOf = await Tools.viewerOf(data); + this.speakerOf = await Tools.speakerOf(data); this.adminOf = await Tools.adminOf(data); - this.supervisorOf = await Tools.supervisorOf(data); + this.viewerOf = await Tools.viewerOf(this.memberOf); + //console.log(this.viewerOf); } /** @@ -232,12 +230,7 @@ export class AuthorizationModel { //ensure uid is valid !!!!!!!! if (this.isAuthenticated()) { let groups = this.adminOf; - let is_admin = groups.simpleGroups.has(gid) || groups.metaGroups.has(gid); - - //TODO : Vérifier s'il a pris les droits d'admin en étant supervisor - let took_admin_rights = false; - - return (is_admin || took_admin_rights); + return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid)); } return false; } @@ -256,34 +249,4 @@ export class AuthorizationModel { return null; } - /** - * @memberof GraphQL.AuthorizationModel# - * @function isSupervisor - * @summary Fonction qui renvoit si l'utilisateur est supervisor du groupe. - * @arg {string} gid - Identifiant du groupe. - * @return {boolean} Renvoie true si l'utilisateur est supervisor du groupe. - */ - isSupervisor(gid: string): boolean { - //ensure uid is valid !!!!!!!! - if (this.isAuthenticated()) { - let groups = this.supervisorOf; - return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid)); - } - return false; - } - - /** - * @memberof GraphQL.AuthorizationModel# - * @function groupsSupervisor - * @summary Fonction qui renvoit les groupes dont l'utilisateur est supervisor. - * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est supervisor. - */ - groupsSupervisor(): GroupCollection { - //ensure uid is valid !!!!!!!! - if (this.isAuthenticated()) { - return this.supervisorOf; - } - return null; - } - } \ No newline at end of file diff --git a/src/graphql/models/tools.ts b/src/graphql/models/tools.ts index 0f22268622244771df1025598511594e38ea975c..26d0f8b9357507a2abd7c3edc7b7c763c13ecb43 100644 --- a/src/graphql/models/tools.ts +++ b/src/graphql/models/tools.ts @@ -10,13 +10,12 @@ */ import { userData } from '../../ldap/export/user' +import { groupData, Group as GT } from '../../ldap/export/group'; import knex from '../../../db/knex_router'; export class GroupSet extends Set<string> { addList(l: string[]) { - for(let elt of l) { - this.add(elt); - } + for(let elt of l) this.add(elt); } } export interface GroupCollection { @@ -70,7 +69,11 @@ export class Tools { * @async */ static async memberOfSimple(data: userData): Promise<GroupSet> { - return new GroupSet(data.groups); + //Do a DFS from data.members to find all parents + //return Tools.DFS(data.members, 'parent'); + + //No need to do DFS + return new GroupSet(data.members); } /** @@ -82,7 +85,7 @@ export class Tools { * @async */ static async speakerOfSimple(data: userData): Promise<GroupSet> { - throw "Not implemented"; + return new GroupSet(data.speakers); } /** @@ -94,7 +97,11 @@ export class Tools { * @async */ static async adminOfSimple(data: userData): Promise<GroupSet> { - return new GroupSet(data.groupsIsAdmin); + //Do a DFS from data.admins to find all children + //return Tools.DFS(data.admins, 'child'); + + //No need to do DFS + return new GroupSet(data.admins); } /** @@ -106,7 +113,7 @@ export class Tools { * @async */ static async metaGroupsOfGroups(groups: GroupSet): Promise<GroupSet> { - let metas = await knex.select('meta_group_gid').from('metagroup_memberships').whereIn('simple_group_gid', groups); + let metas = await knex.select('meta_group_gid').from('metagroup_memberships').whereIn('simple_group_gid', [...groups]); return new GroupSet(metas.map( elt => { return elt.meta_group_gid; })); @@ -134,9 +141,8 @@ export class Tools { * @async */ static async speakerOf(data: userData): Promise<GroupCollection> { - let speaker = await Tools.speakerOfSimple(data); - let admin = await Tools.adminOfSimple(data); - return { simpleGroups: speaker, metaGroups: await Tools.metaGroupsOfGroups(admin) }; + let simple = await Tools.speakerOfSimple(data); + return { simpleGroups: simple, metaGroups: await Tools.metaGroupsOfGroups(simple) }; } /** @@ -154,19 +160,36 @@ export class Tools { /** * @memberof GraphQL - * @summary Fonction qui fait un parcours en profondeur de l'arbre de racine `gid` et renvoie la liste de tous les noeuds. - * @arg {string} gid - Identifiant du groupe, supposé valide. - * @return {Promise(string[])} Renvoie une liste contenant le nom des groupes dans cet arbre. + * @summary Fonction qui fait un parcours en profondeur du graphe a partir de 'roots' et renvoie la liste de tous les noeuds dans la direction donnée. + * @arg {string[]} roots - Identifiants des groupes racine, supposés valides. + * @arg {'parent'|'child'} direction - Direction de la recherche. 'parent' cherche tous les noeuds ascendants. 'child' cherche tous les noeuds descendants. + * @return {Promise(GroupSet)} Renvoie un ensemble contenant le nom des groupes dans cette direction. * @static * @async */ - static async DFS(gid: string): Promise<string[]> { - let res = [gid]; - let children = await knex.select('gid').from('groups').where('parent_gid', gid); - - for(let child of children) { - let sub_tree = await Tools.DFS(child.gid); - res = res.concat(sub_tree); + static async DFS(roots : string[], direction : 'parent'|'child'): Promise<GroupSet> { + let stack = roots.slice(); + let visited = {}; + let res = new GroupSet(); + + while(stack.length > 0) { + let gid = stack.pop(); + if(visited[gid] !== true) { + visited[gid] = true; + res.add(gid); + + //console.log(gid); + if(direction === 'child') { + let gd = new groupData(); + gd.parents = [gid]; //on cherche les enfants, ie tous les groupes qui ont `gid` comme parent + stack.push(...await GT.search(gd)); + } + else { + let data = await GT.peek(gid); + stack.push(...data.parents) + } + + } } return res; @@ -174,79 +197,47 @@ export class Tools { /** * @memberof GraphQL - * @summary Fonction qui fait un parcours a profondeur 1 de l'arbre de racine `gid` et renvoie la liste des noeuds. - * @arg {string} gid - Identifiant du groupe, supposé valide. - * @return {Promise(string[])} Renvoie une liste contenant le nom des groupes a profondeur 1. + * @summary Fonction qui renvoie la liste des enfants des noeuds de `roots`. + * @arg {GroupSet} roots - Identifiants des groupes racine, supposés valides. + * @return {Promise(string[])} Renvoie une liste contenant le nom des groupes enfants (!! doublons !!). * @static * @async */ - static async oneDownSearch(gid: string): Promise<string[]> { - let res = [gid]; - let children = await knex.select('gid').from('groups').where('parent_gid', gid); + static async oneDownSearch(roots: GroupSet): Promise<string[]> { + let res = []; - for (let child of children) { - res.push(child.gid); + for(let r of roots) { + let gd = new groupData(); + gd.parents = [r]; //on cherche les enfants, ie tous les groupes qui ont `r` comme parent + res.push(...await GT.search(gd)); } return res; } - /** - * @memberof GraphQL - * @summary Fonction qui renvoie tous les groupes dont l'utilisateur est supervisor. - * @desc Utilise {@link Tools.oneDownSearch} pour avoir la profondeur 1 des arbres enracinés en chacun des groupes dont il est admin. - * @arg {userData} data - Données du user. - * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes. - * @static - * @async - */ - static async supervisorOf(data: userData): Promise<GroupCollection> { - let groups = await Tools.adminOf(data); - - let simple = new GroupSet(); - let meta = new GroupSet(); - - for(let g of groups.simpleGroups) { - simple.addList(await Tools.oneDownSearch(g)); - } - for(let g of groups.metaGroups) { - meta.addList(await Tools.oneDownSearch(g)); - } - - return { simpleGroups: simple, metaGroups: meta }; - } - /** * @memberof GraphQL * @summary Fonction qui renvoie tous les groupes dont l'utilisateur est viewer. * @desc Utilise {@link Tools.oneDownSearch} pour avoir la profondeur 1 des arbres enracinés en chacun des groupes dont il est membre. - * @arg {userData} data - Données du user. + * @arg {GroupCollection} groups - Groupes dont le user est membre hérité. * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes. * @static * @async */ - static async viewerOf(data: userData): Promise<GroupCollection> { - let groups = await Tools.memberOf(data); + static async viewerOf(groups: GroupCollection): Promise<GroupCollection> { + let simple = groups.simpleGroups; - let simple = new GroupSet(); - let meta = new GroupSet(); - - //Ajouter les groupes dont il est membre + les fils a profondeur 1 - for(let g of groups.simpleGroups) { - simple.addList(await Tools.oneDownSearch(g)); - } - for(let g of groups.metaGroups) { - meta.addList(await Tools.oneDownSearch(g)); - } + //Ajouter les groupes enfants + simple.addList(await Tools.oneDownSearch(simple)); //Ajouter les groupes simples qui sont dans ses métagroupes - let s = await knex.select('simple_group_gid').from('metagroup_memberships').whereIn('meta_group_gid', groups.metaGroups); + let s = await knex.select('simple_group_gid').from('metagroup_memberships').whereIn('meta_group_gid', [...groups.metaGroups]); simple.addList(s.map( elt => { return elt.simple_group_gid; })); //TODO : rajouter les VisibilityEdges - return { simpleGroups: simple, metaGroups: meta }; + return { simpleGroups: simple, metaGroups: await Tools.metaGroupsOfGroups(simple) }; } } \ No newline at end of file diff --git a/src/graphql/models/userModel.ts b/src/graphql/models/userModel.ts index e9f551754aca227ca09352492d7286a95be174dd..cad226216294b834df87910e00b5780554730217 100644 --- a/src/graphql/models/userModel.ts +++ b/src/graphql/models/userModel.ts @@ -47,19 +47,18 @@ export class UserModel { * @rights connectedOrOnplatal */ async searchTOL(args: searchTOLArgs): Promise<User[]> { - const searchData: userData = { - givenName: args.givenName, - lastName: args.lastName, - nickname: args.nickname, - nationality: args.nationality, - promotion: args.promotion, - groups: args.groups, - sport: args.sport, - phone: args.phone, - mail: args.mail, - address: args.addresses[0], - ips: args.ips - } + //TODO : correctly handle groups (in LDAP, a member can be stored as member, speaker or admin...) + + const searchData = new userData(); + searchData.givenName = args.givenName; + searchData.lastName = args.lastName; + searchData.nickname = args.nickname; + searchData.nationality = args.nationality; + searchData.members = args.groups; + searchData.phone = args.phone; + searchData.mail = args.mail; + searchData.address = args.address; + const userList = await UT.search(searchData); return userList.map((uid) => new User(uid)); } @@ -77,29 +76,23 @@ export class UserModel { let data = await UT.peek(this.contextUser); //Modify some fields, keep the others - let editArgs: userData = { - uid: data.uid, - groups: data.groups, - groupsIsAdmin: data.groupsIsAdmin, - password: data.password, - givenName: data.givenName, - lastName: data.lastName, - nickname: args.nickname, // <- this field is modified by user - promotion: data.promotion, - photo: data.photo, - birthdate: data.birthdate, - nationality: data.nationality, - phone: args.phone, // <- this field is modified - address: data.address, // WTF why can't this be changed ???? - mail: args.mail, // <- this field is modified - ips: data.ips, - directory: data.directory, - login: data.login, - readPerm: data.readPerm, - writePerm: data.writePerm, - forlifes: data.forlifes, - sport: data.sport - }; + let editArgs = new userData(); + editArgs.uid = data.uid; + editArgs.password = data.password; + editArgs.givenName = data.givenName; + editArgs.lastName = data.lastName; + editArgs.nickname = args.nickname; // <- this field is modified by user + editArgs.gender = data.gender; + editArgs.photo = data.photo; + editArgs.phone = args.phone; // <- this field is modified + editArgs.address = data.address; // WTF why can't this be changed ???? + editArgs.mail = args.mail; // <- this field is modified + editArgs.birthdate = data.birthdate; + editArgs.nationality = data.nationality; + editArgs.admins = data.admins; + editArgs.speakers = data.speakers; + editArgs.members = data.members; + editArgs.followers = data.followers; if(await UT.edit(editArgs)) { return new User(data.uid); diff --git a/src/graphql/object_resolvers/groups.ts b/src/graphql/object_resolvers/groups.ts index 6c22f21961bb115315988f9776076324917683b6..59e5511a6780984987bdb7ef2a86a023eb6c452c 100644 --- a/src/graphql/object_resolvers/groups.ts +++ b/src/graphql/object_resolvers/groups.ts @@ -60,24 +60,7 @@ export abstract class Group { * Ci-dessous les resolvers a proprement parler. */ - /** - * @memberof GraphQL.Group# - * @function __resolveType - * @summary Renvoie si c'est un SimpleGroup ou un MetaGroup - * @return {string} - * @rights connectedOrOnplatal - */ - __resolveType(args, context: Context, info): string { - if(this instanceof SimpleGroup) { - return "SimpleGroup"; - } - else if(this instanceof MetaGroup) { - return "MetaGroup"; - } - else { - throw new ApolloError("Bad group type"); - } - } + __typename : string = "Bad group type"; /** @rights connectedOrOnplatal */ gid: string; @@ -505,6 +488,8 @@ export class SimpleGroup extends Group { * Ci-dessous les resolvers a proprement parler. */ + __typename: string = "SimpleGroup"; + /** * @memberof GraphQL.SimpleGroup# * @function members @@ -729,6 +714,8 @@ export class MetaGroup extends Group { * Ci-dessous les resolvers a proprement parler. */ + __typename: string = "MetaGroup"; + /** * @memberof GraphQL.MetaGroup# * @function admins diff --git a/src/graphql/object_resolvers/users.ts b/src/graphql/object_resolvers/users.ts index 28ee5f8fccb586fb89699fa70bc8fe584683e4d3..c69048c4152c48b492ed55be13dcb4f88f1607cd 100644 --- a/src/graphql/object_resolvers/users.ts +++ b/src/graphql/object_resolvers/users.ts @@ -64,16 +64,15 @@ export class User { this.m_nickname = data.nickname; this.m_nationality = data.nationality; this.m_birthdate = data.birthdate; - this.m_promotion = data.promotion; this.m_mail = data.mail; this.m_phone = data.phone; - this.m_addresses = [data.address]; + this.m_address = data.address; - this.m_memberOf = data.groups; - //this.m_speakerOf = data.groupsIsSpeaker; - this.m_adminOf = data.groupsIsAdmin; - //this.m_likes = data.likes; + this.m_memberOf = data.members; + this.m_speakerOf = data.speakers; + this.m_adminOf = data.admins; + this.m_likes = data.followers; this.m_dataLoaded = true; return true; @@ -99,11 +98,10 @@ export class User { protected m_nickname: string protected m_nationality: string protected m_birthdate: string - protected m_promotion: string protected m_mail: string protected m_phone: string - protected m_addresses: string[] + protected m_address: string protected m_memberOf: string[] protected m_speakerOf: string[] @@ -192,7 +190,7 @@ export class User { */ async promotion(args, context: Context, info): Promise<string> { await this.fetchData(); - return this.m_promotion; + throw "Not implemented"; } /** @@ -223,15 +221,15 @@ export class User { /** * @memberof GraphQL.User# - * @function addresses - * @summary Renvoie les adresses - * @return {Promise(string[])} + * @function address + * @summary Renvoie l'adresse + * @return {Promise(string)} * @rights connectedOrOnplatal * @async */ - async addresses(args, context: Context, info): Promise<string[]> { + async address(args, context: Context, info): Promise<string> { await this.fetchData(); - return this.m_addresses; + return this.m_address; } /** @@ -247,13 +245,15 @@ export class User { let simple = new GroupSet(this.m_memberOf); let meta = await Tools.metaGroupsOfGroups(simple); - let all: Group[]; + let all = new Array<Group>(); for(let gid of simple) { all.push(new SimpleGroup(gid)); + //all.push(await SimpleGroup.tryCreate(gid)); } for(let gid of meta) { all.push(new MetaGroup(gid)); + //all.push(await MetaGroup.tryCreate(gid)); } return all; diff --git a/src/graphql/typeDefs/actions.graphql b/src/graphql/typeDefs/actions.graphql index afbe385f1b7b2e24dbee9547ab5c710950ca9bcf..9fe106739adfd8abdadeab53f27331ceae4636c1 100644 --- a/src/graphql/typeDefs/actions.graphql +++ b/src/graphql/typeDefs/actions.graphql @@ -41,14 +41,11 @@ type Query { nickname: String, nationality: String, school: String, - promotion: String, groups: [String], studies: String, - sport: String, phone: String, mail: String, - addresses: [String], - ips: [String] + address: String ): [User!] } @@ -88,7 +85,7 @@ type Mutation { == Pour les méta-groupes == - Un user est membre d'un méta-groupe G s'il est membre (hérité) d'un groupe simple dans G. - - Un user est speaker d'un méta-groupe G s'il est admin strict d'un groupe simple dans G. + - Un user est speaker d'un méta-groupe G s'il est speaker d'un groupe simple dans G. - Un user est admin d'un méta-groupe G s'il est admin (hérité) d'un groupe simple dans G. - Un user est viewer d'un méta-groupe G s'il est viewer d'un groupe simple dans G. diff --git a/src/graphql/typeDefs/queries.d.ts b/src/graphql/typeDefs/queries.d.ts index 75c7b9517cbe074e38c4e3c4ad0ffd2a04a8915c..31d469632dbc75cd3393622e98b3ac71fb3889b0 100644 --- a/src/graphql/typeDefs/queries.d.ts +++ b/src/graphql/typeDefs/queries.d.ts @@ -1,3 +1,8 @@ +/** + * @file Ce fichier définit quelques types utiles pour le serveur Apollo. + * @author ofacklam +*/ + import { AuthorizationModel } from "../models/authorization"; import { UserModel } from "../models/userModel"; import { GroupModel } from "../models/groupModel"; @@ -22,14 +27,11 @@ interface searchTOLArgs { nickname: string, nationality: string, school: string, - promotion: string, groups: string[], studies: string, - sport: string, phone: string, mail: string, - addresses: string[], - ips: string[] + address: string } interface editProfileArgs { diff --git a/src/ldap/export/group.ts b/src/ldap/export/group.ts index 7f9f11f9d4fd12d7600e67f40942113339a0646d..d36eb37a844afe75926bc3cc8c51b5eab1e66f34 100644 --- a/src/ldap/export/group.ts +++ b/src/ldap/export/group.ts @@ -1,34 +1,19 @@ /** * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers. * @author hawkspar + * @memberof LDAP */ -import {ldapConfig} from '../internal/config'; +import { ldapConfig, groupData, categories } from '../internal/config'; import {Basics} from '../internal/basics'; import {Tools} from '../internal/tools'; -/** - * @interface groupData - * @var {string} gid - Identifiant du groupe - * @var {string} name - Nom du groupe (souvent son nom mais pas nécessairement) - * @var {string} type - Statut du groupe ; binet, section sportive... (actuellement juste 'binet' ou 'free') - * @var {string[]} members - Liste des membres du groupe - * @var {string[]} admins - Liste des admins du groupe ; supposée être une sous-liste de la précédente - * @var {string} description - Description du groupe (facultatif) - */ -export interface groupData { - "gid": string, - "name": string, - "type": string, - "members": string[], - "admins": string[], - "description"?: string -} - //------------------------------------------------------------------------------------------------------------------------ // Classes à exporter TBT //------------------------------------------------------------------------------------------------------------------------ +export {groupData}; + export class Group { /** * @memberof LDAP @@ -41,7 +26,7 @@ export class Group { /** * @memberof LDAP * @summary Fonction qui renvoit toutes les infos relatives à un groupe particulier. - * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link groupData}. + * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link groupData}. Elle ne fait que consulter le groupe sans le changer, et en extrayant les uid des membres. * @arg {string} gid - Identifiant du groupe * @return {Promise(groupData)} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe au format {@link groupData}. * @static @@ -49,7 +34,10 @@ export class Group { */ static async peek(gid: string) : Promise<groupData> { try { - return Tools.peek<groupData>("gr", gid); + let data = await Tools.peek<groupData>("group", gid, groupData); + // Extraction des uid de membres (TBM pour inclure childs aussi) + for (let cat of categories.concat(["parents"])) data[cat] = data[cat].map(dn => dn.split(',')[0].split('=')[1]); + return data; } catch(err) { throw "Erreur lors d'une recherche d'informations sur un groupe."; @@ -67,185 +55,117 @@ export class Group { */ static async search(data: groupData) : Promise<string[]> { try { - return Tools.search("gr", data); + return Tools.search("group", data); } catch(err) { throw "Erreur lors de la recherche approximative d'un groupe."; } } + /** + * @memberof LDAP + * @summary Fonction qui permet de rajouter un administrateur à un groupe. + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Le nouvel administrateur ne devient pas membre ou porte-parole du groupe pour autant ! + * @arg {string} uid - Identifiant du membre futur admin + * @arg {string} gid - Identifiant du groupe + * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async addAdmin(uid: string, gid: string): Promise<boolean> { return Tools.add(uid, gid, "admins"); } + + /** + * @memberof LDAP + * @summary Fonction qui permet de supprimer un administrateur. + * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}. + * Elle ne remonte pas les échelons, car cela permettrait à un admin d'un petit groupe de supprimer un admin d'un grand. + * @arg {string} uid - Identifiant de l'admin à dégrader, supposé membre + * @arg {string} gid - Identifiant du groupe + * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remAdmin(uid: string, gid: string): Promise<boolean> { return Tools.remove(uid, gid, "admins"); } + + /** + * @memberof LDAP + * @summary Fonction qui permet de rajouter un porte-parole à un groupe. + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Elle ne rajoute pas l'utilisateur au groupe. + * @arg {string} uid - Identifiant du membre futur porte-parole + * @arg {string} gid - Identifiant du groupe + * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async addSpeaker(uid: string, gid: string): Promise<boolean> { return Tools.add(uid, gid, "speakers"); } + + /** + * @memberof LDAP + * @summary Fonction qui permet de rétrograder un membre du stade de porte-parole d'un groupe au stade d'utilisateur. + * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}. Elle dégrade aussi d'un éventuel statut d'administrateur. + * @arg {string} uid - Identifiant de l'admin à dégrader (pas supposé valide) + * @arg {string} gid - Identifiant du groupe + * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remSpeaker(uid: string, gid: string): Promise<boolean> { return Tools.remove(uid, gid, "speakers"); } + /** * @memberof LDAP * @summary Fonction qui permet d'ajouter un utilisateur à un groupe. - * @desc Cette fonction fait essentiellement appel à {@link Tools.getMembers}, {@link Tools.getGroups} et {@link LDAP.change}. + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. * @arg {string} uid - Identifiant de l'utilisateur à ajouter * @arg {string} gid - Identifiant du groupe * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ - static async addMember(uid: string, gid: string) : Promise<boolean> { - try { - // Vérifie que l'utilisateur est pas déjà membre pour groupes - let lm = await Tools.getMembers(gid); - if (!lm.includes(uid)) { - let vals = {}; - vals[ldapConfig.group.members] = uid; - // Erreur si pb lors de la modification - if (!await Basics.change("gr", gid, "add", vals)) { - throw "Erreur lors de la modification dans l'arbre des groupes pour ajouter un membre."; - } - } - } - catch(err) { - throw "Erreur lors de la recherche de la liste des membres pour ajouter un membre."; - } - try { - // Vérifie que l'utilisateur est pas déjà membre pour users - let lg = await Tools.getGroups(uid); - if (!lg.includes(gid)) { - let vals2 = {}; - vals2[ldapConfig.user.groups] = gid; - // Erreur si pb lors de la modification - if (!await Basics.change("us", uid, "add", vals2)) { - throw "Erreur lors de la modification dans l'arbre des utilisateurs pour ajouter un membre."; - } - } - return true; - } - catch(err) { - throw "Erreur lors de la recherche de la liste des membres pour ajouter un membre."; - } - } + static async addMember(uid: string, gid: string) : Promise<boolean> { return Tools.add(uid, gid, "members"); } /** * @memberof LDAP * @summary Fonction qui permet de supprimer un membre existant d'un groupe. - * @desc Cette fonction fait essentiellement appel à {@link Tools.getMembers}, {@link Tools.getGroups} et {@link LDAP.change}. - * @arg {string} uid - Identifiant de l'ex-membre + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. + * Cette fonction supprime tous les droits de l'utilisateur sur le groupe, mais aussi sur les groupes sources si son statut de membre était hérité. + * @arg {string} uid - Identifiant de l'ex-membre (pas supposé valide) * @arg {string} gid - Identifiant du groupe * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ - static async remMember(uid: string, gid: string): Promise<boolean> { - try { - // Vérifie que l'utilisateur est pas déjà viré pour groupes - let lm = await Tools.getMembers(gid); - if (lm.includes(uid)) { - // Supprime tous les utilisateurs - if (!await Basics.change("gr", gid, "del", ldapConfig.group.members)) { - throw "Erreur lors de la suppression de tous les membres du groupe."; - } - // Les rajoute un par un, sauf pour le supprimé - lm.forEach(id => { - if (id!=uid) { - Group.addMember(id, gid).then(res => { - if (!res) { throw "Erreur lors du ré-ajout d'un autre membre"; } - }); - } - }); - } - } - catch(err) { - throw "Erreur pour obtenir une liste de membres d'un groupe pour supprimer un membre du groupe."; - } - try { - let lg = await Tools.getGroups(uid); - // Vérifie que l'utilisateur est pas déjà viré pour users - if (lg.includes(gid)) { - // Supprime tous les groupes - if (!await Basics.change("us", uid, "del", ldapConfig.user.groups)) { - throw "Erreur lors de la suppression de tous les groupes du membre."; - } - // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) { - Group.addMember(uid, id).then(res => { - if (!res) { throw "Erreur lors du ré-ajout des autres groupes"; } - }); - } - }); - } - return true; - } - catch(err) { - throw "Erreur pour obtenir une liste de groupes d'un membres pour le supprimer du groupe."; - } - } + static async remMember(uid: string, gid: string): Promise<boolean> { return Tools.remove(uid, gid, "members"); } /** * @memberof LDAP - * @summary Fonction qui permet de promouvoir un membre au stade d'administrateur d'un groupe. - * @desc Cette fonction fait essentiellement appel à {@link Group.addMember} {@link Tools.getAdmins} et {@link LDAP.change}. Elle n'autorise pas - * les doublons et opère dans les deux dns users et groups. - * @arg {string} uid - Identifiant du membre futur admin + * @summary Fonction qui permet d'ajouter un sympathisant à un groupe. + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. + * @arg {string} uid - Identifiant de l'utilisateur à ajouter * @arg {string} gid - Identifiant du groupe - * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ - static async addAdmin(uid: string, gid: string): Promise<boolean> { - // Ajoute le membre au groupe avant d'en faire un admin - if (!await Group.addMember(uid,gid)) { throw "Erreur lors de l'ajout du futur admin en tant que membre."; } - try { - let la = await Tools.getAdmins(gid); - if (!la.includes(uid)) { - // Finalement modification, uniquement dans groups - let vals = {}; - vals[ldapConfig.group.admins] = uid; - if (!await Basics.change("gr", gid, "add", vals)) { - throw "Erreur lors de l'ajout de l'admin dans l'arbre des groupes."; - } - } - return true; - } - catch(err) { - throw "Erreur lors de l'obtention de la liste des administrateurs d'un groupe."; - } - } + static async addFollower(uid: string, gid: string) : Promise<boolean> { return Tools.add(uid, gid, "followers"); } /** * @memberof LDAP - * @summary Fonction qui permet de rétrograder un membre du stade d'administrateur d'un groupe au stade d'utilisateur. - * @desc Cette fonction fait essentiellement appel à {@link Group.remMember}, {@link Group.addMember} {@link LDAP.change}. - * Rajoute l'utilisateur au groupe par effet de bord si l'utilisateur n'est pas administrateur. - * @arg {string} uid - Identifiant de l'admin à dégrader, supposé membre + * @summary Fonction qui permet de supprimer un sympathisant d'un groupe. + * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. + * @arg {string} uid - Identifiant de l'ex-sympathisant (pas supposé valide) * @arg {string} gid - Identifiant du groupe - * @return {boolean} `true` si la modification s'est bien déroulée, false sinon + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static */ - static async remAdmin(uid: string, gid: string): Promise<boolean> { - // Peut paraître absurde mais permet de s'assurer que le membre est bien présent et que ses champs sont comme il faut - if (!(await Group.remMember(uid, gid) && Group.addMember(uid,gid))) { throw "Erreur dans l'éjection/réadmission de l'ex-admin."; } - try { - // Vérifie que l'utilisateur est bien admin (comme dans delGroupMember) - let la = await Tools.getAdmins(gid); - if (la.includes(uid)) { - // Supprime tous les administrateurs - if (!await Basics.change("gr", gid, "del", ldapConfig.group.admins)) { - throw "Erreur dans la suppression de tous les admins pour en supprimer un."; - } - // Les rajoute un par un, sauf pour le supprimé - la.forEach(id => { - if (id!=uid) { Group.addAdmin(id, gid).then(res => { - if (!res) { throw "Erreur dans le réajout d'un des autres admins."; } - }); } - }); - } - return true; - } - catch(err) { - throw "Erreur lors de l'obtention de la liste des administrateurs d'un groupe."; - } - } + static async remFollower(uid: string, gid: string): Promise<boolean> { return Tools.remove(uid, gid, "followers"); } + /** * @memberof LDAP * @summary Fonction qui créé un nouveau groupe dans le LDAP. * @desc Cette fonction fait une utilisation massive d'eval pour anonymiser son code ; c'est mal et cela suppose que beaucoup de soins ont été pris lors de - * l'escape de ses paramètres. Appelle {@link LDAP.add} et {@link LDAP.change}, mais aussi {@link Group.addMember} et {@link Group.addAdmin} - * pour gérer les groupes du nouvel utilisateur. Attention une manip FOIREUSE est cachée dedans. + * l'escape de ses paramètres. Appelle {@link LDAP.add} et {@link LDAP.change}, mais aussi {@link Tools.add} + * pour gérer les groupes du nouvel utilisateur. Cettte application permet de rajouter des utilisateurs à toutes les catégories du groupe. * @arg {groupData} data - Dictionnaire des informations utilisateurs (voir détail des champs dans ldapConfig.json) * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async @@ -257,80 +177,67 @@ export class Group { // gid de base généré à partir du nom standardisé, pas à partir de l'entrée 'gid' ! try { - Tools.generateReadableId(data['name']).then(id => { - vals[ldapConfig.key_id]=id; - vals[ldapConfig.group['name']]=id; + Tools.generateReadableId("group", data['name']).then(id => { + vals[ldapConfig.group.gid] = id; + vals[ldapConfig.group['name']] = id; }); } catch(err) { throw "Erreur lors de la génération d'un hruid pour créer un nouveau groupe."; } - let gid: string = vals[ldapConfig.key_id]; + let gid: string = vals[ldapConfig.group.gid]; // Ecriture de toutes les valeurs directement inscrites dans le LDAP - for (let key_att in data) { vals[ldapConfig.group[key_att]]=data[key_att] }; + for (let key_att of ["name","logo","description","site","category"]) { + if (data[key_att] != undefined) vals[ldapConfig.group[key_att]]=data[key_att] + }; // Appel à la fonction de base - if (!await Basics.add("gr", vals)) { - throw "Erreur lors de la création d'une nouvelle feuille dans l'arbre des groupes."; - } + if (!await Basics.add("group", vals)) throw "Erreur lors de la création d'une nouvelle feuille dans l'arbre des groupes."; + // Certains champs nécessitent de petits calculs let vals2={}; - // Encore un champ redondant - vals2[ldapConfig.group['adress']] = gid; - // ?! - vals2[ldapConfig.group['password']] = ''; + vals2[ldapConfig.group['password']] = "{CRYPT}"+data['password']; // Génération id aléatoire et test contre le LDAP try { - Tools.generateId(ldapConfig.group["idNumber"], "gr").then(id => { vals2[ldapConfig.group['idNumber']]=id; }); + Tools.generateId(ldapConfig.group["idNumber"], "group").then(id => { vals2[ldapConfig.group['idNumber']]=id; }); } catch(err) { throw "Erreur lors de la génération d'un id numérique pour créer un nouveau groupe."; } - // FOIREUX : Hypothèse sur la structure du reste des données mais évite un test.assurerUnicite à deux variables - vals2[ldapConfig.group['idNumber2']]=vals2[ldapConfig.group['idNumber']]; - - // Stockage machine ; dépend du prénom - vals2[ldapConfig.group['directory']] = '/hosting/groups/'+gid; - - // Code root - vals2[ldapConfig.group['cleanFullName']]=data['name'].replace(':', ';').toLowerCase().normalize('UFD'); - - // Adressage root - vals2[ldapConfig.group['login']] = "/sbin/nologin"; - - // Permissions BR - vals2[ldapConfig.group['readPerm']] = '!*'; - vals2[ldapConfig.group['writePerm']] = '!*'; // Inscription des valeurs calculées par effet de bord - if (!await Basics.change("gr", gid, "add", vals2)) { + if (!await Basics.change("group", gid, "add", vals2)) { throw "Erreur lors de l'ajout des valeurs intelligentes du nouveau groupe."; } - ["posixAccount", "posixGroup", "brAccount"].forEach(cst => { + ["posixGroup", "brGroup"].forEach(cst => { let vals3={}; vals3[ldapConfig.group['classes']]=cst; - Basics.change("gr", gid, "add", vals3).then(res => { - if (!res) { throw "Erreur lors de l'ajout des valeurs constantes du nouveau groupe."; } + Basics.change("group", gid, "add", vals3).then(res => { + if (!res) throw "Erreur lors de l'ajout des valeurs constantes du nouveau groupe."; + }); }); + + // Ajout groupes parents et fils + for (let rel of ["childs","parents"]) { + data[rel].forEach(gid => { + let tmp = ldapConfig.group[rel]; + Basics.change("group", gid, "add", { tmp: gid }).then(res => { + if (!res) throw "Erreur de l'ajout d'un groupe associé au nouveau groupe."; + }); }); - }); + } // Utilisation des fonctions adaptées pour assurer la cohérence de l'ensemble - data['members'].forEach(uid => { - Group.addMember(uid, gid).then(res => { - if (!res) { throw "Erreur de l'ajout d'un membre au groupe."; } - }); - }); - data['admins'].forEach(uid => { - Group.addAdmin(uid, gid).then(res => { - if (!res) { throw "Erreur de l'ajout d'un admin au groupe."; } + for (let cat of categories) { + for (let uid of data[cat]) Tools.add(uid, gid, cat).then(res => { + if (!res) throw "Erreur de l'ajout d'un membre au nouveau groupe."; }); - }); + } return true; } @@ -338,7 +245,7 @@ export class Group { * @memberof LDAP * @summary Fonction qui supprime un groupe du LDAP. * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. A modifier une fois que le LDAP incluerait les groupes administres par une utilisateur. - * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Group.remMember} et {@link Group.remAdmin} pour gérer les groupes de l'utilisateur sortant. + * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} pour gérer les groupes de l'utilisateur sortant. * @arg {string} gid - gid de la victime * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async @@ -346,30 +253,11 @@ export class Group { */ static async delete(gid: string): Promise<boolean> { try { - // Gestion des administrateur et membres d'abord - let profil = await Group.peek(gid); - // Modification du profil de chaque utilisateur - profil[ldapConfig.group['member']].forEach(async function quickPartRemUser(uid: string) { - // Modification des profils de tous les utilisateurs - let lg = await Tools.getGroups(uid); - // Vérifie que l'utilisateur est pas déjà viré pour users - if (lg.includes(gid)) { - // Supprime tous les groupes - if (!await Basics.change("us", uid, "del", ldapConfig.user.groups)) { - throw "Erreur lors de la suppression de tous les groupes du membre."; - } - // Les rajoute un par un, sauf pour le supprimé - lg.forEach(id => { - if (id!=gid) { - Group.addMember(uid, id).then(res => { - if (!res) { throw "Erreur lors du ré-ajout des autres groupes"; } - }); - } - }); - } - }); + // Gestion des catégories en bloc d'abord + let profile = await Group.peek(gid); + for (let cat of categories) profile[ldapConfig.group[cat]].forEach(uid => Tools.remove(uid, gid, cat)); // Elimination - if (!await Basics.clear("gr",gid)) { throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes."; } + if (!await Basics.clear("group",gid)) throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes."; return true; } catch(err) { @@ -388,7 +276,7 @@ export class Group { */ static async edit(data: groupData) : Promise<boolean> { try { - return Tools.edit("gr",data); + return Tools.edit("group",data); } catch(err) { throw "Erreur lors de la modification d'un groupe."; diff --git a/src/ldap/export/user.ts b/src/ldap/export/user.ts index b50f668b223274b1a78734d7504357ea9488378b..c9c4b8d1ab9b16afbe83d6305ac9c7dc11abc1a3 100644 --- a/src/ldap/export/user.ts +++ b/src/ldap/export/user.ts @@ -1,67 +1,19 @@ /** * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers. * @author hawkspar + * @memberof LDAP */ -import {ldapConfig} from '../internal/config'; +import { ldapConfig, userData, categories } from '../internal/config'; import {Basics} from '../internal/basics'; import {Tools} from '../internal/tools'; -import {Group} from './group'; - -/** - * @interface userData - * @desc Interface avec toutes les données extractables pour un utilisateur. - * @var {string} uid - Identifiant utilisateur - * @var {string} givenName - Prénom - * @var {string} lastName - Nom - * @var {string} nickname - Surnom - * @var {string} photo - Bytestring de la photo de l'utilisateur - * @var {string} birthdate - Date d'anniversaire - * TBA @var {string} nationality - Nationalité d'origine - * @var {string} promotion - Année(s) de promo - * @var {string} phone - Numéro(s) de téléphone - * @var {string[]} address - Adresse(s) - * @var {string[]} mail - Adresse(s) courriel - * @var {string[]} groups - Un ou plusieurs groupes dont l'utilisateur est membre (inclus section sportive, binet, PA...) - * @var {string} password - Mot de passe généré en amont - * @var {string[]} ips - Adresse(s) ip - * @var {string} directory - Adresse soft des données utilisateurs - * @var {string} login - Astuce de root flemmard - * @arg {string} readPerm - Permissions spéciales BR - * @var {string} writePerm - Permissions spéciales BR - * @var {string[]} forlifes - Alias BR (attention le filtre .fkz n'est plus fonctionnel) - * @var {string[]} admins - Liste des gid dont l'utilisateur est admin ; supposé sous-liste de groups - * TBA @var {string[]} likes - Liste des gid dont l'utilisateur est sympathisant - */ -export interface userData { - uid?: string, - groups?: string[], - groupsIsAdmin?: string[], - password?: string, - givenName?: string, - lastName?: string, - nickname?: string, - promotion?: string, - photo?: string, - birthdate?: string, - nationality?: string, - phone?: string, - address?: string, - mail?: string, - ips?: string[], - directory?: string, - login?: string, - readPerm?: string, - writePerm?: string, - forlifes?: string[], - sport?: string - //"likes"?: string[] -} //------------------------------------------------------------------------------------------------------------------------ // Classes à exporter TBT //------------------------------------------------------------------------------------------------------------------------ +export {userData}; + export class User { /** * @memberof LDAP @@ -82,7 +34,9 @@ export class User { */ static async peek(uid: string) : Promise<userData> { try { - return Tools.peek<userData>("us", uid); + let data = await Tools.peek<userData>("user", uid, userData); + for (let cat of categories) data[cat] = data[cat].map(dn => dn.split(',')[0].split('=')[1]); + return data; } catch(err) { throw "Error while peeking a user."; @@ -102,7 +56,7 @@ export class User { */ static async search(data: userData) : Promise<string[]> { try { - return Tools.search("us", data); + return Tools.search("user", data); } catch(err) { throw "Erreur lors de la recherche approximative d'un utilisateur."; @@ -112,9 +66,9 @@ export class User { /** * @memberof LDAP * @summary Fonction qui créé un nouvel utilisateur dans le LDAP. - * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Group.addMember} et {@link Group.addAdmin} pour gérer les groupes du nouvel utilisateur. - * @arg {fullUserData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis. - * Cette application ne permet pas de rejoindre des groupes. + * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Tools.add} pour gérer les groupes du nouvel utilisateur. + * @arg {userData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis. + * Cette application permet de rejoindre des groupes en masse pour toute catégorie, à la fois façon Sigma et CAS. * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async * @static @@ -126,90 +80,60 @@ export class User { // uid de base généré à partir de nom et prénom, plus potentiellement promo et un offset // MEF mélange de Promise et de fonction standard try { - Tools.generateUid(data['givenName'],data['lastName'],data['promotion']).then(id => { vals[ldapConfig.key_id]=id; } ); + Tools.generateUid("user",data['givenName'],data['lastName'],data['birthdate']).then(id => { vals[ldapConfig.user.uid]=id; } ); } catch(err) { throw "Erreur lors de la génération d'un hruid pour un nouvel utilisateur."; } - let uid = vals[ldapConfig.key_id]; + let uid : string = vals[ldapConfig.user.uid]; // Génère une erreur si un champ n'est pas rempli - for (let key_att in data) { + for (let key_att of ["givenName","lastName","nickname","gender","photo","phone","adress","mail","birthdate","nationality"]) { // Ecriture de toutes les valeurs uniques - if (!Array.isArray(data[key_att])) { vals[ldapConfig.user[key_att]]=data[key_att]; } + if (data[key_att] != undefined) vals[ldapConfig.user[key_att]]=data[key_att]; } // Appel à la fonction de base - if (!await Basics.add("us", vals)) { throw "Erreur de l'ajout de la feuille à l'arbre utilisateur."; } - - for (let key_att in data) { - // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples - if (Array.isArray(data[key_att])) { - // On rajoute chaque valeur en entrée - data[key_att].forEach(val => { - let vals2 = {}; - vals2[ldapConfig.user[key_att]]=val; - Basics.change("us", uid, "add", vals2).then(res => { - if (!res) { throw "Erreur lors de l'ajout d'une valeur pour un champ à valeurs multiples à la feuille du nouvel utilisateur."; } - }); - }); - } - } + if (!await Basics.add("user", vals)) throw "Erreur de l'ajout de la feuille à l'arbre utilisateur."; // Certains champs nécessitent de petits calculs let vals3={}; - // Création d'un nom complet lisible - vals3[ldapConfig.user['fullName']]=data['givenName']+' '+data['lastName'].toUpperCase(); - // ldapConfiguration du mot de passe utilisateur // Le préfixe {CRYPT} signifie que le mdp est hashé dans OpenLDAP voir : https://www.openldap.org/doc/admin24/security.html vals3[ldapConfig.user['password']] = "{CRYPT}"+data['password']; // Ecriture d'un surnom s'il y a lieu - if ((data['nickname']!=undefined) && (data['nickname']!='')) { - vals3[ldapConfig.user['nickname']]=data['nickname']; - } + if ((data['nickname']!=undefined) && (data['nickname']!='')) vals3[ldapConfig.user['nickname']]=data['nickname']; try { // Génération id aléatoire unique - vals3[ldapConfig.user['id']]= await Tools.generateId(ldapConfig.user['id'], "us"); + vals3[ldapConfig.user['id']]= await Tools.generateId(ldapConfig.user['id'], "user"); } catch(err) { throw "Erreur lors de la génération d'un id numérique pour un nouvel utilisateur."; } - - // Stockage machine ; dépend du prénom - vals3[ldapConfig.user['directory']] = '/hosting/users/' + data['givenName'][0]; // Code root vals3[ldapConfig.user['cleanFullName']]=data['fullName'].replace(':', ';').toLowerCase().normalize('UFD'); - - // Adressage root - if (data['groups'].includes("on_platal")) { vals3[ldapConfig.user['login']] = "/bin/bash"; } - else { vals3[ldapConfig.user['login']] = "/sbin/nologin"; } - - // Permissions BR - vals3[ldapConfig.user['readPerm']] = 'br.*,public.*'; - if (data['readPerm'].length>0) { vals3[ldapConfig.user['readPerm']] += ',' + data['readPerm']; } - vals3[ldapConfig.user['writePerm']] = 'br.*,!br.blague-du-jour,public.*,!br.campagnekes'; - if (data['writePerm'].length>0) { vals3[ldapConfig.user['readPerm']] += ',' + data['writePerm']; } - - // Valeur nécessaire ASKIP mais inutile - vals3[ldapConfig.user['idNum']] ='5000'; // Inscription des valeurs calculées - if (!await Basics.change("us", uid, "add", vals3)) { - throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur."; - } + if (!await Basics.change("user", uid, "add", vals3)) throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur."; - ["posixAccount", "shadowAccount", "inetOrgPerson", "brAccount"].forEach(cst => { + ["posixAccount", "shadowAccount", "brUser"].forEach(cst => { let val3={}; vals3[ldapConfig.user['class']]=cst; - Basics.change("us", uid, "add", vals3).then(res => { - if (!res) { throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur."; } + Basics.change("user", uid, "add", vals3).then(res => { + if (!res) throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur."; }); }); + + // Ajout dans les groupes à la catégorie voulue + for (let cat of categories) { + for (let gid of data[cat]) Tools.add(uid, gid, cat).then(res => { + if (!res) throw "Erreur de l'ajout d'un membre au nouveau groupe."; + }); + } return true; } @@ -221,7 +145,7 @@ export class User { * @memberof LDAP * @summary Fonction qui supprime un utilisateur du LDAP. * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. - * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Group.remMember} et {@link Group.remAdmin} pour gérer les groupes de l'utilisateur sortant. + * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} pour gérer les groupes de l'utilisateur sortant. * @arg {string} uid - uid de la victime * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async @@ -229,34 +153,15 @@ export class User { */ static async delete(uid: string): Promise<boolean> { try { - // Gestion des groupes d'abord + // Gestion des groupes de l'utilisateur d'abord let profil = await User.peek(uid); - profil[ldapConfig.user['groups']].forEach(async function (gid: string) { - // Si l'utilisateur était admin, l'enlever - Group.remAdmin(uid, gid); - // Enlever de la liste des membres - let lm = await Tools.getMembers(gid); - if (lm.includes(uid)) { - // Supprime tous les membres - if (!await Basics.change("gr", gid, "del", ldapConfig.group.members)) { - throw "Erreur lors de la suppression de tous les membres du groupe."; - } - // Les rajoute un par un, sauf pour le supprimé - lm.forEach(id => { - if (id!=uid) { - Group.addMember(id, gid).then(res => { - if (!res) { throw "Erreur lors du ré-ajout d'un autre membre"; } - }); - } - }); - } - }); + for (let cat of categories) profil[ldapConfig.user[cat]].forEach(gid => Tools.remove(uid, gid, cat)); } catch(err) { throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer."; } - // Elimination - if (!Basics.clear("us", uid)) { throw "Erreur lors de la suppression de l'utilisateur."; } + // Elimination pure et simple + if (!Basics.clear("user", uid)) throw "Erreur lors de la suppression de l'utilisateur."; return true; } @@ -271,7 +176,7 @@ export class User { */ static async edit(data : userData) : Promise<boolean> { try { - return Tools.edit("us",data); + return Tools.edit("user",data); } catch(err) { throw "Erreur lors de la modification d'un utilisateur."; diff --git a/src/ldap/internal/basics.ts b/src/ldap/internal/basics.ts index b96736d52a7376356c2580e6cc5b3194b12b0717..089d74b60c164ba72d1360c881b11242972090a6 100644 --- a/src/ldap/internal/basics.ts +++ b/src/ldap/internal/basics.ts @@ -4,6 +4,7 @@ * Toutes les fonctions écrites ici sont asynchrones et renvoient des Promises ce qui nécessite de les appeler avec la synthaxe * un peu particulière `f(args).then(res => ...)` pour exploiter leur résultat. * @author hawkspar + * @memberof LDAP */ import ldap from 'ldapjs'; @@ -17,7 +18,7 @@ var client = ldap.createClient({ url: ldapConfig.server}); // Interface pratique pour que Typescript comprenne ce qu'est un dictionnaire simple interface dic { - [Key: string]: string; + [Key: string]: string | string[]; } //------------------------------------------------------------------------------------------------------------------------ @@ -26,9 +27,9 @@ interface dic { export class Basics { /** + * @memberof LDAP * @class Basics * @classdesc Cette classe est la brique de base du fichier tout entier puisqu'elle contient les functions qui agissent directement sur le LDAP. - * @memberof LDAP * @summary Constructeur vide. */ constructor() {} @@ -80,6 +81,7 @@ export class Basics { /** + * @memberof LDAP * @callback entryHandler * @arg entry {*} - Convoluted ldap.js search result object */ @@ -98,30 +100,37 @@ export class Basics { * @static * @async */ - static search(domain: 'gr'|'us', attributes: string[], id: string, filter: string, handler : (entry: any) => void) : void { - Basics.adminBind(); + static search(domain: 'group'|'user', attributes: string[], id: string, filter: string, handler : (entry: any) => void) : Promise<void> { let dn =""; - if (id != null) { dn+=ldapConfig.key_id+'='+id+','; } - if (domain == "gr") { dn+=ldapConfig.dn_groups; } - else { dn+=ldapConfig.dn_users; } + if (id != null) { + if (domain == "group") dn += ldapConfig.group.gid; + else dn += ldapConfig.user.uid; + dn += '=' + ldapEscape.dn("${txt}", { txt: id }) + ','; + } + dn+=ldapConfig.dn[domain]; + console.log("Searching dn= " + dn + ", filter : " + filter); // Interrogation LDAP selon filter - client.search(ldapEscape.dn("${txt}", { txt: dn}), { // Must be escaped in case of a malignious false id - "scope": "sub", - "filter": ldapEscape.filter("${txt}", { txt: filter}), // Must be escaped in case of a malignious search arg - "attributes": attributes - }, (err, res) => { - // Gestion erreur ; pb car pas simple true / autre en sortie - if (err) { - throw "Erreur lors de la recherche sur le LDAP."; - } else { - // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse - res.on('searchEntry', entry => { handler(entry); }); - // Si la recherche renvoie une erreur, on renvoit - res.on('error', resErr => { throw resErr; }); - // Quand la recherche est finie on se déconnecte - res.on('end', _ => { Basics.unbind(); }); - } + let promise = new Promise<void>(function(resolve, reject) { + client.search(dn, { // Must be escaped in case of a malignious false id + "scope": "sub", + "filter": filter, // Must be escaped in case of a malignious search arg + "attributes": attributes + }, (err, res) => { + // Gestion erreur ; pb car pas simple true / autre en sortie + if (err) { + throw "Erreur lors de la recherche sur le LDAP."; + } else { + // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse + res.on('searchEntry', entry => handler(entry)); + // Si la recherche renvoie une erreur, on renvoit + res.on('error', resErr => { throw resErr; }); + // Quand la recherche est finie on se déconnecte + res.on('end', _ => resolve()); + } + }); }); + + return promise; } /** @@ -137,10 +146,11 @@ export class Basics { * @static * @async */ - static async searchSingle(domain: 'gr'|'us', attribute: string, id: string=null, filter: string="(objectClass=*)") : Promise<string[]> { + static async searchSingle(domain: 'group'|'user', attribute: string, id: string=null, filter: string="(objectClass=*)") : Promise<string[]> { let vals=[]; - Basics.search(domain, [attribute], id, filter, entry => { + await Basics.search(domain, [attribute], id, filter, entry => { // Cas un seul attribut où le résultat est une liste directement + console.log("searchSingle found " + entry.object[(domain == 'group' ? ldapConfig['group']['gid'] : ldapConfig['user']['uid'])]); vals.push(entry.object[attribute]); }); return vals; @@ -160,25 +170,23 @@ export class Basics { * @static * @async */ - static async searchMultiple(domain: 'gr'|'us', attributes: string[], id: string=null, filter: string="(objectClass=*)") : Promise<Array<dic>> { + static async searchMultiple(domain: 'group'|'user', attributes: string[], id: string=null, filter: string="(objectClass=*)") : Promise<Array<dic>> { let vals=[]; - Basics.search(domain, attributes, id, filter, entry => { + await Basics.search(domain, attributes, id, filter, entry => { // Cas plusieurs attributs donc résultat dictionnaire vals.push({}); - attributes.forEach(attribute => { - vals.slice(-1)[0][attribute]=entry.object[attribute]; - }); + console.log("searchMultiple found " + entry.object[(domain == 'group' ? ldapConfig['group']['gid'] : ldapConfig['user']['uid'])]); + attributes.forEach(attribute => vals.slice(-1)[0][attribute]=entry.object[attribute]); }); return vals; } - //TBT /** * @memberof LDAP * @summary Fonction qui permet de modifier un élément sur le LDAP. Gestion intelligente de l'appartenance à un binet. * @desc Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode modify). * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur) - * @arg {string} id - Identifiant unique de la feuille à modifier + * @arg {string} id - Identifiant unique de la feuille à modifier ; passé par ldapEscape dans cette fonction * @arg {"add"|"del"|"replace"} op - Operation à réaliser sur le LDAP. Trois opération sont possibles ; "add", qui rajoute des attributs et qui peut créer des doublons, * "del" qui en supprime, et "replace" qui remplace du contenu par un autre. * @arg {dic} mod - Dictionnaire contenant les attributs à modifier et les nouvelles valeurs des attributs. @@ -187,70 +195,70 @@ export class Basics { * @static * @async */ - static async change(domain: 'gr'|'us', id: string, op: "add"|"del"|"replace", mod: dic) : Promise<boolean> { - Basics.adminBind(); - let dn = ldapConfig.key_id+'='+id+',' - if (domain == "gr") { dn+=ldapConfig.dn_groups } - else { dn+=ldapConfig.dn_users } + static async change(domain: 'group'|'user', id: string, op: "add"|"del"|"replace", mod: dic) : Promise<boolean> { + let dn = ""; + if (domain == 'group') dn += ldapConfig.group.gid; + else dn += ldapConfig.user.uid; + dn+='='+ldapEscape.dn("${txt}", { txt: id })+','+ldapConfig.dn[domain]; // Modification LDAP selon dn fourni en argument (pourrait prendre une liste de Changes) client.modify(ldapEscape.dn("${txt}", {txt: dn}), new ldap.Change({ operation: op, modification: mod, // Gestion erreur - }), err => { - throw "Erreur lors d'une opération de modification sur le LDAP."; - }); - Basics.unbind(); + }), err => { throw "Erreur lors d'une opération de modification sur le LDAP."; }); return true; } - //TBT /** * @memberof LDAP * @summary Fonction qui permet de rajouter un élément sur le LDAP. * @desc Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode add). + * On notera le rôle particulier de vals[uid/gid] qui sert à identifier la feuille à changer ; passé par ldapEscape dans cette fonction. * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur) - * @arg {Object.<string, string>} vals - Dictionnaire contenant les valeurs à créer (contient un champ en ldapConfig.key_id) + * @arg {Object.<string, string>} vals - Dictionnaire contenant les valeurs à créer (contient un champ en ldapConfig) * @arg {Object} vals[key] - Nouvelle valeur pour le champ key * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon. * @static * @async */ - static async add(domain: 'gr'|'us', vals) : Promise<boolean> { - Basics.adminBind(); - let dn = ldapConfig.key_id+"="+vals[ldapConfig.key_id]; - if (domain == "gr") { dn+=ldapConfig.dn_groups; } - else { dn+=ldapConfig.dn_users; } + static async add(domain: 'group'|'user', vals) : Promise<boolean> { + let dn = ""; + if (domain == "group") dn += ldapConfig.group.gid+"="+ldapEscape.dn("${txt}", { txt: vals[ldapConfig.group.gid] }); + else dn += ldapConfig.user.uid+"="+ldapEscape.dn("${txt}", { txt: vals[ldapConfig.user.uid] }); + dn += ldapConfig.dn[domain]; // Ajout LDAP selon la ldapConfiguration en argument - client.add(ldapEscape.dn("${txt}", { txt: dn}), vals, err => { + client.add(ldapEscape.dn("${txt}", { txt: dn }), vals, err => { throw "Erreur lors d'une opération d'ajout sur le LDAP."; }); - Basics.unbind(); return true; } - //TBT /** * @memberof LDAP * @summary Fonction qui permet de supprimer une feuille du LDAP. * @desc Cette fonction traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode del). * Elle est différente de modify avec "del" car elle affecte directement une feuille et pas un attribut. * @arg {'gr'|'us'} domain - Emplacement de la requête (groupe ou utilisateur) - * @arg {string} id - Identifiant unique de la cible + * @arg {string} id - Identifiant unique de la cible, passé par ldapEscape dans cette fonction * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @static * @async */ - static async clear(domain: 'gr'|'us', id: string) : Promise<boolean> { - Basics.adminBind(); - let dn = ldapConfig.key_id+'='+id+',' - if (domain == "gr") { dn+=ldapConfig.dn_groups; } - else { dn+=ldapConfig.dn_users; } + static async clear(domain: 'group'|'user', id: string) : Promise<boolean> { + let dn = ""; + if (domain == "group") dn += ldapConfig.group.gid+"="+ldapEscape.dn("${txt}", { txt: id }); + else dn += ldapConfig.user.uid+"="+ldapEscape.dn("${txt}", { txt: id }); + dn+=ldapConfig.dn[domain]; // Suppression LDAP client.del(ldapEscape.dn("${txt}", {txt: dn}), err => { throw "Erreur lors d'une opération de suppression sur le LDAP."; }); - Basics.unbind(); return true; } -} \ No newline at end of file +} + +// Bind +Basics.unbind(); +Basics.adminBind(); + +console.log("Binding with LDAP client completed successfully, looking good !"); \ No newline at end of file diff --git a/src/ldap/internal/config.ts b/src/ldap/internal/config.ts index 084c46e79ed41c7c29b1ee4020b65e8380d73ee6..3b00495644370c4c05267190703c4a55afb2af8d 100644 --- a/src/ldap/internal/config.ts +++ b/src/ldap/internal/config.ts @@ -5,30 +5,117 @@ /** * @file Importe la configuration du LDAP au sein de l'application, et remplace certaines valeurs en fonction des variables d'environnement. + * @author hawkspar * @memberof LDAP - * @author manifold, hawkspar */ import fs from 'fs'; import path from 'path'; import colors from 'colors'; import dotenv from 'dotenv'; -dotenv.config(); -// Point central ; tous les champs de la BDD sont 'cachés' dans ldap_config.json et pas visibles directement -let path_config = path.resolve(__dirname,'..', '..', '..', 'ldap_config.json'); +// Chargement de l'environnement +let path_env = path.resolve(__dirname, '..', '..', '..', './.env'); +console.log(colors.red("Loading .env config file from "+path_env)); +dotenv.config({ path: path_env }); + +// Point central ; tous les champs de la BDD sont 'cachés' dans config.json et pas visibles directement +let path_config = path.resolve(__dirname, '..', '..', '..', './ldap_config.json'); console.log(colors.cyan("Loading LDAP config file from "+path_config)); export const ldapConfig = JSON.parse(fs.readFileSync(path_config).toString()); -let path_credentials = path.resolve(__dirname,'..', '..', '..', 'ldap_credentials.json'); -console.log(colors.cyan("Loading LDAP credentials from "+path_credentials)); +// Override config server from environment +if (process.env.LDAP_URI != null) ldapConfig.server = process.env.LDAP_URI; +else { + if (process.env.TARGET_ENV == `production`) ldapConfig.server = ldapConfig.server_prod; + else ldapConfig.server = ldapConfig.server_dev; +} + +// Gestion des super-identifiants +let path_credentials = path.resolve(__dirname, '..', '..', '..', 'ldap_credentials.json'); +console.log(colors.green("Loading LDAP credentials from "+path_credentials)); export const credentialsLdapConfig = JSON.parse(fs.readFileSync(path_credentials).toString()); -// Override config server from environment -if (process.env.LDAP_URI != null) { - ldapConfig.server = process.env.LDAP_URI; +// Data formats and useful constants +export const categories = ["admins","speakers","members","followers"]; + +/** + * @memberof LDAP + * @class partUserData + * @desc Interface avec les données visibles au mponde extérieur. + * @var {string} uid - Identifiant utilisateur + * @var {string} givenName - Prénom + * @var {string} lastName - Nom + * @var {string?} gender - Sexe + * @var {string?} photo - Bytestring de la photo de l'utilisateur + * @var {string?} address - Adresse(s) + * @var {string[]} admins - Liste des gid (group id, inclus section sportive, binet, PA...) dont l'utilisateur est admin ; pas forcément sous-liste de members + * @var {string[]} speakers - Liste des gid dont l'utilisateur est porte-parole ; pas forcément sous-liste de members + * @var {string[]} members - Liste des gid dont l'utilisateur est membre + * @var {string[]} followers - Liste des gid dont l'utilisateur est sympathisant + */ +export class partUserData { + uid: string; + givenName: string; + lastName: string; + gender?: 'M'|'F'|'U'; + photo?: string; + address?: string; + admins: string[] = []; + speakers: string[] = []; + members: string[] = []; + followers: string[] = []; } -else { - if (process.env.TARGET_ENV == `production`) { ldapConfig.server = ldapConfig.server_prod; } - else { ldapConfig.server = ldapConfig.server_dev; } + +/** + * @memberof LDAP + * @class userData + * @desc Interface avec toutes les données extractables pour un utilisateur. + * @var {string?} password - Mot de passe (jamais transmis en clair) + * @var {string?} nickname - Surnom + * @var {string?} phone - Numéro(s) de téléphone + * @var {string?} mail - Adresse(s) courriel + * @var {string} birthdate - Date d'anniversaire + * @var {string} nationality - Nationalité d'origine + */ +export class userData extends partUserData { + nickname?: string; + password?: string; + phone?: string; + mail?: string; + birthdate: string; + nationality?: string; } + +/** + * @memberof LDAP + * @class groupData + * @var {string} gid - Identifiant du groupe + * @var {string?} password - Mot de passe du groupe + * @var {string} name - Nom du groupe (souvent son nom mais pas nécessairement) + * @var {string?} logo - Logo du groupe (en bytestring) + * @var {string?} description - Description du groupe (script Markdown) + * @var {string?} site - Site web du groupe (URL) + * @var {string} category - Statut du groupe ; binet, section sportive... (actuellement juste 'binet' ou 'free') + * @var {string[]} parents - Liste des groupes directement parents de celui-ci + * @var {string[]} childs - Liste des groupes directement enfants de celui-ci + * @var {string[]} admins - Liste des admins du groupe + * @var {string[]} speakers - Liste des porte-parole du groupe + * @var {string[]} members - Liste des membres du groupe + * @var {string[]} followers - Liste des sympathisants du groupe + */ +export class groupData { + gid: string; + password?: string; + name: string; + logo?: string; + description?: string; + site?: string; + category: string; + parents: string[] = []; + //childs: string[] = []; + admins: string[] = []; + speakers: string[] = []; + members: string[] = []; + followers: string[] = []; +} \ No newline at end of file diff --git a/src/ldap/internal/tools.ts b/src/ldap/internal/tools.ts index cb7912224c14f5fd13278897ed54052103dc7242..cb5b6b6baf29c65d0d1d4c51ca6e838f27a2a20d 100644 --- a/src/ldap/internal/tools.ts +++ b/src/ldap/internal/tools.ts @@ -1,12 +1,14 @@ /** * @file Ce fichier regroupe les fonctions génériques de recherche et de test utiles, mais trop puissantes pour être exportées directement. * @author hawkspar + * @memberof LDAP */ -import {ldapConfig} from './config'; +// Toutes les entrées utilisateur sont escapées par sécurité +import ldapEscape from 'ldap-escape'; +// Imports internes +import { ldapConfig, userData, groupData } from './config'; import {Basics} from './basics'; -import {userData} from '../export/user'; -import {groupData} from '../export/group'; //------------------------------------------------------------------------------------------------------------------------ // Fonctions intermédiaires TBT @@ -20,11 +22,11 @@ export class Tools { * @summary Constructeur vide. */ constructor() {} - + /** * @memberof LDAP * @summary Fonction qui renvoit toutes les infos relatives à un groupe ou un utilisateur particulier. - * @desc Cette fonction utilise {@link LDAP.search} avec des attributs prédéfinis. + * @desc Cette fonction utilise {@link LDAP.search} avec des attributs prédéfinis. Elle est naïve et n'opère pas de récursion. * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData}) * @arg {string} domain - Domaine de la recherche (utilisateur ou groupe) * @arg {string} id - Identifiant de la feuille cherchée (uid ou gid) @@ -32,28 +34,29 @@ export class Tools { * @static * @async */ - static async peek<T>(domain: 'us'|'gr', id: string) : Promise<T> { - if (domain='gr') { - var dirtyKeys = ldapConfig.group; - } - else { - var dirtyKeys = ldapConfig.user; - } - let cleanData : T; - let dirtyData = await Basics.searchMultiple(domain, dirtyKeys.values(), id)[0]; - // Rename output - for (let uncleanKey in dirtyData) { - for (let cleanKey in cleanData) { - if (uncleanKey=dirtyKeys[cleanKey]) { cleanData[cleanKey] = dirtyData[uncleanKey]; } + static async peek<T>(domain: 'user'|'group', id: string, type: new () => T) : Promise<T> { + // Utrilisation du tableu d'équivalence dans le fichier de configuration + let map = ldapConfig[domain]; + let cleanKeys = Object.keys(map); + let dirtyKeys = cleanKeys.map(key => map[key]); + + // Création de la structure de données renvoyée + let cleanData: T = new type(); + let dirtyData = (await Basics.searchMultiple(domain, dirtyKeys, id))[0]; + // Renommage des clés + for(let cleanKey of cleanKeys) { + let val = dirtyData[map[cleanKey]]; + if (val !== undefined) { + if (Array.isArray(cleanData[cleanKey]) && !Array.isArray(val)) val = [val]; + cleanData[cleanKey] = val; } } return cleanData; } - /** * @memberof LDAP - * @summary Fonction qui retrouve les id des paxs ou groupes validant les critères de recherche. Etape vers vrai TOL (Trombino On Line). + * @summary Fonction qui retrouve les ids des paxs ou groupes validant les critères de recherche. Etape vers vrai TOL (Trombino On Line). * Utiliser {@link peekUser} au cas par cas après pour obtenir les vraies infos. * @desc Cette fonction utilise {@link LDAP.search} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets pour la plupart des champs * mais pas approximatifs et ne gère pas l'auto-complete. MEF Timeout pour des recherches trop vagues. Va crasher si un champ n'est pas dans ldapConfig. @@ -66,28 +69,31 @@ export class Tools { * @static * @async */ - static async search(domain : "us"|"gr", data : userData|groupData) : Promise<string[]> { + static async search(domain: "user"|"group", data: userData|groupData) : Promise<string[]> { let filter=""; // Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfinis dans ldapConfig encore - for (var key in data) { - if ((data[key]!= undefined) && (data[key] != '')) { // Si il y a qque chose à chercher pour ce filtre - if (!Array.isArray(data[key])) { data[key]=[data[key]]; } // Génération systématique d'une liste de valeurs à rechercher + for (var key in ldapConfig[domain]) { + if ((data[key]!= undefined) && (data[key] != '')) { // Si il y a qque chose à chercher pour ce filtre + if (!Array.isArray(data[key])) data[key]=[data[key]]; // Génération systématique d'une liste de valeurs à rechercher // Iteration pour chaque valeur fournie par l'utilisateur data[key].forEach(val => { // Traduction en language LDAP let attribute = ""; - if (domain="us") { attribute = ldapConfig.user[key]; } - else { attribute = ldapConfig.group[key]; } + attribute = ldapConfig[domain][key]; + // Escape user input + val = ldapEscape.filter("${fil}", { fil: val }); // Creation incrémentale du filtre - filter="(&"+filter+ "(|("+attribute+"="+ val+")"+ // On cherche la valeur exacte - "(|("+attribute+"=*"+val+")"+ // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs) - "(|("+attribute+"=*"+val+"*)"+ // La valeur du milieu avec des trucs avant et après - "("+ attribute+"="+ val+"*)))))"; // La valeur du début avec des trucs après + filter="(&"+filter+ "(|("+attribute+"="+ val+")"+ // On cherche la valeur exacte + "("+attribute+"=*"+val+")"+ // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs) + "("+attribute+"=*"+val+"*)"+ // La valeur du milieu avec des trucs avant et après + "("+ attribute+"="+ val+"*)))"; // La valeur du début avec des trucs après }); } } - // Appel avec filtre de l'espace - return Basics.searchSingle(domain, ldapConfig.key_id, null, filter); + // Appel avec filtre de l'espace + if (domain == "group") var att=ldapConfig.group.gid; + else var att=ldapConfig.user.uid; + return Basics.searchSingle(domain, att, null, filter); } /** @@ -100,228 +106,428 @@ export class Tools { * @async * @static */ - static async edit(domain: "us"|"gr", data: userData|groupData) : Promise<boolean> { - if (domain = "us") { - var id=data['uid']; - var dirtyKeys=ldapConfig.user; - } - else { - var id=data['gid']; - var dirtyKeys=ldapConfig.group; - } + static async edit(domain: "user"|"group", data: userData|groupData) : Promise<boolean> { + if (domain == "user") var id=data['uid']; + else var id=data['gid']; + var dirtyKeys=ldapConfig[domain]; // Rename in an LDAP-friendly way let dirtyData = {}; Object.keys(data).forEach(function(key: string) { // Some values edit can't change - if (!['readPerm','writePerm','groups','groupsIsAdmin','members','admins'].includes(key)) { - dirtyData[dirtyKeys.key]=data[key]; - } + if (![ 'admins','speakers','members','followers', + 'directory','classes','id','cleanFullName'].includes(key)) dirtyData[dirtyKeys.key]=data[key]; }); - return Basics.change(domain,id,"replace",dirtyData); + return Basics.change(domain, id, "replace", dirtyData); } - /** - * @callback changeValueCallback - * @param {string} id - Id à modifier - * @param {number} n - Nombre d'itérations - * @return {string} Nouveau id - */ /** * @memberof LDAP - * @summary Cette fonction teste une valeur d'un attribut (typiquement un identifiant) et le fait évoluer jusqu'à ce qu'il soit unique. - * @desc Librement adapté de Stack Overflow. Appelle {@link LDAP.search} pour vérifier - * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut - * dans le dn fourni. - * @param {string} value - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération - * @param {string} attribute - Attribut à tester - * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique - * @param {changeValueCallback} changeValue - Fonction qui prend uniquement en argument l'id courant et - * le nombre d'itérations et qui renvoit la prochaine valeur de l'attribut - * @param {number} n [0] - Nombre d'itérations (à initialiser à 0) - * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié + * @summary Fonction qui retrouve les utilisateurs ou groupes respectivement correspondant à un groupe ou un utilisateur de la même catégorie. + * @desc Cette fonction utilise {@link LDAP.search} et va directement à la feuille de l'utilisateur ou du groupe interrogé. + * Pour autant, elle est moins naïve qu'elle en a l'air. Elle ne gère ni la descente des admins ni la remontée des membres et renvoit une réponse naïve. + * @param {string} id - Identifiant du groupe ou de l'individu à interroger (supposé valide) + * @param {"user"|"group"} domain - Arbre à interroger + * @param {"admins"|"speakers"|"members"|"followers"} category - Catégorie considérée + * @return {Promise(string[])} Liste des id de groupes ou d'utilisateurs de la bonne catégorie associé à l'id * @static * @async */ - static async ensureUnique(value: string, attribute: string, domain: 'gr'|'us', changeValue: (string, number) => string, n: number=0) : Promise<string> { - // Recherche d'autres occurences de l'id + static async get(id : string, domain : "user"|"group", category : string): Promise<string[]> { try { - return Basics.searchSingle(domain, ldapConfig.key_id, null, "("+attribute+"="+value+")").then(function (matches: string[]) { - if (!matches) { throw ""; } - // On renvoit la valeur si elle est bien unique - else if (matches.length=0) { return value; } - // Sinon, on tente de nouveau notre chance avec la valeur suivante - else { return Tools.ensureUnique(changeValue(value, n+1), attribute, domain, changeValue, n+1); } - }); + if (domain == "group") var dirtyId = ldapConfig.group.gid; + else var dirtyId = ldapConfig.user.uid; + dirtyId += "="+ldapEscape.filter("${txt}", { txt: id }) + "," + ldapConfig.dn[domain]; + return await Basics.searchSingle(domain, ldapConfig[domain][category], dirtyId); } catch(err) { - throw "Erreur lors de la recherche d'une valeur pour assurer son unicité."; + throw "Erreur lors d'une recherche générique d'un membre d'une certaine catégorie d'un groupe."; } } - + /** * @memberof LDAP - * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique. - * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation). - * @param {string} givenName - Prénom - * @param {string} lastName - Nom - * @param {string} promotion - Année de promotion - * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié - * @static + * @summary Fonction intermédiaire naïve. + * @desc Cette fonction rajoute un utilisateur à un groupe pour un des deux arbres si cette entrée n'était pas déjà présente de façon à ne pas créer de doublon. + * @arg {string} id1 - uid/gid + * @arg {"group"|"user"} domain1 - Arbre concerné pour l'id1 + * @arg {string} id2 - gid/uid + * @arg {"group"|"user"} domain2 - Arbre concerné pour l'id2 + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async + * @static */ - static async generateUid(givenName: string, lastName: string, promotion: string) : Promise<string> { + static async addIfAbsent(id1: string, domain1: "group"|"user", id2: string, domain2: "group"|"user", category: string): Promise<boolean> { try { - // normalize et lowerCase standardisent le format - return Tools.ensureUnique((givenName+'.'+lastName).toLowerCase().normalize('UFD'), ldapConfig.key_id, "us", (id: string, n: number) => { - if (n=1) { id+='.'+promotion; } // Si prénom.nom existe déjà , on rajoute la promo - else if (n=2) { id+='.'+(n-1).toString(); } // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1 - else if (n>2) { id+=n; } // Ensuite on continue .123, .1234, etc... - return id; - }); - } - catch(err) { - throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid)."; + // Vérifie que l'utilisateur est pas déjà membre pour groupes + let l = await Tools.get(id1, domain1, category); + var catName = ldapConfig[domain1][category]; + if (!l.includes(id2)) { + // Ajoute l'utilisateur dans la catégorie concernée + if (domain2 == "group") var id = ldapConfig[domain2].gid; + else var id = ldapConfig[domain2].uid; + if (!await Basics.change(domain1, id1, "add", {catName: id+"="+id2+","+ldapConfig.dn[domain2]})) throw "Erreur lors de la modification dans l'arbre "+domain2+" pour ajouter une entrée dans la catégorie voulue."; + } } + catch(err) { throw "Erreur pour obtenir une liste d'entrées d'une catégorie d'un "+domain1+"."; } + return true; } /** * @memberof LDAP - * @summary Cette fonction génère un id lisible, puis le fait évoluer jusqu'à ce qu'il soit unique. - * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation). - * @param {string} name - Nom - * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié + * @summary Fonction intermédiaire. + * @desc Cette fonction gère les inclusions de droits. Elle ne rajoute pas un admin pour les admins, mais elle le rajoute en tant que speaker. + * Cette fonction agit uniquement sur l'arbre User. + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async * @static + */ + static async addIncluded(uid: string, gid: string, category: string): Promise<boolean> { + var spk = ldapConfig.group.speakers; + var mem = ldapConfig.group.members; + switch (category) { + case "admins": + // Admin => speaker + if (!await Basics.change("user", uid, "add", { spk: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin parmi les portes-paroles d'un groupe"; + case "speakers": + // Speaker & admin => member + if (!await Basics.change("user", uid, "add", { mem: ldapConfig.group.gid+"="+gid+","+ldapConfig.dn.group })) throw "Erreur à l'ajout d'un nouvel admin ou porte-parole parmi les membres d'un groupe"; + case "members": + case "followers": + break; + } + return true; + } + + /** + * @memberof LDAP + * @summary Fonction intermédiaire de récursion. + * @desc Cette fonction gère les droits par récursion par une classique Depth First Search. + * Cette fonction agit uniquement sur l'arbre User. + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {boolean} direction - direction de la recursion + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async + * @static */ - static async generateReadableId(name: string) : Promise<string> { - try { - // normalize et lowerCase standardisent le format - return Tools.ensureUnique(name.toLowerCase().normalize('UFD'), ldapConfig.key_id, "gr", (id: string, n: number) => { - if (n=1) { id+='.'+n.toString(); } // Si nom existe déjà , on essaie nom.1 - else if (n>1) { id+=n.toString(); } // Ensuite on continue .12, .123, etc... - return id; - }); + static async addDFS(uid: string, gid: string, direction: boolean): Promise<boolean> { + // Cas récursif ascendant (admins) + if (direction) { + var rol = ldapConfig.group.admins; + var tov = ldapConfig.group.childs; } - catch(err) { - throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid)."; + // Cas récursif descendant (membres) + else { + var rol = ldapConfig.group.members; + var tov = ldapConfig.group.parents; + } + // Classic DFS + var to_visit = [gid]; + while (to_visit.length > 0) { + let cur_gid = to_visit.pop(); + Basics.change("user", uid, "add", { rol: ldapConfig.group.gid+"="+cur_gid+","+ldapConfig.dn.group }); + to_visit.concat(await Basics.searchSingle("group", tov, cur_gid)); } + return true; } /** * @memberof LDAP - * @summary Cette fonction teste une valeur dummy (0) pour un identifiant numérique puis le fait évoluer aléatoirement (entre 1 et 100 000) jusqu'à ce qu'il soit unique. - * @param {string} attribut - Intitulé exact de l'id concerné - * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique - * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié + * @summary Fonction essentielle qui permet d'ajouter un utilisateur à une catégorie d'un groupe. + * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} ; {@link Tools.addIfNotPresent} et {@link Tools.manageInclusions}. + * Puis elle gère en interne la récursion et utilise {@link LDAP.change} pour cela. + * @arg {string} uid - Identifiant du futur membre + * @arg {string} gid - Identifiant du groupe + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async * @static + */ + static async add(uid: string, gid: string, category: string): Promise<boolean> { + // Gestion naïve + Tools.addIfAbsent(uid, "user", gid, "group", category); + Tools.addIfAbsent(gid, "group", uid, "user", category); + // Gestion des droits par inclusion + Tools.addIncluded(uid, gid, category); + // Gestion des droits récursive + if (category != "followers") Tools.addDFS(uid, gid, false); + if (category == "admins") Tools.addDFS(uid, gid, true); + return true; + } + + /** + * @memberof LDAP + * @summary Fonction intermédiaire naïve. + * @desc Cette fonction enlève un utilisateur d'un groupe pour un des deux arbres si cette entrée n'était pas déjà absente. + * Elle ne donne pas de précédence particulière à un administrateur strict, ou de protection à une administrateur hérité. + * @arg {string} id1 - uid/gid + * @arg {"group"|"user"} domain1 - Arbre concerné pour l'id1 + * @arg {string} id2 - gid/uid + * @arg {"group"|"user"} domain2 - Arbre concerné pour l'id2 + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async + * @static */ - static async generateId(attribut: string, domain: "gr"|"us") : Promise<string> { + static async remIfPresent(id1: string, domain1: "group"|"user", id2: string, domain2: "group"|"user", category: string): Promise<boolean> { try { - return Tools.ensureUnique("0", attribut, domain, (id,n) => { return Math.floor((Math.random() * 100000) + 1).toString(); }); - } - catch(err) { - throw "Erreur lors de l'assurance de l'unicité d'un unique identifier numérique."; + let l = await Tools.get(id1, domain1, category); + var catName = ldapConfig[domain1][category]; + // Vérifie que l'identifiant est bien présent + if (l.includes(id2)) { + // Supprime tous les identifiants + if (!await Basics.change(domain1, id1, "del", catName)) throw "Erreur lors de la suppression de tous les "+category+" de l'identifiant "+id1+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=id2) { + if (domain2 == "group") var id_n = ldapConfig[domain2].gid; + else var id_n = ldapConfig[domain2].uid; + var catName = ldapConfig[domain1][category]; + Basics.change(domain1, id1, "add", {catName: id_n+'='+id+','+ldapConfig[domain2].dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre "+domain1+" de la catégorie "+category+"."; + }); + } + }); + } } + catch(err) { throw "Erreur pour obtenir une liste d'entrées d'une catégorie d'un "+domain1+"."; } + return true; } /** * @memberof LDAP - * @summary Fonction qui retrouve les groupes dont un individu est membre. - * @desc Cette fonction utilise {@link LDAP.search} va directement à la feuille de l'utilisateur. - * @arg {string} uid - Identifiant de l'individu à interroger (le plus souvent prenom.nom, parfois l'année, supposé valide) - * @return {Promise(string[])} Liste des uid de groupes (noms flat des groupes) où l'id fourni est membre + * @summary Fonction intermédiaire. + * @desc Cette fonction gère les inclusions de droits. Elle ne rajoute pas un admin pour les admins, mais elle le rajoute en tant que speaker. + * Cette fonction agit uniquement sur l'arbre User. + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async * @static + */ + static async remIncluded(uid: string, gid: string, category: string): Promise<boolean> { + var spk = ldapConfig.group.speakers; + var mem = ldapConfig.group.members; + switch (category) { + case "admins": + // Admin => speaker + let l = await Tools.get(gid, "group", spk); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", spk)) throw "Erreur lors de la suppression de tous les portes-paroles de l'identifiant "+gid+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {spk: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie porte-parole."; + }); + } + }); + case "speakers": + // Speaker & admin => member + let lm = await Tools.get(gid, "group", mem); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", mem)) throw "Erreur lors de la suppression de tous les portes-paroles de l'identifiant "+gid+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {mem: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie membre."; + }); + } + }); + case "members": + case "followers": + break; + } + return true; + } + + /** + * @memberof LDAP + * @summary Fonction intermédiaire de récursion. + * @desc Cette fonction gère les droits par récursion par une classique Depth First Search. + * Cette fonction agit uniquement sur l'arbre User. TBM + * @arg {string} uid - uid de l'utilisateur à ajouter + * @arg {string} gid - gid du groupe concerné + * @arg {boolean} direction - direction de la recursion + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon * @async + * @static */ - static async getGroups(uid: string) : Promise<string[]> { - try { - return Basics.searchSingle("us", ldapConfig.user.groups, uid); + static async remDFS(uid: string, gid: string, direction: boolean): Promise<boolean> { + // Cas récursif ascendant (admins) + if (direction) { + var rol = ldapConfig.group.admins; + var tov = ldapConfig.group.childs; } - catch(err) { - throw "Erreur lors de la recherche des groupes d'un individu."; + // Cas récursif descendant (membres) + else { + var rol = ldapConfig.group.members; + var tov = ldapConfig.group.parents; } + // Classic DFS + var to_visit = [gid]; + while (to_visit.length > 0) { + let cur_gid = to_visit.pop(); + let l = await Tools.get(gid, "group", rol); + // Supprime tous les identifiants + if (!await Basics.change("group", gid, "del", rol)) throw "Erreur lors de la suppression de tous les "+rol+" de l'identifiant "+gid+"."; + // Les rajoute un par un, sauf pour le supprimé + l.forEach(id => { + if (id!=uid) { + let tmp = ldapConfig.user.uid; + Basics.change("group", gid, "add", {rol: tmp+'='+uid+','+ldapConfig.user.dn}).then(res => { + if (!res) throw "Erreur lors du ré-ajout d'un autre membre de la catégorie "+rol+"."; + }); + } + }); + to_visit.concat(await Basics.searchSingle("group", tov, cur_gid)); + } + return true; } - + + /** + * @memberof LDAP + * @summary Fonction qui permet de supprimer un membre d'une catégorie existant d'un groupe. + * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}. + * Elle essaie d'assurer les propriétés d'inclusion et de récursion du LDAP. Elle est sans effet pour un statut hérité. + * @arg {string} uid - Identifiant de l'ex-membre + * @arg {string} gid - Identifiant du groupe + * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower) + * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon + * @async + * @static + */ + static async remove(uid: string, gid: string, category : string): Promise<boolean> { + // Invulnérabilité pour les admins hérités + if ((await Tools.get(gid, "group", category)).includes(uid)) { + Tools.remIfPresent(uid, "user", gid, "group", category); + Tools.remIfPresent(gid, "group", uid, "user", category); + // Gestion des droits par inclusion + Tools.remIncluded(uid, gid, category); + // Gestion des droits récursive + if (category != "followers") Tools.remDFS(uid, gid, false); + if (category == "admins") Tools.remDFS(uid, gid, true); + } + return true; + } + + /** + * @memberof LDAP + * @callback changeValueCallback + * @param {string} id - Id à modifier + * @param {number} n - Nombre d'itérations + * @return {string} Nouveau id + */ /** * @memberof LDAP - * @summary Fonction qui retrouve la liste des membres d'un groupe. - * @desc Cette fonction utilise {@link LDAP.search} avec un dictionnaire prédéfini dans ldapConfig.json. - * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule) - * @return {Promise(string[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes) + * @summary Cette fonction teste une valeur d'un attribut (typiquement un identifiant) et le fait évoluer jusqu'à ce qu'il soit unique. + * @desc Librement adapté de Stack Overflow. Appelle {@link LDAP.search} pour vérifier + * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut + * dans le dn fourni. + * @param {string} value - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération + * @param {string} attribute - Attribut à tester + * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique + * @param {changeValueCallback} changeValue - Fonction qui prend uniquement en argument l'id courant et + * le nombre d'itérations et qui renvoit la prochaine valeur de l'attribut + * @param {number} n [0] - Nombre d'itérations (à initialiser à 0) + * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié * @static * @async */ - static async getMembers(gid: string) : Promise<string[]> { + static async ensureUnique(value: string, attribute: string, domain: 'group'|'user', changeValue: (string, number) => string, n: number=0) : Promise<string> { + // Recherche d'autres occurences de l'id try { - return Basics.searchSingle("gr", ldapConfig.group.members, gid); + if (domain == "group") var att=ldapConfig.group.gid; + else var att=ldapConfig.user.uid; + let matches = await Basics.searchSingle(domain, att, null, "("+attribute+"="+ldapEscape.filter("${txt}", { txt: value })+")") + // On renvoit la valeur si elle est bien unique + if (matches.length=0) return value; + // Sinon, on tente de nouveau notre chance avec la valeur suivante + else return Tools.ensureUnique(changeValue(value, n+1), attribute, domain, changeValue, n+1); } catch(err) { - throw "Erreur lors de la recherche des membres d'un groupe."; + throw "Erreur lors de la recherche d'une valeur pour assurer son unicité."; } } - + /** * @memberof LDAP - * @summary Fonction qui retrouve la liste des admins d'un groupe. - * @desc Cette fonction utilise {@link LDAP.search} avec un dictionnaire prédéfini dans ldapConfig.json. - * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule) - * @return {Promise(string[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes) + * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique. + * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation). + * @param {"group"|"user"} domain - Arbre à parcourir + * @param {string} givenName - Prénom + * @param {string} lastName - Nom + * @param {string} promotion - Année de promotion + * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié * @static * @async */ - static async getAdmins(gid: string) : Promise<string[]> { + static async generateUid(domain : "group"|"user", givenName: string, lastName: string, promotion: string) : Promise<string> { try { - return Basics.searchSingle("gr", ldapConfig.group.admins, gid); + if (domain == "group") var att=ldapConfig.group.gid; + else var att=ldapConfig.user.uid; + // normalize et lowerCase standardisent le format + return Tools.ensureUnique((givenName+'.'+lastName).toLowerCase().normalize('UFD'), att, "user", (id: string, n: number) => { + if (n=1) id+='.'+promotion; // Si prénom.nom existe déjà , on rajoute la promo + else if (n=2) id+='.'+(n-1).toString(); // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1 + else if (n>2) id+=n; // Ensuite on continue .123, .1234, etc... + return id; + }); } catch(err) { - throw "Erreur lors de la recherche des admins d'un groupe."; + throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid)."; } } /** * @memberof LDAP - * @summary Cette fonction teste si un utilisateur est membre d'un groupe. - * @desc Utilise les méthodes statiques {@link open.getGroups} et {@link open.getMembers} - * @param {string} uid - Identifiant de l'utilisateur à tester - * @param {string} gid - Identification du groupe à tester - * @returns {Promise(boolean)} True si l'utilisateur est membre + * @summary Cette fonction génère un id lisible, puis le fait évoluer jusqu'à ce qu'il soit unique. + * @desc Limité à un appel à {@link Tools.ensureUnique} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation). + * @param {"group"|"user"} domain - Arbre à parcourir + * @param {string} name - Nom + * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié * @static * @async */ - static async isGroupMember(uid: string, gid: string) : Promise<boolean> { + static async generateReadableId(domain : "group"|"user", name: string) : Promise<string> { try { - let lg = await Tools.getGroups(uid); - let lm = await Tools.getMembers(gid); - if (lg.includes(gid) && lm.includes(uid)) { - return true; - } - else { return false; } + if (domain == "group") var att=ldapConfig.group.gid; + else var att=ldapConfig.user.uid; + // normalize et lowerCase standardisent le format + return Tools.ensureUnique(name.toLowerCase().normalize('UFD'), att, domain, (id: string, n: number) => { + if (n=1) id+='.'+n.toString(); // Si nom existe déjà , on essaie nom.1 + else if (n>1) id+=n.toString(); // Ensuite on continue .12, .123, etc... + return id; + }); } catch(err) { - throw "Erreur lors du test d'appartenance à un groupe."; + throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid)."; } } /** * @memberof LDAP - * @summary Cette fonction teste si un utilisateur est admin d'un groupe. - * @desc Utilise la méthode statique {@link Open.getAdmins} - * @param {string} uid - Identifiant de l'utilisateur à tester - * @param {string} gid - Identification du groupe à tester - * @returns {Promise(boolean)} True si l'utilisateur est administrateur + * @summary Cette fonction teste une valeur dummy (0) pour un identifiant numérique puis le fait évoluer aléatoirement (entre 1 et 100 000) jusqu'à ce qu'il soit unique. + * @param {string} attribute - Intitulé exact de l'id concerné + * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique + * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié * @static * @async */ - static async isGroupAdmin(uid: string, gid: string) : Promise<boolean> { + static async generateId(attribute: string, domain: "group"|"user") : Promise<string> { try { - let lm = await Tools.getMembers(gid); - let la = await Tools.getAdmins(gid); - if (la.includes(uid) && lm.includes(uid)) { return true; } - else { return false; } + return Tools.ensureUnique("0", attribute, domain, (id,n) => Math.floor((Math.random() * 100000) + 1).toString()); } catch(err) { - throw "Erreur lors du test d'appartenance au bureau d'administration un groupe."; + throw "Erreur lors de l'assurance de l'unicité d'un unique identifier numérique."; } } } \ No newline at end of file diff --git a/src/ldap/test.js b/src/ldap/test.js new file mode 100644 index 0000000000000000000000000000000000000000..832f1fee2566b21bbcba60cf0552242b64903ad0 --- /dev/null +++ b/src/ldap/test.js @@ -0,0 +1,6 @@ +var Group = require("../../tsbuild/src/ldap/export/group").Group; +console.log(Group); + +Group.peek("faerix").then(dat => { console.log(dat); }); + +var User = require("../../tsbuild/src/ldap/export/group"); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 89c4276a651bd7d5cd34e7ba347354de31b5a7f4..fe9726b049c06760f49696848eec7396b3f7d135 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,12 @@ { - "comment": "Fichier servant à la configuration des fichiers typescript, ou javascript typé", + "comment": "Fichier servant à la configuration des fichiers typescript, ou javascript typé (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)", "compilerOptions": { "module": "commonjs", "esModuleInterop": true, "target": "es6", "moduleResolution": "node", "sourceMap": true, - "outDir": "tsbuild", + "outDir": "build", "resolveJsonModule": true, "allowSyntheticDefaultImports": true, "lib": ["es7"] @@ -14,10 +14,5 @@ "include": [ "src/**/*", "db/**/*" - ], - "exclude": [ - "node_modules", - "tsbuild", - "build" - ], + ] } \ No newline at end of file