diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6ce79ea..d163ede 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ Checklist -* [] I've added a mention in CHANGELOG.md +- [ ] I've added a mention in CHANGELOG.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 346ecfc..cb2bf32 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,6 @@ test: script: - npm i - npm test - - npm run lint lint: image: node:latest @@ -35,22 +34,17 @@ build: entrypoint: [""] script: - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json - - cat package.json | head -10 - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG - --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA deploy_review: stage: deploy - image: dtzar/helm-kubectl + image: dtzar/helm-kubectl:3.0.2 before_script: - - apk upgrade --update-cache --available && apk add openssl && rm -rf /var/cache/apk/* - - curl -L https://git.io/get_helm.sh | bash - mkdir -p `dirname $KUBECONFIG` - echo ${STAGING_KUBECONFIG} | base64 -d > $KUBECONFIG - - "helm init --upgrade --service-account tiller --force-upgrade --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | kubectl apply -f -" script: - helm upgrade --install @@ -62,7 +56,6 @@ deploy_review: --set imageCredentials.registry="${CI_REGISTRY}" --set env.REDIS="${STAGING_REDIS}" --set env.MONGODB="${STAGING_MONGODB}" - --set env.SATISFACTION_QUESTIONNAIRE_URL="${STAGING_SATISFACTION_QUESTIONNAIRE_URL}" --set env.TWILIO__SID="${STAGING_TWILIO__SID}" --set env.TWILIO__TOKEN="${STAGING_TWILIO__TOKEN}" --set env.TWILIO__MESSAGING_SERVICE_SID="${STAGING_TWILIO__MESSAGING_SERVICE_SID}" @@ -74,11 +67,13 @@ deploy_review: --set env.MAIL__CONTACT_MAIL="${STAGING_MAIL__CONTACT_MAIL}" --set env.REDIRECT_TARGET="${STAGING_REDIRECT_TARGET}" --set env.USER_WEBSITE_URL="${STAGING_USER_WEBSITE_URL}" + --set env.VAPID__PUBLIC_KEY="${STAGING_VAPID__PUBLIC_KEY}" + --set env.VAPID__PRIVATE_KEY="${STAGING_VAPID__PRIVATE_KEY}" --set-string env.WHITELIST_DOMAINS="${STAGING_WHITELIST_DOMAINS}" --set env.VERSION="Version ${CI_COMMIT_REF_NAME} - ${CI_COMMIT_SHA} (job \#${CI_JOB_ID})" - --set ingress.issuer="letsencrypt-staging" + --set monitoring.alert.enabled="false" --wait - e-chauffeur-api-${CI_COMMIT_REF_SLUG} + api-${CI_COMMIT_REF_SLUG} .helm-chart except: refs: @@ -88,13 +83,10 @@ deploy_review: deploy_staging: stage: deploy - image: dtzar/helm-kubectl + image: dtzar/helm-kubectl:3.0.2 before_script: - - apk upgrade --update-cache --available && apk add openssl && rm -rf /var/cache/apk/* - - curl -L https://git.io/get_helm.sh | bash - mkdir -p `dirname $KUBECONFIG` - echo ${STAGING_KUBECONFIG} | base64 -d > $KUBECONFIG - - "helm init --upgrade --service-account tiller --force-upgrade --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | kubectl apply -f -" script: - helm upgrade --install @@ -107,7 +99,6 @@ deploy_staging: --set imageCredentials.registry="${CI_REGISTRY}" --set env.REDIS="${STAGING_REDIS}" --set env.MONGODB="${STAGING_MONGODB}" - --set env.SATISFACTION_QUESTIONNAIRE_URL="${STAGING_SATISFACTION_QUESTIONNAIRE_URL}" --set env.TWILIO__SID="${STAGING_TWILIO__SID}" --set env.TWILIO__TOKEN="${STAGING_TWILIO__TOKEN}" --set env.TWILIO__MESSAGING_SERVICE_SID="${STAGING_TWILIO__MESSAGING_SERVICE_SID}" @@ -119,11 +110,14 @@ deploy_staging: --set env.MAIL__CONTACT_MAIL="${STAGING_MAIL__CONTACT_MAIL}" --set env.REDIRECT_TARGET="${STAGING_REDIRECT_TARGET}" --set env.USER_WEBSITE_URL="${STAGING_USER_WEBSITE_URL}" + --set env.VAPID__PUBLIC_KEY="${STAGING_VAPID__PUBLIC_KEY}" + --set env.VAPID__PRIVATE_KEY="${STAGING_VAPID__PRIVATE_KEY}" --set-string env.WHITELIST_DOMAINS="${STAGING_WHITELIST_DOMAINS}" --set env.VERSION="Version ${CI_COMMIT_REF_NAME} - ${CI_COMMIT_SHA} (job \#${CI_JOB_ID})" --set ingress.issuer="letsencrypt-prod" + --set monitoring.alert.minimumPod=2 --wait - e-chauffeur-api-${CI_COMMIT_REF_SLUG} + api-staging .helm-chart only: refs: @@ -134,13 +128,10 @@ deploy_staging: deploy_prod: stage: deploy - image: dtzar/helm-kubectl + image: dtzar/helm-kubectl:3.0.2 before_script: - - apk upgrade --update-cache --available && apk add openssl && rm -rf /var/cache/apk/* - - curl -L https://git.io/get_helm.sh | bash - mkdir -p `dirname $KUBECONFIG` - echo ${PRODUCTION_KUBECONFIG} | base64 -d > $KUBECONFIG - - helm init --upgrade --service-account tiller --force-upgrade script: - helm upgrade --install @@ -153,7 +144,6 @@ deploy_prod: --set imageCredentials.registry="${CI_REGISTRY}" --set env.REDIS="${PRODUCTION_REDIS}" --set env.MONGODB="${PRODUCTION_MONGODB}" - --set env.SATISFACTION_QUESTIONNAIRE_URL="${PRODUCTION_SATISFACTION_QUESTIONNAIRE_URL}" --set env.TWILIO__SID="${PRODUCTION_TWILIO__SID}" --set env.TWILIO__TOKEN="${PRODUCTION_TWILIO__TOKEN}" --set env.TWILIO__MESSAGING_SERVICE_SID="${PRODUCTION_TWILIO__MESSAGING_SERVICE_SID}" @@ -165,15 +155,15 @@ deploy_prod: --set env.MAIL__CONTACT_MAIL="${PRODUCTION_MAIL__CONTACT_MAIL}" --set env.REDIRECT_TARGET="${PRODUCTION_REDIRECT_TARGET}" --set env.USER_WEBSITE_URL="${PRODUCTION_USER_WEBSITE_URL}" + --set env.VAPID__PUBLIC_KEY="${PRODUCTION_VAPID__PUBLIC_KEY}" + --set env.VAPID__PRIVATE_KEY="${PRODUCTION_VAPID__PRIVATE_KEY}" --set-string env.WHITELIST_DOMAINS="${PRODUCTION_WHITELIST_DOMAINS}" --set env.VERSION="Version ${CI_COMMIT_REF_NAME} - ${CI_COMMIT_SHA} (job \#${CI_JOB_ID})" --set ingress.issuer="letsencrypt-prod" + --set monitoring.alert.minimumPod=3 --wait - e-chauffeur-api-${CI_COMMIT_REF_SLUG} + api .helm-chart only: - refs: - - master - except: refs: - tags diff --git a/.helm-chart/templates/_helpers.tpl b/.helm-chart/templates/_helpers.tpl index 5236f00..4a4eb7c 100644 --- a/.helm-chart/templates/_helpers.tpl +++ b/.helm-chart/templates/_helpers.tpl @@ -12,16 +12,7 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this If release name contains chart name it will be used as a full name. */}} {{- define ".helm-chart.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} {{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} {{- end -}} {{/* diff --git a/.helm-chart/templates/deployment.yaml b/.helm-chart/templates/deployment.yaml index 6064391..0b916e0 100644 --- a/.helm-chart/templates/deployment.yaml +++ b/.helm-chart/templates/deployment.yaml @@ -31,8 +31,6 @@ spec: value: "{{ .Values.env.TOKEN__DURATION }}" - name: TOKEN__SECRET value: "{{ randAlphaNum 35 }}" - - name: SATISFACTION_QUESTIONNAIRE_URL - value: "{{ .Values.env.SATISFACTION_QUESTIONNAIRE_URL }}" - name: TWILIO__SID value: "{{ .Values.env.TWILIO__SID }}" - name: TWILIO__TOKEN @@ -59,6 +57,10 @@ spec: value: "{{ .Values.env.MAIL__TEXT }}" - name: MAIL__SUBJECT value: "{{ .Values.env.MAIL__SUBJECT }}" + - name: VAPID__PUBLIC_KEY + value: "{{ .Values.env.VAPID__PUBLIC_KEY }}" + - name: VAPID__PRIVATE_KEY + value: "{{ .Values.env.VAPID__PRIVATE_KEY }}" - name: REDIRECT_TARGET value: "{{ .Values.env.REDIRECT_TARGET }}" - name: USER_WEBSITE_URL diff --git a/.helm-chart/templates/grafana_dashboard.yaml b/.helm-chart/templates/grafana_dashboard.yaml new file mode 100644 index 0000000..2beeeac --- /dev/null +++ b/.helm-chart/templates/grafana_dashboard.yaml @@ -0,0 +1,583 @@ +{{- $fullName := include ".helm-chart.fullname" . -}} +{{- if .Values.monitoring.dashboard.deploy }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-%s" $fullName "grafana-dashboard" | trunc 63 | trimSuffix "-" }} + labels: +{{ include ".helm-chart.labels" . | indent 4 }} +{{- if $.Values.monitoring.dashboard.sidecarLabel }} + {{ $.Values.monitoring.dashboard.sidecarLabel }}: "1" +{{- end }} +data: + {{$fullName}}-dashboard.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "Prometheus", + "enable": true, + "expr": "time() == BOOL timestamp(rate(kube_pod_container_status_restarts_total{job=\"kube-state-metrics\", namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"}[2m]) > 0)", + "hide": false, + "iconColor": "rgba(215, 44, 44, 1)", + "limit": 100, + "name": "Restarts", + "showIn": 0, + "tags": [ + "restart" + ], + "type": "rows" + } + ] + }, + "editable": false, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 6, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 3, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.5.2", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "ALERTS{deployment=\"{{ $fullName }}\", namespace=\"{{ .Values.namespace }}\"}", + "legendFormat": "{{`{{alertname}} / Severity : {{severity}} / State : {{alertstate}}`}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Alertes triggered", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(phase) (kube_pod_status_phase{namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\"})", + "instant": false, + "legendFormat": "Status: {{`{{phase}}`}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "warning", + "fill": false, + "line": true, + "op": "gt", + "value": {{ .Values.monitoring.alert.minimumPod}}, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Status", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Loki", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 8 + }, + "options": { + "showTime": true, + "sortOrder": "Descending" + }, + "targets": [ + { + "expr": "{job=\"{{ .Values.namespace }}/{{ $fullName }}\"}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Logs", + "type": "logs" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "panels": [], + "title": "Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (container) (irate(container_cpu_usage_seconds_total{job=\"kubelet\", namespace=\"{{ .Values.namespace }}\", image!=\"\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"}[4m]))", + "legendFormat": "Current: {{`{{ container }}`}}", + "refId": "A" + }, + { + "expr": "sum by(container) (kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"{{ .Values.namespace }}\", resource=\"cpu\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "legendFormat": "Requested: {{`{{ container }}`}}", + "refId": "B" + }, + { + "expr": "sum by(container) (kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"{{ .Values.namespace }}\", resource=\"cpu\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "legendFormat": "Limit: {{`{{ container }}`}}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 9 + }, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (container) (container_memory_usage_bytes{job=\"kubelet\", namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "format": "time_series", + "legendFormat": "Current: {{`{{ container }}`}}", + "refId": "A" + }, + { + "expr": "sum by(container) (kube_pod_container_resource_requests{job=\"kube-state-metrics\", namespace=\"{{ .Values.namespace }}\", resource=\"memory\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "legendFormat": "Requested: {{`{{ container }}`}}", + "refId": "B" + }, + { + "expr": "sum by(container) (kube_pod_container_resource_limits{job=\"kube-state-metrics\", namespace=\"{{ .Values.namespace }}\", resource=\"memory\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "hide": false, + "legendFormat": "Limit: {{`{{ container }}`}}", + "refId": "C" + }, + { + "expr": "sum by(container) (container_memory_cache{job=\"kubelet\", namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\", container=\"{{ .Chart.Name }}\"})", + "hide": false, + "legendFormat": "Cache: {{`{{ container }}`}}", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 8, + "x": 16, + "y": 9 + }, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum by (container) (irate(container_network_receive_bytes_total{job=\"kubelet\", namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\"}[4m])))", + "format": "time_series", + "legendFormat": "RX: {{ .Chart.Name }}", + "refId": "A" + }, + { + "expr": "sort_desc(sum by (container) (irate(container_network_transmit_bytes_total{job=\"kubelet\", namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\"}[4m])))", + "format": "time_series", + "legendFormat": "TX: {{ .Chart.Name }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "title": "e-Chauffeur / API ({{ $fullName }})" + } +{{- end }} diff --git a/.helm-chart/templates/prometheus-alerting-rule.yaml b/.helm-chart/templates/prometheus-alerting-rule.yaml new file mode 100644 index 0000000..5d94a2f --- /dev/null +++ b/.helm-chart/templates/prometheus-alerting-rule.yaml @@ -0,0 +1,26 @@ +{{- $fullName := include ".helm-chart.fullname" . -}} +{{- if .Values.monitoring.alert.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" $fullName "alerting-rule" | trunc 63 | trimSuffix "-" }} + labels: +{{ include ".helm-chart.labels" . | indent 4 }} +{{- if .Values.monitoring.alert.labels }} +{{ toYaml .Values.monitoring.alert.labels | indent 4 }} +{{- end }} + +spec: + groups: + - name: {{ $fullName }} + rules: + - alert: NotEnoughPod + expr: "sum(kube_pod_status_phase{namespace=\"{{ .Values.namespace }}\", pod=~\"{{ $fullName }}.+\", phase=\"Running\"}) < {{ .Values.monitoring.alert.minimumPod }}" + for: 1m + labels: + namespace: {{ .Values.namespace }} + deployment: {{ $fullName }} + severity: major + annotations: + summary: Not enough pods running +{{- end }} diff --git a/.helm-chart/values.yaml b/.helm-chart/values.yaml index 5e9684e..4516f5b 100644 --- a/.helm-chart/values.yaml +++ b/.helm-chart/values.yaml @@ -4,6 +4,16 @@ replicaCount: 1 namespace: e-chauffeur +monitoring: + dashboard: + deploy: true + sidecarLabel: grafana-dashboard + alert: + enabled: true + minimumPod: 1 + labels: + app: prometheus-operator + release: prometheus image: repository: registry.gitlab.com/fabnum-minarm/e-chauffeur/api tag: stable @@ -16,7 +26,6 @@ env: REDIS: e-chauffeur-redis MONGODB: e-chauffeur-mongodb TOKEN__DURATION: 3600 - SATISFACTION_QUESTIONNAIRE_URL: null TWILIO__SID: null TWILIO__TOKEN: null TWILIO__MESSAGING_SERVICE_SID: null @@ -30,6 +39,8 @@ env: MAIL__HTML: "
:message
" MAIL__TEXT: ":message" MAIL__SUBJECT: ":gsbdd - :firstname :lastname (:email - :phone)." + VAPID__PUBLIC_KEY: null + VAPID__PRIVATE_KEY: null REDIRECT_TARGET: null USER_WEBSITE_URL: null WHITELIST_DOMAINS: null @@ -47,7 +58,7 @@ service: ingress: enabled: true host: api.localhost - issuer: letsencrypt-staging + issuer: self-signing resources: limits: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2213759..2610a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## Current ### Features ### Fix +## Version 1.4.4 +### Features +* Refactor rights to be able to check inheritance and add rights on model +* Add rating form route and model +* Add push notifications +* User can delete his own account +* Add password constraint +* Add password expiration +* Add rights for admin to update his own campuses +* Add date coherence control +* Add mergeMasks helper +* Add defaultReservationScope to campus model +* Add possibility for ride owner to cancel ride by updating status +* Remove logs from mongodb, using Loki stack right now +* Export dashboard and monitoring on deploy +### Fix +* Rides and ratings routes tests +* Link in registration mail +* Fix fixtures script +* Fix deprecation warnings ## Version 1.4.3 ### Features * Add /campuses/{id}/users route @@ -9,6 +29,9 @@ * Add SMS on refusal * Refactor cars planning and remove dead/old code and lib * Add Redis sync capability +* Add filter management to pois list route +* Add enabled field to Poi model +* Add right to list user own rides and delete it * Standardize email content ### Fix * Fix potential leak of hashed password diff --git a/Dockerfile b/Dockerfile index 5bba5d4..b06407c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12-stretch-slim as base +FROM node:13-stretch-slim as base FROM base as builder RUN apt update && apt upgrade -y @@ -20,10 +20,6 @@ RUN npm install --only=production FROM base -RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ - wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ - chmod +x /bin/grpc_health_probe - RUN mkdir -p /usr/src/app WORKDIR /usr/src/app diff --git a/config.json.dist b/config.json.dist index 48bc25e..bf294dc 100644 --- a/config.json.dist +++ b/config.json.dist @@ -8,7 +8,6 @@ }, "mongodb": "mongodb://localhost/e-chauffeur", "user_website_url": "", - "satisfaction_questionnaire_url": "", "twilio": { "sid": "", "token": "", @@ -32,5 +31,9 @@ "subject": "E-chauffeur : :firstname :lastname (:email)" }, "whitelist_domains": ["def.gouv.fr"], - "default_timezone": "Europe/Paris" + "default_timezone": "Europe/Paris", + "vapid": { + "public_key": "", + "private_key": "" + } } diff --git a/fixtures/index.mjs b/fixtures/index.mjs index 076644d..e24289d 100644 --- a/fixtures/index.mjs +++ b/fixtures/index.mjs @@ -14,18 +14,18 @@ const DIRNAME = typeof __dirname !== 'undefined' ? __dirname : FILENAME.replace(/[\/\\][^\/\\]*?$/, ''); const CURRENT_FILE = path.basename(FILENAME); -const modelsPath = path.join(DIRNAME, '..', 'models'); - (async () => { await import('../services'); + await import('../models/role.mjs'); - await Promise.all((await readDir(modelsPath)).map(async (f) => import(`../models/${f}`))); await Promise.all((await readDir(DIRNAME)) - .filter((f) => f !== CURRENT_FILE && f !== 'index.js') - .map(async (file) => { - const { default: Model } = await import(`../models/${file.replace(/\.json|.js/, '')}.mjs`); - const data = JSON.parse(await readFile(path.resolve(DIRNAME, `./${file}`), 'utf8')); + .filter((f) => f !== CURRENT_FILE) + .map(async (jsonFileName) => { + const filename = path.basename(jsonFileName, '.json'); + const file = `../models/${filename}.mjs`; + const { default: Model } = await import(file); + const data = JSON.parse(await readFile(path.resolve(DIRNAME, `./${jsonFileName}`), 'utf8')); await Promise.all(data.map(async (datum) => { const d = new Model(datum); await d.save(); diff --git a/generate-vapid-key.js b/generate-vapid-key.js new file mode 100644 index 0000000..009736f --- /dev/null +++ b/generate-vapid-key.js @@ -0,0 +1,5 @@ +const webpush = require('web-push'); + +const vapidKeys = webpush.generateVAPIDKeys(); +// eslint-disable-next-line no-console +console.log(JSON.stringify(vapidKeys)); diff --git a/helpers/prefetch-ride.mjs b/helpers/prefetch-ride.mjs index f87120a..8c5d6ef 100644 --- a/helpers/prefetch-ride.mjs +++ b/helpers/prefetch-ride.mjs @@ -1,8 +1,10 @@ -import Ride from '../models/ride'; +import mongoose from 'mongoose'; const PREFETCH_RIDE_KEY = Symbol('prefetched-ride'); export const getPrefetchedRide = (ctx, id) => ctx.state[PREFETCH_RIDE_KEY][id]; export const prefetchRideMiddleware = (getId = (ctx) => ctx.params.id) => async (ctx, next) => { + // Impossible to use MODEL_NAME from ride.mjs, due to cyclic import + const Ride = mongoose.model('Ride'); const rideId = getId(ctx); ctx.state[PREFETCH_RIDE_KEY] = ctx.state[PREFETCH_RIDE_KEY] || {}; ctx.state[PREFETCH_RIDE_KEY][rideId] = await Ride.findById(Ride.castId(rideId)); diff --git a/middlewares/add-filter.mjs b/middlewares/add-filter.mjs index 68b48f2..be03a66 100644 --- a/middlewares/add-filter.mjs +++ b/middlewares/add-filter.mjs @@ -3,6 +3,7 @@ export default (id, mongoPath) => async (ctx, next) => { const filters = ctx.filters || {}; if (queryFilters[id]) { filters[mongoPath] = queryFilters[id]; + delete ctx.query.filters[id]; } ctx.filters = filters; await next(); diff --git a/middlewares/check-rights.mjs b/middlewares/check-rights.mjs index 9c30514..d966e0b 100644 --- a/middlewares/check-rights.mjs +++ b/middlewares/check-rights.mjs @@ -27,7 +27,8 @@ export const injectUserMayMiddleware = async (ctx, next) => { ctx.may = function userMay(right, ...params) { return list.reduce( (acc, row) => acc || ( - roles[row.role].has(right) + row + && [...roles[row.role]].find((r) => r && right && r.id === right.id) && right.rule( row, ctx, diff --git a/middlewares/mask-output.mjs b/middlewares/mask-output.mjs index b2b1a24..5b1c71a 100644 --- a/middlewares/mask-output.mjs +++ b/middlewares/mask-output.mjs @@ -2,14 +2,14 @@ import mask from 'json-mask'; import transform from 'lodash.transform'; import isPlainObject from 'lodash.isplainobject'; -export function cleanObject(e) { +export function cleanObject(e, ctx) { if (!e) { return e; } let item = e; if (e.toCleanObject) { - item = e.toCleanObject({ virtuals: true }); + item = e.toCleanObject({ virtuals: true }, ctx); } else if (e.toObject) { item = e.toObject({ virtuals: true }); } @@ -22,14 +22,14 @@ export function cleanObject(e) { if (['__v'].includes(key)) { return; } - acc[key.replace ? key.replace(/^_/g, '') : key] = cleanObject(val); + acc[key.replace ? key.replace(/^_/g, '') : key] = cleanObject(val, ctx); }); } export default async (ctx, next) => { await next(); if (typeof ctx.body === 'object') { - ctx.body = cleanObject(ctx.body); + ctx.body = cleanObject(ctx.body, ctx); ctx.body = mask(ctx.body, (ctx.query || {}).mask || ','); } }; diff --git a/models/campus.mjs b/models/campus.mjs index 6f20f70..0be2883 100644 --- a/models/campus.mjs +++ b/models/campus.mjs @@ -44,6 +44,10 @@ const CampusSchema = new Schema({ }, default: 30, }, + defaultReservationScope: { + type: Number, + default: 3600, + }, location: { type: { type: String, @@ -89,7 +93,7 @@ const driverFilter = () => ({ CampusSchema.statics.countUsers = async function countUsers(campus, filters = {}) { const User = mongoose.model('User'); const f = { ...campusFilter(campus), ...filters }; - return User.count(f); + return User.countDocuments(f); }; CampusSchema.statics.countDrivers = async function countDrivers(campus) { diff --git a/models/helpers/object-cleaner.mjs b/models/helpers/object-cleaner.mjs new file mode 100644 index 0000000..6a0e8c5 --- /dev/null +++ b/models/helpers/object-cleaner.mjs @@ -0,0 +1,41 @@ +import transform from 'lodash.transform'; +import isPlainObject from 'lodash.isplainobject'; +import set from 'lodash.set'; +import mongoose from 'mongoose'; + +function deepTransform(object, iterator, defaultAcc = {}, keys = []) { + return transform(object, (acc, value, key) => { + const currentKeyPath = [...keys, key]; + if (isPlainObject(value)) { + deepTransform(value, iterator, acc, currentKeyPath); + } else { + iterator(acc, value, currentKeyPath.join('.')); + } + }, defaultAcc); +} + +export default function cleanObjectPlugin(schema, modelName = '') { + /* eslint-disable no-param-reassign */ + schema.methods.toCleanObject = function toCleanObject(config = {}, ctx) { + if (!ctx || !ctx.may) { + return this.toObject ? this.toObject(config) : this; + } + return deepTransform(this.toObject ? this.toObject(config) : this, (acc, value, path) => { + const definition = (schema.paths[path] || {}).options || null; + if (!definition || typeof definition.canEmit === 'undefined' || definition.canEmit === true) { + set(acc, path, value); + } else if ( + Array.isArray(definition.canEmit) + && definition.canEmit.reduce((bool, right) => bool || ctx.may(right, this), false) + ) { + set(acc, path, value); + } + }); + }; + schema.statics.cleanObject = (o, ...params) => { + const Model = mongoose.model(modelName); + + const entity = new Model(o); + return entity.toCleanObject(...params); + }; +} diff --git a/models/notification-device.mjs b/models/notification-device.mjs new file mode 100644 index 0000000..0c53818 --- /dev/null +++ b/models/notification-device.mjs @@ -0,0 +1,63 @@ +import mongoose from 'mongoose'; +import webPush from 'web-push'; +import createdAtPlugin from './helpers/created-at'; +import config from '../services/config'; + +const { Schema } = mongoose; + +const NotificationDeviceSchema = new Schema({ + user: { + _id: { type: mongoose.Types.ObjectId, alias: 'user.id' }, + }, + endpoint: { + type: String, + required: true, + }, + keys: { + p256dh: { + type: String, + required: true, + }, + auth: { + type: String, + required: true, + }, + }, +}); + +NotificationDeviceSchema.plugin(createdAtPlugin); + +NotificationDeviceSchema.index({ 'user._id': 1 }); + +NotificationDeviceSchema.statics.findOneByUser = async function findOneByUser(userId) { + return this.findOne({ 'user._id': userId }); +}; + +NotificationDeviceSchema.statics.findOneAndUpdateByUser = async function findOneAndUpdateByUser(body) { + return this.findOneAndUpdate({ 'user._id': body.user._id }, body, { upsert: true }); +}; + +NotificationDeviceSchema.methods.notify = async function notify(payload = {}) { + const vapidPublicKey = config.get('vapid:public_key'); + const vapidPrivateKey = config.get('vapid:private_key'); + + const options = { + vapidDetails: { + subject: `mailto:${config.get('mail:feedback_mail')}`, + publicKey: vapidPublicKey, + privateKey: vapidPrivateKey, + }, + TTL: 3600, + }; + + return webPush.sendNotification( + { + endpoint: this.endpoint, + keys: this.keys, + }, + JSON.stringify(payload), + options, + ); +}; + +export default mongoose.model('NotificationDevice', NotificationDeviceSchema, 'notification-devices'); diff --git a/models/poi.mjs b/models/poi.mjs index 69c3ce6..b2f3705 100644 --- a/models/poi.mjs +++ b/models/poi.mjs @@ -19,6 +19,10 @@ const PoiSchema = new Schema({ _id: { type: String }, name: String, }, + enabled: { + type: Boolean, + default: true, + }, }); PoiSchema.plugin(createdAtPlugin); @@ -31,6 +35,44 @@ PoiSchema.virtual('campus.id') this.campus._id = id; }); +PoiSchema.statics.formatFilters = function formatFilters(rawFilters, queryParams) { + let queryFilter = { ...rawFilters }; + + if (queryFilter.enabled !== 'true') { + queryFilter = { + ...queryFilter, + enabled: { $ne: false }, + }; + } else { + delete queryFilter.enabled; + } + + if (queryParams && queryParams.search) { + queryFilter.$or = [ + { + _id: new RegExp(queryParams.search, 'i'), + }, + { + label: new RegExp(queryParams.search, 'i'), + }, + ]; + } + + if (queryFilter.length < 1) { + return null; + } + return queryFilter; +}; + +PoiSchema.statics.countDocumentsWithin = function countDocumentsWithin(...params) { + const filter = this.formatFilters(...params); + return this.countDocuments(filter); +}; + +PoiSchema.statics.findWithin = function findWithin(...params) { + const filter = this.formatFilters(...params); + return this.find(filter); +}; PoiSchema.index({ _id: 'text', diff --git a/models/rating.mjs b/models/rating.mjs new file mode 100644 index 0000000..44f805a --- /dev/null +++ b/models/rating.mjs @@ -0,0 +1,47 @@ +import mongoose from 'mongoose'; +import createdAtPlugin from './helpers/created-at'; +import Ride from './ride'; + +const { Schema } = mongoose; + +const RatingSchema = new Schema({ + ride: { + _id: { + type: Schema.Types.ObjectId, + alias: 'ride.id', + required: true, + }, + campus: { + _id: { + type: String, + alias: 'ride.campus.id', + required: true, + }, + }, + }, + uxGrade: { + type: Number, + required: true, + }, + recommandationGrade: { + type: Number, + required: true, + }, + message: String, +}); + +RatingSchema.plugin(createdAtPlugin); + +RatingSchema.pre('validate', async function preValidate(next) { + const ride = await Ride.findById(this.ride._id).lean(); + if (!ride) { + const err = new Error(); + err.status = 404; + err.message = 'Ride does not exist in database'; + throw err; + } + this.ride.campus._id = ride.campus._id; + next(); +}); + +export default mongoose.model('Rating', RatingSchema, 'ratings'); diff --git a/models/ride.mjs b/models/ride.mjs index c374924..3c5dcd6 100644 --- a/models/ride.mjs +++ b/models/ride.mjs @@ -4,12 +4,19 @@ import Luxon from 'luxon'; import nanoid from 'nanoid'; import stateMachinePlugin from '@rentspree/mongoose-state-machine'; import gliphone from 'google-libphonenumber'; -import stateMachine, { DRAFTED } from './status'; +import { CAN_ACCESS_OWN_DATA_ON_RIDE, CAN_ACCESS_PERSONAL_DATA_ON_RIDE } from './rights'; +import stateMachine, { + DRAFTED, + DELIVERED, + CANCELABLE, +} from './status'; import config from '../services/config'; import { sendSMS } from '../services/twilio'; import createdAtPlugin from './helpers/created-at'; +import cleanObjectPlugin from './helpers/object-cleaner'; const DEFAULT_TIMEZONE = config.get('default_timezone'); +const MODEL_NAME = 'Ride'; const { DateTime, Duration } = Luxon; const { PhoneNumberFormat, PhoneNumberUtil } = gliphone; const { Schema, Types } = mongoose; @@ -35,10 +42,22 @@ const RideSchema = new Schema({ }, end: Date, owner: { - _id: { type: mongoose.Types.ObjectId, alias: 'owner.id' }, - firstname: String, - lastname: String, - email: String, + _id: { + type: mongoose.Types.ObjectId, + alias: 'owner.id', + }, + firstname: { + type: String, + canEmit: [CAN_ACCESS_PERSONAL_DATA_ON_RIDE, CAN_ACCESS_OWN_DATA_ON_RIDE], + }, + lastname: { + type: String, + canEmit: [CAN_ACCESS_PERSONAL_DATA_ON_RIDE, CAN_ACCESS_OWN_DATA_ON_RIDE], + }, + email: { + type: String, + canEmit: [CAN_ACCESS_PERSONAL_DATA_ON_RIDE, CAN_ACCESS_OWN_DATA_ON_RIDE], + }, }, departure: { _id: { type: String, required: true, alias: 'departure.id' }, @@ -89,9 +108,15 @@ const RideSchema = new Schema({ type: String, default: process.env.TZ || DEFAULT_TIMEZONE, }, + defaultReservationScope: { + type: Number, + }, }, comments: String, - userComments: String, + userComments: { + type: String, + canEmit: [CAN_ACCESS_PERSONAL_DATA_ON_RIDE, CAN_ACCESS_OWN_DATA_ON_RIDE], + }, passengersCount: { type: Number, default: 1, @@ -104,9 +129,13 @@ const RideSchema = new Schema({ }); RideSchema.plugin(createdAtPlugin); +RideSchema.plugin(cleanObjectPlugin, MODEL_NAME); RideSchema.plugin(stateMachinePlugin.default, { stateMachine }); RideSchema.pre('validate', async function beforeSave() { + if (this.start >= this.end) { + throw new Error('End date should be higher than start date'); + } try { const phoneUtil = PhoneNumberUtil.getInstance(); this.phone = phoneUtil.format(phoneUtil.parse(this.phone, 'FR'), PhoneNumberFormat.E164); @@ -123,7 +152,23 @@ RideSchema.pre('validate', async function beforeSave() { await Promise.all([ (async (Campus) => { const campusId = this.campus._id; - this.campus = await Campus.findById(campusId).lean(); + this.campus = await Campus.findById(campusId); + if (this.campus) { + const currentReservationScope = DateTime.local() + .plus({ seconds: this.campus.defaultReservationScope }) + .toJSDate(); + if (currentReservationScope < this.start) { + const err = new Error(); + err.status = 403; + err.message = 'Ride date should be in campus reservation scope'; + throw err; + } + } else { + const err = new Error(); + err.status = 404; + err.message = 'Campus not found'; + throw err; + } })(mongoose.model('Campus')), (async (User) => { const userId = this.owner._id; @@ -157,9 +202,45 @@ RideSchema.statics.castId = (v) => { } }; -RideSchema.statics.filtersWithin = function filtersWithin(start, end, f = {}) { - const filters = f; - filters.$or = [ +RideSchema.statics.formatFilters = function formatFilters(rawFilters, queryFilter) { + let filter = { + ...rawFilters, + ...queryFilter, + ...this.filtersWithin(queryFilter.start, queryFilter.end), + }; + + delete filter.start; + delete filter.end; + + + if (filter.current) { + let status; + if (filter.current === 'false') { + status = { status: DELIVERED }; + } else { + status = { status: { $in: CANCELABLE } }; + } + + filter = { + ...filter, + ...status, + }; + + delete filter.current; + } + + + if (!filter) { + return null; + } + return filter; +}; + +RideSchema.statics.filtersWithin = function filtersWithin(rawStart, rawEnd) { + const queryFilter = {}; + const start = new Date(rawStart); + const end = new Date(rawEnd); + queryFilter.$or = [ { start: { $lte: start, @@ -197,21 +278,15 @@ RideSchema.statics.filtersWithin = function filtersWithin(start, end, f = {}) { }, }, ]; - return filters; + return queryFilter; }; -RideSchema.statics.findWithin = function findWithin(start, end, filters = {}, ...rest) { - return this.find( - this.filtersWithin(start, end, filters), - ...rest, - ); +RideSchema.statics.findWithin = function findWithin(...params) { + return this.find(this.formatFilters(...params)); }; -RideSchema.statics.countDocumentsWithin = function countDocumentsWithin(start, end, filters = {}, ...rest) { - return this.countDocuments( - this.filtersWithin(start, end, filters), - ...rest, - ); +RideSchema.statics.countDocumentsWithin = function countDocumentsWithin(...params) { + return this.countDocuments(this.formatFilters(...params)); }; RideSchema.methods.findDriverPosition = async function findDriverPosition() { @@ -256,7 +331,7 @@ RideSchema.methods.getRideClientURL = function getRideClientURL() { }; RideSchema.methods.getSatisfactionQuestionnaireURL = function getSatisfactionQuestionnaireURL() { - return `${config.get('satisfaction_questionnaire_url')}`; + return `${config.get('user_website_url')}/rating?rideId=${this.id}`; }; -export default mongoose.model('Ride', RideSchema); +export default mongoose.model(MODEL_NAME, RideSchema); diff --git a/models/rights.mjs b/models/rights.mjs index 8603c64..3eb89c8 100644 --- a/models/rights.mjs +++ b/models/rights.mjs @@ -2,139 +2,150 @@ // of the tree // eslint-disable-next-line import/no-cycle import { - stdRule, campusRule, selfEditingUserRule, roleEditingRule, ownedRideRule, tokenRideRule, + stdRule, campusRule, selfEditingUserRule, roleEditingRule, ownedRideRule, tokenRideRule, onlyLowerRightsRule, } from './rules'; -export const CAN_LOGIN = stdRule(); - -export const CAN_EDIT_CAR_MODEL = stdRule(); -export const CAN_CREATE_CAR_MODEL = stdRule(); -export const CAN_LIST_CAR_MODEL = stdRule(); -export const CAN_GET_CAR_MODEL = stdRule(); -export const CAN_REMOVE_CAR_MODEL = stdRule(); - -export const CAN_EDIT_CAR_EVENT = stdRule(); -export const CAN_CREATE_CAR_EVENT = stdRule(); -export const CAN_LIST_CAR_EVENT = stdRule(); -export const CAN_GET_CAR_EVENT = stdRule(); -export const CAN_REMOVE_CAR_EVENT = stdRule(); - -export const CAN_EDIT_USER = stdRule(); -export const CAN_EDIT_USER_SENSITIVE_DATA = stdRule(); -export const CAN_CREATE_USER = stdRule(); -export const CAN_LIST_USER = stdRule(); -export const CAN_GET_USER = stdRule(); -export const CAN_REMOVE_USER = stdRule(); - -export const CAN_SEND_CREATION_TOKEN = stdRule(); - -export const CAN_EDIT_SELF_USER_PASSWORD = selfEditingUserRule(); -export const CAN_EDIT_SELF_USER_NAME = selfEditingUserRule(); - -export const CAN_EDIT_USER_EVENT = stdRule(); -export const CAN_CREATE_USER_EVENT = stdRule(); -export const CAN_LIST_USER_EVENT = stdRule(); -export const CAN_GET_USER_EVENT = stdRule(); -export const CAN_REMOVE_USER_EVENT = stdRule(); - -export const CAN_EDIT_CAMPUS = stdRule(); -export const CAN_CREATE_CAMPUS = stdRule(); -export const CAN_LIST_CAMPUS = stdRule(); -export const CAN_LIST_CAMPUS_BASIC = stdRule(); -export const CAN_GET_CAMPUS = stdRule(); -export const CAN_GET_CAMPUS_BASIC = stdRule(); -export const CAN_REMOVE_CAMPUS = stdRule(); - -export const CAN_GET_CAMPUS_STATS = campusRule(); - -export const CAN_LIST_CAMPUS_CAR = campusRule(); -export const CAN_LIST_CAMPUS_DRIVER_RIDE = campusRule(); - -export const CAN_LIST_CAMPUS_DRIVER = campusRule(); -export const CAN_GET_CAMPUS_DRIVER = campusRule(); -export const CAN_CREATE_CAMPUS_DRIVER = campusRule(); -export const CAN_EDIT_CAMPUS_DRIVER = campusRule(); -export const CAN_REMOVE_CAMPUS_DRIVER = campusRule(); - -export const CAN_LIST_CAMPUS_USER = campusRule(); -export const CAN_GET_CAMPUS_USER = campusRule(); -export const CAN_CREATE_CAMPUS_USER = campusRule(); -export const CAN_EDIT_CAMPUS_USER = campusRule(); -export const CAN_REMOVE_CAMPUS_USER = campusRule(); - -export const CAN_LIST_PHONE_LOCAL = campusRule(); -export const CAN_GET_PHONE_LOCAL = campusRule(); -export const CAN_CREATE_PHONE_LOCAL = campusRule(); -export const CAN_EDIT_PHONE_LOCAL = campusRule(); -export const CAN_REMOVE_PHONE_LOCAL = campusRule(); - -export const CAN_LIST_PHONE_MODEL = stdRule(); -export const CAN_GET_PHONE_MODEL = stdRule(); -export const CAN_CREATE_PHONE_MODEL = stdRule(); -export const CAN_EDIT_PHONE_MODEL = stdRule(); -export const CAN_REMOVE_PHONE_MODEL = stdRule(); - -export const CAN_EDIT_CATEGORY = stdRule(); -export const CAN_CREATE_CATEGORY = stdRule(); -export const CAN_LIST_CATEGORY = stdRule(); -export const CAN_GET_CATEGORY = stdRule(); -export const CAN_REMOVE_CATEGORY = stdRule(); - -export const CAN_EDIT_CAR = stdRule(); -export const CAN_CREATE_CAR = stdRule(); -export const CAN_LIST_CAR = stdRule(); -export const CAN_GET_CAR = stdRule(); -export const CAN_REMOVE_CAR = stdRule(); - -export const CAN_EDIT_POI = stdRule(); -export const CAN_CREATE_POI = stdRule(); -export const CAN_LIST_POI = stdRule(); -export const CAN_GET_POI = stdRule(); -export const CAN_REMOVE_POI = stdRule(); - -export const CAN_EDIT_POI_LOCAL = campusRule(); -export const CAN_CREATE_POI_LOCAL = campusRule(); -export const CAN_LIST_POI_LOCAL = campusRule(); -export const CAN_GET_POI_LOCAL = campusRule(); -export const CAN_REMOVE_POI_LOCAL = campusRule(); - -export const CAN_LIST_LOG = stdRule(); -export const CAN_GET_POSITION_HISTORY = stdRule(); +export const CAN_LOGIN = stdRule('CAN_LOGIN'); + +export const CAN_EDIT_CAR_MODEL = stdRule('CAN_EDIT_CAR_MODEL'); +export const CAN_CREATE_CAR_MODEL = stdRule('CAN_CREATE_CAR_MODEL'); +export const CAN_LIST_CAR_MODEL = stdRule('CAN_LIST_CAR_MODEL'); +export const CAN_GET_CAR_MODEL = stdRule('CAN_GET_CAR_MODEL'); +export const CAN_REMOVE_CAR_MODEL = stdRule('CAN_REMOVE_CAR_MODEL'); + +export const CAN_EDIT_CAR_EVENT = stdRule('CAN_EDIT_CAR_EVENT'); +export const CAN_CREATE_CAR_EVENT = stdRule('CAN_CREATE_CAR_EVENT'); +export const CAN_LIST_CAR_EVENT = stdRule('CAN_LIST_CAR_EVENT'); +export const CAN_GET_CAR_EVENT = stdRule('CAN_GET_CAR_EVENT'); +export const CAN_REMOVE_CAR_EVENT = stdRule('CAN_REMOVE_CAR_EVENT'); + + +export const CAN_EDIT_USER = stdRule('CAN_EDIT_USER'); +export const CAN_EDIT_USER_SENSITIVE_DATA = stdRule('CAN_EDIT_USER_SENSITIVE_DATA'); +export const CAN_CREATE_USER = stdRule('CAN_CREATE_USER'); +export const CAN_LIST_USER = stdRule('CAN_LIST_USER'); +export const CAN_GET_USER = stdRule('CAN_GET_USER'); +export const CAN_REMOVE_USER = stdRule('CAN_REMOVE_USER'); +export const CAN_REMOVE_SELF_USER = selfEditingUserRule('CAN_REMOVE_SELF_USER'); +export const CAN_EDIT_USER_WITHOUT_UPPER_RIGHTS = onlyLowerRightsRule('CAN_EDIT_USER_WITH_LOWER_RIGHTS'); + +export const CAN_SEND_CREATION_TOKEN = stdRule('CAN_SEND_CREATION_TOKEN'); + +export const CAN_EDIT_SELF_USER_PASSWORD = selfEditingUserRule('CAN_EDIT_SELF_USER_PASSWORD'); +export const CAN_EDIT_SELF_USER_NAME = selfEditingUserRule('CAN_EDIT_SELF_USER_NAME'); + +export const CAN_EDIT_USER_EVENT = stdRule('CAN_EDIT_USER_EVENT'); +export const CAN_CREATE_USER_EVENT = stdRule('CAN_CREATE_USER_EVENT'); +export const CAN_LIST_USER_EVENT = stdRule('CAN_LIST_USER_EVENT'); +export const CAN_GET_USER_EVENT = stdRule('CAN_GET_USER_EVENT'); +export const CAN_REMOVE_USER_EVENT = stdRule('CAN_REMOVE_USER_EVENT'); + +export const CAN_EDIT_CAMPUS = stdRule('CAN_EDIT_CAMPUS'); +export const CAN_EDIT_SELF_CAMPUS = campusRule('CAN_EDIT_SELF_CAMPUS'); +export const CAN_CREATE_CAMPUS = stdRule('CAN_CREATE_CAMPUS'); +export const CAN_LIST_CAMPUS = stdRule('CAN_LIST_CAMPUS'); +export const CAN_LIST_CAMPUS_BASIC = stdRule('CAN_LIST_CAMPUS_BASIC'); +export const CAN_GET_CAMPUS = stdRule('CAN_GET_CAMPUS'); +export const CAN_GET_CAMPUS_BASIC = stdRule('CAN_GET_CAMPUS_BASIC'); +export const CAN_REMOVE_CAMPUS = stdRule('CAN_REMOVE_CAMPUS'); + +export const CAN_GET_CAMPUS_STATS = campusRule('CAN_GET_CAMPUS_STATS'); + +export const CAN_LIST_CAMPUS_CAR = campusRule('CAN_LIST_CAMPUS_CAR'); +export const CAN_LIST_CAMPUS_DRIVER_RIDE = campusRule('CAN_LIST_CAMPUS_DRIVER_RIDE'); + +export const CAN_LIST_CAMPUS_DRIVER = campusRule('CAN_LIST_CAMPUS_DRIVER'); +export const CAN_GET_CAMPUS_DRIVER = campusRule('CAN_GET_CAMPUS_DRIVER'); +export const CAN_CREATE_CAMPUS_DRIVER = campusRule('CAN_CREATE_CAMPUS_DRIVER'); +export const CAN_EDIT_CAMPUS_DRIVER = campusRule('CAN_EDIT_CAMPUS_DRIVER'); +export const CAN_REMOVE_CAMPUS_DRIVER = campusRule('CAN_REMOVE_CAMPUS_DRIVER'); + +export const CAN_LIST_CAMPUS_USER = campusRule('CAN_LIST_CAMPUS_USER'); +export const CAN_GET_CAMPUS_USER = campusRule('CAN_GET_CAMPUS_USER'); +export const CAN_CREATE_CAMPUS_USER = campusRule('CAN_CREATE_CAMPUS_USER'); +export const CAN_EDIT_CAMPUS_USER = campusRule('CAN_EDIT_CAMPUS_USER'); +export const CAN_REMOVE_CAMPUS_USER = campusRule('CAN_REMOVE_CAMPUS_USER'); + +export const CAN_LIST_PHONE_LOCAL = campusRule('CAN_LIST_PHONE_LOCAL'); +export const CAN_GET_PHONE_LOCAL = campusRule('CAN_GET_PHONE_LOCAL'); +export const CAN_CREATE_PHONE_LOCAL = campusRule('CAN_CREATE_PHONE_LOCAL'); +export const CAN_EDIT_PHONE_LOCAL = campusRule('CAN_EDIT_PHONE_LOCAL'); +export const CAN_REMOVE_PHONE_LOCAL = campusRule('CAN_REMOVE_PHONE_LOCAL'); + +export const CAN_LIST_PHONE_MODEL = stdRule('CAN_LIST_PHONE_MODEL'); +export const CAN_GET_PHONE_MODEL = stdRule('CAN_GET_PHONE_MODEL'); +export const CAN_CREATE_PHONE_MODEL = stdRule('CAN_CREATE_PHONE_MODEL'); +export const CAN_EDIT_PHONE_MODEL = stdRule('CAN_EDIT_PHONE_MODEL'); +export const CAN_REMOVE_PHONE_MODEL = stdRule('CAN_REMOVE_PHONE_MODEL'); + +export const CAN_EDIT_CATEGORY = stdRule('CAN_EDIT_CATEGORY'); +export const CAN_CREATE_CATEGORY = stdRule('CAN_CREATE_CATEGORY'); +export const CAN_LIST_CATEGORY = stdRule('CAN_LIST_CATEGORY'); +export const CAN_GET_CATEGORY = stdRule('CAN_GET_CATEGORY'); +export const CAN_REMOVE_CATEGORY = stdRule('CAN_REMOVE_CATEGORY'); + +export const CAN_EDIT_CAR = stdRule('CAN_EDIT_CAR'); +export const CAN_CREATE_CAR = stdRule('CAN_CREATE_CAR'); +export const CAN_LIST_CAR = stdRule('CAN_LIST_CAR'); +export const CAN_GET_CAR = stdRule('CAN_GET_CAR'); +export const CAN_REMOVE_CAR = stdRule('CAN_REMOVE_CAR'); + +export const CAN_EDIT_POI = stdRule('CAN_EDIT_POI'); +export const CAN_CREATE_POI = stdRule('CAN_CREATE_POI'); +export const CAN_LIST_POI = stdRule('CAN_LIST_POI'); +export const CAN_GET_POI = stdRule('CAN_GET_POI'); +export const CAN_REMOVE_POI = stdRule('CAN_REMOVE_POI'); + +export const CAN_EDIT_POI_LOCAL = campusRule('CAN_EDIT_POI_LOCAL'); +export const CAN_CREATE_POI_LOCAL = campusRule('CAN_CREATE_POI_LOCAL'); +export const CAN_LIST_POI_LOCAL = campusRule('CAN_LIST_POI_LOCAL'); +export const CAN_GET_POI_LOCAL = campusRule('CAN_GET_POI_LOCAL'); +export const CAN_REMOVE_POI_LOCAL = campusRule('CAN_REMOVE_POI_LOCAL'); + +export const CAN_GET_POSITION_HISTORY = stdRule('CAN_GET_POSITION_HISTORY'); // @todo : scope there by campus -export const CAN_EDIT_RIDE = stdRule(); -export const CAN_EDIT_RIDE_STATUS = stdRule(); -export const CAN_EDIT_OWNED_RIDE_STATUS = ownedRideRule(); -export const CAN_CREATE_RIDE = stdRule(); -export const CAN_REQUEST_RIDE = stdRule(); -export const CAN_GET_OWNED_RIDE = ownedRideRule(); -export const CAN_GET_RIDE_WITH_TOKEN = tokenRideRule(); -export const CAN_EDIT_OWNED_RIDE = ownedRideRule(); -export const CAN_LIST_RIDE = stdRule(); -export const CAN_GET_RIDE = stdRule(); -export const CAN_GET_RIDE_POSITION = stdRule(); - -export const CAN_SEND_FEEDBACK = stdRule(); - -export const CAN_REVOKE_ROLE_SUPERADMIN = stdRule(); -export const CAN_ADD_ROLE_SUPERADMIN = stdRule(); - -export const CAN_REVOKE_ROLE_ADMIN = stdRule(); -export const CAN_ADD_ROLE_ADMIN = stdRule(); - -export const CAN_REVOKE_ROLE_LOCAL_REGULATOR = roleEditingRule(); -export const CAN_ADD_ROLE_LOCAL_REGULATOR = roleEditingRule(); -export const CAN_REVOKE_ROLE_REGULATOR = stdRule(); -export const CAN_ADD_ROLE_REGULATOR = stdRule(); - -export const CAN_REVOKE_ROLE_LOCAL_DRIVER = roleEditingRule(); -export const CAN_ADD_ROLE_LOCAL_DRIVER = roleEditingRule(); -export const CAN_REVOKE_ROLE_DRIVER = stdRule(); -export const CAN_ADD_ROLE_DRIVER = stdRule(); - -export const CAN_LIST_ALL_CAMPUSES = stdRule(); - -export const CAN_EDIT_TIME_SLOT = campusRule(); -export const CAN_CREATE_TIME_SLOT = campusRule(); -export const CAN_LIST_TIME_SLOT = campusRule(); -export const CAN_REMOVE_TIME_SLOT = campusRule(); +export const CAN_EDIT_RIDE = stdRule('CAN_EDIT_RIDE'); +export const CAN_EDIT_RIDE_STATUS = stdRule('CAN_EDIT_RIDE_STATUS'); +export const CAN_EDIT_OWNED_RIDE_STATUS = ownedRideRule('CAN_EDIT_OWNED_RIDE_STATUS'); +export const CAN_CREATE_RIDE = stdRule('CAN_CREATE_RIDE'); +export const CAN_REQUEST_RIDE = stdRule('CAN_REQUEST_RIDE'); +export const CAN_GET_OWNED_RIDE = ownedRideRule('CAN_GET_OWNED_RIDE'); +export const CAN_GET_RIDE_WITH_TOKEN = tokenRideRule('CAN_GET_RIDE_WITH_TOKEN'); +export const CAN_EDIT_OWNED_RIDE = ownedRideRule('CAN_EDIT_OWNED_RIDE'); +export const CAN_LIST_RIDE = stdRule('CAN_LIST_RIDE'); +export const CAN_GET_RIDE = stdRule('CAN_GET_RIDE'); +export const CAN_GET_RIDE_POSITION = stdRule('CAN_GET_RIDE_POSITION'); +export const CAN_LIST_SELF_RIDE = selfEditingUserRule('CAN_LIST_SELF_RIDE'); +export const CAN_DELETE_SELF_RIDE = selfEditingUserRule('CAN_DELETE_SELF_RIDE'); + +export const CAN_SEND_FEEDBACK = stdRule('CAN_SEND_FEEDBACK'); + +export const CAN_REVOKE_ROLE_SUPERADMIN = stdRule('CAN_REVOKE_ROLE_SUPERADMIN'); +export const CAN_ADD_ROLE_SUPERADMIN = stdRule('CAN_ADD_ROLE_SUPERADMIN'); + +export const CAN_REVOKE_ROLE_ADMIN = stdRule('CAN_REVOKE_ROLE_ADMIN'); +export const CAN_ADD_ROLE_ADMIN = stdRule('CAN_ADD_ROLE_ADMIN'); + +export const CAN_REVOKE_ROLE_LOCAL_REGULATOR = roleEditingRule('CAN_REVOKE_ROLE_LOCAL_REGULATOR'); +export const CAN_ADD_ROLE_LOCAL_REGULATOR = roleEditingRule('CAN_ADD_ROLE_LOCAL_REGULATOR'); +export const CAN_REVOKE_ROLE_REGULATOR = stdRule('CAN_REVOKE_ROLE_REGULATOR'); +export const CAN_ADD_ROLE_REGULATOR = stdRule('CAN_ADD_ROLE_REGULATOR'); + +export const CAN_REVOKE_ROLE_LOCAL_DRIVER = roleEditingRule('CAN_REVOKE_ROLE_LOCAL_DRIVER'); +export const CAN_ADD_ROLE_LOCAL_DRIVER = roleEditingRule('CAN_ADD_ROLE_LOCAL_DRIVER'); +export const CAN_REVOKE_ROLE_DRIVER = stdRule('CAN_REVOKE_ROLE_DRIVER'); +export const CAN_ADD_ROLE_DRIVER = stdRule('CAN_ADD_ROLE_DRIVER'); + +export const CAN_LIST_ALL_CAMPUSES = stdRule('CAN_LIST_ALL_CAMPUSES'); + +export const CAN_EDIT_TIME_SLOT = campusRule('CAN_EDIT_TIME_SLOT'); +export const CAN_CREATE_TIME_SLOT = campusRule('CAN_CREATE_TIME_SLOT'); +export const CAN_LIST_TIME_SLOT = campusRule('CAN_LIST_TIME_SLOT'); +export const CAN_REMOVE_TIME_SLOT = campusRule('CAN_REMOVE_TIME_SLOT'); + +export const CAN_ACCESS_OWN_DATA_ON_RIDE = ownedRideRule('CAN_ACCESS_OWN_DATA_ON_RIDE'); +export const CAN_ACCESS_PERSONAL_DATA_ON_RIDE = campusRule('CAN_ACCESS_PERSONAL_DATA_ON_RIDE'); + +export const CAN_CREATE_RATING = stdRule('CAN_CREATE_RATING'); +export const CAN_LIST_RATING = stdRule('CAN_LIST_RATING'); diff --git a/models/role.mjs b/models/role.mjs index f587fd0..ccb2184 100644 --- a/models/role.mjs +++ b/models/role.mjs @@ -1,22 +1,38 @@ +// eslint-disable-next-line import/no-cycle import * as rights from './rights'; class RoleList extends Set { - constructor(...items) { - super(items); + constructor(name, ...items) { + super(items.reduce((acc, row) => acc.concat(row instanceof Set ? Array.from(row) : row), [])); + this.name = name; + this.inheritance = items.filter((i) => i instanceof Set); + } + + get inheritanceList() { + return this.inheritance.concat(this.inheritance.reduce((acc, list) => acc.concat(list.inheritanceList), [])); + } + + hasRoleInInheritance(role) { + return this.inheritanceList.reduce((bool, row) => bool || row.name === role, false); } } +const roles = {}; export const ROLE_ANONYMOUS = new RoleList( + 'ROLE_ANONYMOUS', rights.CAN_LOGIN, rights.CAN_GET_RIDE_WITH_TOKEN, rights.CAN_GET_RIDE_POSITION, rights.CAN_LIST_CAMPUS_BASIC, rights.CAN_SEND_CREATION_TOKEN, + rights.CAN_CREATE_RATING, ); +roles.ROLE_ANONYMOUS = ROLE_ANONYMOUS; export const ROLE_USER = new RoleList( - ...ROLE_ANONYMOUS, - + 'ROLE_USER', + ROLE_ANONYMOUS, + rights.CAN_ACCESS_OWN_DATA_ON_RIDE, rights.CAN_EDIT_SELF_USER_NAME, rights.CAN_EDIT_SELF_USER_PASSWORD, rights.CAN_GET_CAMPUS_BASIC, @@ -25,15 +41,22 @@ export const ROLE_USER = new RoleList( rights.CAN_GET_OWNED_RIDE, rights.CAN_EDIT_OWNED_RIDE, rights.CAN_EDIT_OWNED_RIDE_STATUS, + rights.CAN_LIST_SELF_RIDE, + rights.CAN_DELETE_SELF_RIDE, rights.CAN_GET_POI_LOCAL, rights.CAN_LIST_POI_LOCAL, rights.CAN_GET_POI, rights.CAN_LIST_POI, + + rights.CAN_REMOVE_SELF_USER, + rights.CAN_EDIT_USER_WITHOUT_UPPER_RIGHTS, ); +roles.ROLE_USER = ROLE_USER; export const ROLE_DRIVER = new RoleList( - ...ROLE_USER, + 'ROLE_DRIVER', + ROLE_USER, rights.CAN_GET_CAMPUS, rights.CAN_LIST_CAMPUS, @@ -48,10 +71,12 @@ export const ROLE_DRIVER = new RoleList( rights.CAN_EDIT_RIDE_STATUS, rights.CAN_LIST_CAMPUS_DRIVER_RIDE, ); +roles.ROLE_DRIVER = ROLE_DRIVER; export const ROLE_REGULATOR = new RoleList( - ...ROLE_DRIVER, - + 'ROLE_REGULATOR', + ROLE_DRIVER, + rights.CAN_ACCESS_PERSONNAL_DATA_ON_RIDE, rights.CAN_LIST_USER, rights.CAN_GET_USER, rights.CAN_EDIT_USER, @@ -103,10 +128,11 @@ export const ROLE_REGULATOR = new RoleList( rights.CAN_EDIT_TIME_SLOT, rights.CAN_REMOVE_TIME_SLOT, ); +roles.ROLE_REGULATOR = ROLE_REGULATOR; export const ROLE_ADMIN = new RoleList( - ...ROLE_REGULATOR, - + 'ROLE_ADMIN', + ROLE_REGULATOR, rights.CAN_EDIT_POI_LOCAL, rights.CAN_CREATE_POI_LOCAL, rights.CAN_REMOVE_POI_LOCAL, @@ -115,6 +141,7 @@ export const ROLE_ADMIN = new RoleList( rights.CAN_EDIT_PHONE_LOCAL, rights.CAN_REMOVE_PHONE_LOCAL, + rights.CAN_EDIT_SELF_CAMPUS, rights.CAN_LIST_CAMPUS_USER, rights.CAN_GET_CAMPUS_USER, rights.CAN_CREATE_CAMPUS_USER, @@ -126,10 +153,11 @@ export const ROLE_ADMIN = new RoleList( rights.CAN_EDIT_USER_SENSITIVE_DATA, ); +roles.ROLE_ADMIN = ROLE_ADMIN; export const ROLE_SUPERADMIN = new RoleList( - ...ROLE_ADMIN, - + 'ROLE_SUPERADMIN', + ROLE_ADMIN, rights.CAN_EDIT_CAR_MODEL, rights.CAN_CREATE_CAR_MODEL, rights.CAN_REMOVE_CAR_MODEL, @@ -168,4 +196,11 @@ export const ROLE_SUPERADMIN = new RoleList( rights.CAN_ADD_ROLE_DRIVER, rights.CAN_LIST_ALL_CAMPUSES, + + rights.CAN_LIST_RATING, ); +roles.ROLE_SUPERADMIN = ROLE_SUPERADMIN; + +export const keys = Object.keys(roles) + .map((r) => ({ [r]: roles[r].name })) + .reduce((acc, r) => Object.assign(acc, r), {}); diff --git a/models/rules.mjs b/models/rules.mjs index 99796d0..9e1442b 100644 --- a/models/rules.mjs +++ b/models/rules.mjs @@ -1,8 +1,11 @@ import lGet from 'lodash.get'; +import lXor from 'lodash.xor'; import nanoid from 'nanoid'; // It's not really a cycle import, we're not importing the same part of the tree // eslint-disable-next-line import/no-cycle import { CAN_LIST_ALL_CAMPUSES } from './rights'; +// eslint-disable-next-line import/no-cycle +import * as roles from './role'; import { getPrefetchedRide } from '../helpers/prefetch-ride'; const ruleGenerator = (rule = () => true) => (id) => ({ id: Symbol(id || nanoid()), rule }); @@ -26,7 +29,10 @@ export const campusRule = ruleGenerator(({ campuses = [] }, ctx) => { * @return {symbol} */ export const selfEditingUserRule = ruleGenerator((_, ctx) => { - const userParam = lGet(ctx, 'params.user_id', null); + let userParam = lGet(ctx, 'params.user_id', null); + if (!userParam) { + userParam = lGet(ctx.request, 'query.filters.userId', null); + } const loggedUser = lGet(ctx, 'state.user.id', null); return userParam && loggedUser && userParam === loggedUser; }); @@ -41,8 +47,19 @@ export const tokenRideRule = ruleGenerator((_, ctx) => { const ride = getPrefetchedRide(ctx, ctx.params.id); return ride.token === ctx.query.token; }); -export const ownedRideRule = ruleGenerator((_, ctx) => { + +export const ownedRideRule = ruleGenerator((_, ctx, entity) => { const { user } = ctx.state; - const ride = getPrefetchedRide(ctx, ctx.params.id); + const ride = entity || getPrefetchedRide(ctx, ctx.params.id); return ride.owner && ride.owner.id && ride.owner.id.toString() === user.id; }); + +export const onlyLowerRightsRule = ruleGenerator((_, ctx, userToEdit) => { + const { user } = ctx.state; + return user.roles.reduce( + (acc, { campuses = [], role }) => acc && userToEdit.roles.map( + (u) => lXor(campuses, u.campuses).length <= 0 && roles[role].hasRoleInInheritance(u.role), + ), + true, + ); +}); diff --git a/models/status.mjs b/models/status.mjs index e2f2cc8..c0ac59b 100644 --- a/models/status.mjs +++ b/models/status.mjs @@ -45,7 +45,7 @@ export const CANCEL_REQUESTED_CUSTOMER = 'cancel_requested_by_customer'; export const CANCEL_CUSTOMER_OVERLOAD = 'cancel_customer_overload'; export const CANCEL_CUSTOMER_MISSING = 'cancel_customer_missing'; -export const CANCELABLE = [VALIDATED, ACCEPTED, STARTED, WAITING, IN_PROGRESS]; +export const CANCELABLE = [CREATED, VALIDATED, ACCEPTED, STARTED, WAITING, IN_PROGRESS]; export default { init: DRAFTED, diff --git a/models/user.mjs b/models/user.mjs index 9270b61..20a595a 100644 --- a/models/user.mjs +++ b/models/user.mjs @@ -1,5 +1,4 @@ import mongoose from 'mongoose'; -import omit from 'lodash.omit'; import orderBy from 'lodash.orderby'; import chunk from 'lodash.chunk'; import differenceWith from 'lodash.differencewith'; @@ -9,10 +8,12 @@ import jwt from 'jsonwebtoken'; import validator from 'validator'; import nanoid from 'nanoid/generate'; import gliphone from 'google-libphonenumber'; +import Luxon from 'luxon'; import config from '../services/config'; import { sendPasswordResetMail, sendRegistrationMail, sendVerificationMail } from '../services/mail'; import { sendVerificationSMS } from '../services/twilio'; import createdAtPlugin from './helpers/created-at'; +import cleanObjectPlugin from './helpers/object-cleaner'; import { CAN_ADD_ROLE_ADMIN, CAN_ADD_ROLE_DRIVER, @@ -26,6 +27,7 @@ import { } from './rights'; import * as rolesImport from './role'; +const { DateTime } = Luxon; const { normalizeEmail } = validator; const { PhoneNumberFormat, PhoneNumberUtil } = gliphone; const { @@ -36,9 +38,12 @@ const { .reduce((acc, r) => Object.assign(acc, r), {}), }; +const MODEL_NAME = 'User'; const SALT_WORK_FACTOR = 10; const RESET_TOKEN_EXPIRATION_SECONDS = 60 * 60 * 24; const RESET_TOKEN_ALPHABET = '123456789abcdefghjkmnpqrstuvwxyz'; +const PASSWORD_TEST = /.{8,}/; +export class ExpiredPasswordError extends Error {} const phoneUtil = PhoneNumberUtil.getInstance(); const { Schema } = mongoose; @@ -63,7 +68,11 @@ const UserSchema = new Schema({ }, firstname: String, lastname: String, - password: String, + password: { + type: String, + canEmit: false, + }, + passwordExpiration: Date, phone: { original: String, canonical: String, @@ -106,12 +115,14 @@ const UserSchema = new Schema({ }); UserSchema.plugin(createdAtPlugin); +UserSchema.plugin(cleanObjectPlugin, MODEL_NAME); UserSchema.pre('validate', function preValidate() { if (this.isModified('email')) { this.email = normalizeEmail(this.email); } }); + UserSchema.pre('save', function preSave(next) { if (this.isModified('phone.original')) { if (this.phone.original && this.phone.original.length) { @@ -122,17 +133,26 @@ UserSchema.pre('save', function preSave(next) { this.phone.confirmed = false; } - if (!this.isModified('password') || !this.password) { - next(); - } if (this.isModified('email')) { this.email_confirmed = false; } this.tokens = this.activeTokens; + + if (!this.isModified('password') || !this.password) { + next(); + } + + if (!PASSWORD_TEST.test(this.password)) { + throw new Error('Password should match security criteria'); + } + bcrypt .hash(this.password, SALT_WORK_FACTOR) .then((password) => { this.password = password; + if (!this.isModified('passwordExpiration')) { + this.passwordExpiration = DateTime.local().plus({ months: 4 }).toJSDate(); + } next(); }) .catch((err) => next(err)); @@ -159,11 +179,10 @@ UserSchema.virtual('activeTokens') return firsts; }); -UserSchema.methods.toCleanObject = function toCleanObject(...params) { - return omit(this.toObject ? this.toObject(...params) : this, ['password']); -}; - UserSchema.methods.emitJWT = function emitJWT(isRenewable = true) { + if (this.passwordExpiration && this.passwordExpiration < new Date()) { + throw new ExpiredPasswordError('Password expired'); + } const u = this.toCleanObject({ versionKey: false }); u.id = u._id; u.isRenewable = isRenewable; @@ -244,13 +263,6 @@ UserSchema.methods.confirmEmail = async function confirmEmail(token) { return true; }; -UserSchema.statics.cleanObject = (o, ...params) => { - const User = mongoose.model('User'); - - const user = new User(o); - return user.toCleanObject(...params); -}; - UserSchema.methods.getCampusesAccessibles = async function getCampusesAccessibles() { const campuses = this.roles .map((r) => r.campuses) @@ -321,7 +333,7 @@ UserSchema.statics.findInIds = async function findInIds(ids = []) { UserSchema.methods.getResetTokenUrl = function getResetTokenUrl(token) { const email = encodeURIComponent(this.email); - return `${config.get('user_website_url')}/edit-account?email=${email}&token=${token}`; + return `${config.get('user_website_url')}/my-account/edit-account?email=${email}&token=${token}`; }; UserSchema.methods.sendRegistrationTokenMail = async function sendRegistrationTokenMail(token) { @@ -360,4 +372,4 @@ UserSchema.methods.generateResetToken = async function generateResetToken({ emai return token; }; -export default mongoose.model('User', UserSchema); +export default mongoose.model(MODEL_NAME, UserSchema); diff --git a/package-lock.json b/package-lock.json index f9592fd..374024d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,7 @@ { "name": "e-chauffeur_api", - "version": "1.4.2", - "lockfileVersion": 1, "requires": true, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { "version": "7.5.5", @@ -14,12 +13,12 @@ } }, "@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", "dev": true, "requires": { - "@babel/types": "^7.6.3", + "@babel/types": "^7.7.4", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -34,32 +33,32 @@ } }, "@babel/helper-function-name": { - "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==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/helper-get-function-arity": { - "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==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.4" } }, "@babel/highlight": { @@ -74,43 +73,43 @@ } }, "@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", "dev": true }, "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" } }, "@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -151,9 +150,9 @@ } }, "@types/connect": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", - "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", "requires": { "@types/node": "*" } @@ -169,9 +168,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.16.11", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.11.tgz", - "integrity": "sha512-K8d2M5t3tBQimkyaYTXxtHYyoJPUEhy2/omVRnTAKw5FEdT+Ft6lTaTOpoJdHeG+mIwQXXtqiTcYZ6IR8LTzjQ==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.1.tgz", + "integrity": "sha512-9e7jj549ZI+RxY21Cl0t8uBnWyb22HzILupyHZjYEVK//5TT/1bZodU+yUbLnPdoYViBBnNWbxp4zYjGV0zUGw==", "requires": { "@types/node": "*", "@types/range-parser": "*" @@ -183,9 +182,9 @@ "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" }, "@types/node": { - "version": "12.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz", - "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==" + "version": "13.1.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz", + "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==" }, "@types/range-parser": { "version": "1.2.3", @@ -216,9 +215,9 @@ } }, "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { @@ -232,6 +231,14 @@ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, "aggregate-error": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", @@ -256,6 +263,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, "requires": { "string-width": "^2.0.0" }, @@ -263,17 +271,20 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -283,6 +294,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -296,12 +308,12 @@ "dev": true }, "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", "dev": true, "requires": { - "type-fest": "^0.5.2" + "type-fest": "^0.8.1" } }, "ansi-regex": { @@ -313,6 +325,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -323,22 +336,13 @@ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "aproba": { @@ -364,35 +368,26 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" } }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } }, "arraybuffer.slice": { "version": "0.0.7", @@ -412,6 +407,17 @@ "safer-buffer": "~2.1.0" } }, + "asn1.js": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.3.0.tgz", + "integrity": "sha512-WHnQJFcOrIWT1RLOkFFBQkFVvyt9BPOOrH+Dp152Zk4R993rSzXUGPmkybIcUFhHE2d/iHH+nCaOWVCDbO8fgA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -423,11 +429,6 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -439,11 +440,6 @@ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" - }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -454,20 +450,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" }, "babel-eslint": { "version": "10.0.3", @@ -493,56 +484,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", @@ -554,12 +495,12 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, "bcrypt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.6.tgz", - "integrity": "sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.7.tgz", + "integrity": "sha512-K5UglF9VQvBMHl/1elNyyFvAfOY9Bj+rpKrCSR9sFwcW8FywAYJSRwTURNej5TaAK2TEJkcJ6r6lh1YPmspx5Q==", "requires": { - "nan": "2.13.2", - "node-pre-gyp": "0.12.0" + "nan": "2.14.0", + "node-pre-gyp": "0.13.0" } }, "bcrypt-pbkdf": { @@ -579,9 +520,10 @@ } }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true }, "blob": { "version": "0.0.5", @@ -593,10 +535,16 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, "boxen": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, "requires": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", @@ -610,22 +558,26 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -635,6 +587,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -651,30 +604,12 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" } }, "browser-stdout": { @@ -698,22 +633,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "cache-content-type": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", @@ -742,7 +661,8 @@ "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true }, "caseless": { "version": "0.12.0", @@ -767,6 +687,7 @@ "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", @@ -786,43 +707,19 @@ "dev": true }, "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "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.1" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } }, "chownr": { @@ -833,28 +730,8 @@ "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true }, "clean-stack": { "version": "1.3.0", @@ -864,7 +741,8 @@ "cli-boxes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true }, "cli-cursor": { "version": "3.1.0", @@ -917,15 +795,6 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", @@ -1013,6 +882,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, "requires": { "dot-prop": "^4.1.0", "graceful-fs": "^4.1.2", @@ -1079,11 +949,6 @@ } } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, "copy-to": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", @@ -1098,6 +963,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, "requires": { "capture-stack-trace": "^1.0.0" } @@ -1118,7 +984,8 @@ "crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true }, "dashdash": { "version": "1.14.1", @@ -1128,6 +995,11 @@ "assert-plus": "^1.0.0" } }, + "dayjs": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.19.tgz", + "integrity": "sha512-7kqOoj3oQSmqbvtvGFLU5iYqies+SqUiEGNT0UtUPPxcPYgY1BrkXR0Cq2R9HYSimBXN+xHkEN4Hi399W+Ovlg==" + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -1141,11 +1013,6 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -1180,43 +1047,6 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1237,11 +1067,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "deprecate": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/deprecate/-/deprecate-1.0.0.tgz", - "integrity": "sha1-ZhSQ7SQokWpsiIPYg05WRvTkpKg=" - }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -1281,6 +1106,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, "requires": { "is-obj": "^1.0.0" } @@ -1293,7 +1119,8 @@ "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true }, "ecc-jsbn": { "version": "0.1.2", @@ -1417,27 +1244,28 @@ "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=" }, "es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", + "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -1445,6 +1273,19 @@ "is-symbol": "^1.0.2" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1453,12 +1294,13 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eslint": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz", - "integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -1476,7 +1318,7 @@ "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -1489,7 +1331,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -1506,6 +1348,15 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -1541,13 +1392,13 @@ } }, "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", "dev": true, "requires": { "debug": "^2.6.9", - "resolve": "^1.5.0" + "resolve": "^1.13.1" }, "dependencies": { "debug": { @@ -1568,12 +1419,12 @@ } }, "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", + "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", "dev": true, "requires": { - "debug": "^2.6.8", + "debug": "^2.6.9", "pkg-dir": "^2.0.0" }, "dependencies": { @@ -1595,22 +1446,23 @@ } }, "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz", + "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==", "dev": true, "requires": { "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", + "eslint-module-utils": "^2.4.1", "has": "^1.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" + "resolve": "^1.12.0" }, "dependencies": { "debug": { @@ -1674,14 +1526,6 @@ "acorn": "^7.1.0", "acorn-jsx": "^5.1.0", "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", - "dev": true - } } }, "esprima": { @@ -1724,6 +1568,7 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -1738,6 +1583,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -1746,75 +1592,11 @@ } } }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -1826,65 +1608,6 @@ "tmp": "^0.0.33" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -1896,9 +1619,9 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", @@ -1940,24 +1663,12 @@ "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==" }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } + "to-regex-range": "^5.0.1" } }, "find-up": { @@ -1992,553 +1703,66 @@ "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.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "optional": 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" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "optional": true, + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "glob": "^7.1.3" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "optional": true } } }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -2581,12 +1805,8 @@ "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true }, "getpass": { "version": "0.1.7", @@ -2622,6 +1842,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, "requires": { "ini": "^1.3.4" } @@ -2641,6 +1862,7 @@ "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -2658,7 +1880,8 @@ "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true }, "growl": { "version": "1.10.5", @@ -2667,9 +1890,9 @@ "dev": true }, "handlebars": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", - "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.1.tgz", + "integrity": "sha512-2dd6soo60cwKNJ90VewNLIzdZPR/E2YhszOTgHpN9V0YuwZk7x33/iZoIBnASwDFVHMY7iJ6NPL8d9f/DWYCTA==", "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -2723,12 +1946,13 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, "has-unicode": { @@ -2736,40 +1960,6 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -2818,6 +2008,33 @@ "sshpk": "^1.7.0" } }, + "http_ece": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http_ece/-/http_ece-1.1.0.tgz", + "integrity": "sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA==", + "requires": { + "urlsafe-base64": "~1.0.0" + } + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2835,7 +2052,8 @@ "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true }, "ignore-walk": { "version": "3.0.3", @@ -2851,9 +2069,9 @@ "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2871,12 +2089,14 @@ "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indent-string": { "version": "3.2.0", @@ -2913,9 +2133,9 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.3.tgz", + "integrity": "sha512-+OiOVeVydu4hnCGLCSX+wedovR/Yzskv9BFqUNNKq9uU2qg7LCcCo3R86S2E7WLo0y/x2pnEZfZe1CoYnORUAw==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -2927,16 +2147,16 @@ "lodash": "^4.17.15", "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", + "rxjs": "^6.5.3", "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "is-fullwidth-code-point": { @@ -2946,14 +2166,25 @@ "dev": true }, "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, "strip-ansi": { @@ -2963,6 +2194,14 @@ "dev": true, "requires": { "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } @@ -2988,40 +2227,18 @@ "standard-as-callback": "^2.0.1" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { @@ -3031,74 +2248,31 @@ "dev": true }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, "is-ci": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, "requires": { "ci-info": "^1.5.0" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -3117,6 +2291,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -3125,6 +2300,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, "requires": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" @@ -3133,52 +2309,30 @@ "is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, "requires": { "path-is-inside": "^1.0.1" } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -3188,34 +2342,42 @@ "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dev": true, "requires": { - "has": "^1.0.1" + "has": "^1.0.3" } }, "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, "is-typedarray": { @@ -3223,11 +2385,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3244,12 +2401,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isstream": { "version": "0.1.2", @@ -3299,9 +2452,9 @@ "dev": true }, "json-mask": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/json-mask/-/json-mask-0.3.8.tgz", - "integrity": "sha1-LWZBXeFLDovGwVFFVKkL/Kg1aUE=" + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/json-mask/-/json-mask-0.3.9.tgz", + "integrity": "sha512-RRu7bf7vzOohKMrU5pD9+fROMltTegWj2trZlPNr7hXekptFGkOZo4S63Jdx2X1GR7IK6rEVvXkQKY+2TPs0PA==" }, "json-schema": { "version": "0.2.3", @@ -3399,11 +2552,6 @@ "tsscmp": "1.0.6" } }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, "koa": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/koa/-/koa-2.11.0.tgz", @@ -3557,6 +2705,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, "requires": { "package-json": "^4.0.0" } @@ -3714,11 +2863,26 @@ "resolved": "https://registry.npmjs.org/lodash.orderby/-/lodash.orderby-4.6.0.tgz", "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=" }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, "lodash.transform": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz", "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=" }, + "lodash.xor": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.xor/-/lodash.xor-4.5.0.tgz", + "integrity": "sha1-TUjtfpgJWwYyWCunFNP/iuj7HbY=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -3743,12 +2907,14 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -3757,19 +2923,21 @@ "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 } } }, "luxon": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.21.1.tgz", - "integrity": "sha512-3zxaKX7mj7eA80TU0sm4CfNEtiUZ2QXGjMc80rfG4d1dOnnOOWz63U9j4nYR7+1w716DYtWfdOeVhDXYlH+D4w==" + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.21.3.tgz", + "integrity": "sha512-lLRwNcNnkZLuv13A1FUuZRZmTWF7ro2ricYvb0L9cvBYHPvZhQdKwrYnZzi103D2XKmlVmxWpdn2wfIiOt2YEw==" }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, "requires": { "pify": "^3.0.0" }, @@ -3777,23 +2945,11 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -3815,26 +2971,6 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -3842,16 +2978,16 @@ "dev": true }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", "requires": { - "mime-db": "1.40.0" + "mime-db": "1.43.0" } }, "mimic-fn": { @@ -3860,6 +2996,11 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3890,25 +3031,6 @@ "minipass": "^2.9.0" } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -3918,13 +3040,14 @@ } }, "mocha": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", - "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.0.tgz", + "integrity": "sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", + "chokidar": "3.3.0", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", @@ -3937,7 +3060,7 @@ "minimatch": "3.0.4", "mkdirp": "0.5.1", "ms": "2.1.1", - "node-environment-flags": "1.0.5", + "node-environment-flags": "1.0.6", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", @@ -4026,9 +3149,9 @@ "dev": true }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -4115,9 +3238,9 @@ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "mongodb": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.3.tgz", - "integrity": "sha512-MdRnoOjstmnrKJsK8PY0PjP6fyF/SBS4R8coxmhsfEU7tQ46/J6j+aSHF2n4c2/H8B+Hc/Klbfp8vggZfI0mmA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz", + "integrity": "sha512-juqt5/Z42J4DcE7tG7UdVaTKmUC6zinF4yioPfpeOSNBieWSK6qCY+0tfGQcHLKrauWPDdMZVROHJOa8q2pWsA==", "requires": { "bson": "^1.1.1", "require_optional": "^1.0.1", @@ -4126,13 +3249,13 @@ } }, "mongoose": { - "version": "5.7.10", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.7.10.tgz", - "integrity": "sha512-KpQosHPXmlNJKZbiP19mtmC0icaziRlB+xZ14R8q7jY7+OgbbynLD9VWSFb1CyzJX5ebdkVSGmay9HXn341hTA==", + "version": "5.8.7", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.8.7.tgz", + "integrity": "sha512-PCCuTrdxpUmO86L1geXWE+9AvJRFuneIrMUT2hB/LXZ+5HIGOIfE6OSMU7cd8wFU7JRINP9V73zZ9YsmAbt+Iw==", "requires": { "bson": "~1.1.1", "kareem": "2.3.1", - "mongodb": "3.3.3", + "mongodb": "3.4.1", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.6.0", "mquery": "3.2.2", @@ -4192,32 +3315,14 @@ "dev": true }, "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "nanoid": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.6.tgz", - "integrity": "sha512-2NDzpiuEy3+H0AVtdt8LoFi7PnqkOnIzYmJQp7xsEU6VexLluHQwKREuiz57XaQC5006seIadPrIZJhyS2n7aw==" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.9.tgz", + "integrity": "sha512-J2X7aUpdmTlkAuSe9WaQ5DsTZZPW1r/zmEWKsGhbADO6Gm9FMd2ZzJ8NhsmP4OtA9oFhXfxNqPlreHEDOGB4sg==" }, "natural-compare": { "version": "1.4.0", @@ -4273,9 +3378,9 @@ "dev": true }, "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", @@ -4303,9 +3408,9 @@ } }, "node-pre-gyp": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", + "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -4320,16 +3425,17 @@ } }, "nodemailer": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.3.1.tgz", - "integrity": "sha512-j0BsSyaMlyadEDEypK/F+xlne2K5m6wzPYMXS/yxKI0s7jmT1kBx6GEKRVbZmyYfKOsjkeC/TiMVDJBI/w5gMQ==" + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.2.tgz", + "integrity": "sha512-g0n4nH1ONGvqYo1v72uSWvF/MRNnnq1LzmSzXb/6EPF3LFb51akOhgG3K2+aETAsJx90/Q5eFNTntu4vBCwyQQ==" }, "nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz", + "integrity": "sha512-GWhYPMfde2+M0FsHnggIHXTqPDHXia32HRhh6H0d75Mt9FKUoCBvumNHr7LdrpPBTKxsWmIEOjoN+P4IU6Hcaw==", + "dev": true, "requires": { - "chokidar": "^2.1.8", + "chokidar": "^3.2.2", "debug": "^3.2.6", "ignore-by-default": "^1.0.1", "minimatch": "^3.0.4", @@ -4345,6 +3451,7 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { "ms": "^2.1.1" } @@ -4375,7 +3482,8 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "notepack.io": { "version": "2.1.3", @@ -4383,14 +3491,22 @@ "integrity": "sha512-AgSt+cP5XMooho1Ppn8NB3FFaVWefV+qZoZncYTUSch2GAEwlYLcIIbT5YVkMlFeNHnfwOvc4HDlbvrB5BRxXA==" }, "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz", + "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==", "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -4400,6 +3516,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, "requires": { "path-key": "^2.0.0" } @@ -4435,58 +3552,17 @@ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", "dev": true }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } + "dev": true }, "object.assign": { "version": "4.1.0", @@ -4501,43 +3577,35 @@ } }, "object.entries": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", - "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } }, "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" } @@ -4587,25 +3655,17 @@ } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } + "word-wrap": "~1.2.3" } }, "os-homedir": { @@ -4691,6 +3751,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, "requires": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", @@ -4737,16 +3798,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -4761,12 +3812,14 @@ "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true }, "path-parse": { "version": "1.0.6", @@ -4775,9 +3828,9 @@ "dev": true }, "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "requires": { "isarray": "0.0.1" }, @@ -4817,6 +3870,12 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -4836,11 +3895,6 @@ "resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz", "integrity": "sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M=" }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -4850,7 +3904,8 @@ "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true }, "process-nextick-args": { "version": "2.0.1", @@ -4866,17 +3921,19 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" }, "pstree.remy": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==" + "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "dev": true }, "punycode": { "version": "2.1.1", @@ -4898,6 +3955,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + }, "raw-body": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", @@ -4958,9 +4020,9 @@ } }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4972,13 +4034,12 @@ } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.0.4" } }, "redis": { @@ -5016,15 +4077,6 @@ "redis-errors": "^1.0.0" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexp-clone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", @@ -5040,6 +4092,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -5049,25 +4102,11 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, "requires": { "rc": "^1.0.1" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -5123,10 +4162,15 @@ "semver": "^5.1.0" } }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.2.tgz", + "integrity": "sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -5137,11 +4181,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -5152,11 +4191,6 @@ "signal-exit": "^3.0.2" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -5180,9 +4214,9 @@ } }, "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -5193,14 +4227,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5221,9 +4247,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "scmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.0.0.tgz", - "integrity": "sha1-JHEQ7yLM+JexOj8KvdtSeCOTzWo=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" }, "secure-keys": { "version": "1.0.0", @@ -5239,6 +4265,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, "requires": { "semver": "^5.0.3" } @@ -5248,27 +4275,6 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -5278,6 +4284,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -5285,7 +4292,8 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true }, "sift": { "version": "7.0.1", @@ -5329,126 +4337,6 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "socket.io": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", @@ -5463,9 +4351,9 @@ } }, "socket.io-adapter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", - "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" }, "socket.io-client": { "version": "2.3.0", @@ -5569,23 +4457,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -5627,14 +4498,6 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5672,25 +4535,6 @@ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==" }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -5707,9 +4551,9 @@ } }, "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -5717,9 +4561,9 @@ } }, "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -5751,7 +4595,8 @@ "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true }, "strip-json-comments": { "version": "2.0.1", @@ -5801,6 +4646,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -5875,6 +4721,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, "requires": { "execa": "^0.7.0" } @@ -5899,12 +4746,13 @@ "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true }, "timezone-validator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/timezone-validator/-/timezone-validator-1.0.2.tgz", - "integrity": "sha512-MdmeWb2wFagzChabzDl56sgaUpYLWUpQRp3G/mOe7M0V1CGnrT/9nuSX4nFxKNToYQP5CmYoiyGU7Hh8cobUCQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/timezone-validator/-/timezone-validator-1.0.3.tgz", + "integrity": "sha512-WrTCfMJY3kUUnVxqumKZEWHv71R09u4+KhXQEE+JbgztTbqL5wCo0a6f4G9o9kvO/sYIcFAbdHAobWp6elIlKQ==" }, "tmp": { "version": "0.0.33", @@ -5926,47 +4774,13 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "toidentifier": { @@ -5986,6 +4800,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, "requires": { "nopt": "~1.0.10" }, @@ -5994,6 +4809,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, "requires": { "abbrev": "1" } @@ -6046,20 +4862,20 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "twilio": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.37.0.tgz", - "integrity": "sha512-XnuTpDncrTCU3aj07wrgZMt/LIA3zKJ73U4RX+vWdx9J7Ppmxk1z8XxsSmjinNBZW+N4sYPkChoA7s4PV1CqyA==", + "version": "3.39.2", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.39.2.tgz", + "integrity": "sha512-M0dM6wCaR+YVXQeqldiqXNAqqSeZSuhSL5paRFbFTJDpsq/R6eqqhSPvyoaS9hQIm2PNhaEKq+lvqCELckDWpg==", "requires": { - "@types/express": "^4.17.1", - "deprecate": "1.0.0", + "@types/express": "^4.17.2", + "dayjs": "^1.8.19", "jsonwebtoken": "^8.5.1", "lodash": "^4.17.15", - "moment": "^2.24.0", "q": "2.0.x", "request": "^2.88.0", - "rootpath": "0.1.2", - "scmp": "2.0.0", - "xmlbuilder": "9.0.1" + "rootpath": "^0.1.2", + "scmp": "^2.1.0", + "url-parse": "^1.4.7", + "xmlbuilder": "^13.0.2" } }, "type-check": { @@ -6078,9 +4894,9 @@ "dev": true }, "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, "type-is": { @@ -6093,9 +4909,9 @@ } }, "uglify-js": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.7.tgz", - "integrity": "sha512-4sXQDzmdnoXiO+xvmTzQsfIiwrjUCSA95rSP4SEd8tDb51W2TiDOlL76Hl+Kw0Ie42PSItCW8/t6pBNCF2R48A==", + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.5.tgz", + "integrity": "sha512-GFZ3EXRptKGvb/C1Sq6nO1iI7AGcjyqmIyOw0DrD0675e+NNbGO72xmMM2iEBdFbxaTLo70NbjM/Wy54uZIlsg==", "optional": true, "requires": { "commander": "~2.20.3", @@ -6111,6 +4927,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "dev": true, "requires": { "debug": "^2.2.0" }, @@ -6119,6 +4936,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -6126,25 +4944,16 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, "requires": { "crypto-random-string": "^1.0.0" } @@ -6154,56 +4963,17 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, "unzip-response": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true }, "update-notifier": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", @@ -6230,23 +5000,28 @@ "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, "requires": { "prepend-http": "^1.0.1" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + "urlsafe-base64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz", + "integrity": "sha1-I/iQaabGL0bPOh07ABac77kL4MY=" }, "util-deprecate": { "version": "1.0.2", @@ -6299,10 +5074,31 @@ "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz", "integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes=" }, + "web-push": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/web-push/-/web-push-3.4.3.tgz", + "integrity": "sha512-nt/hRSlfRDTwvem//7jle1+cy62lBoxFshad8ai2Q4SlHZS00oHnrw5Dul3jSWXR+bOcnZkwnRs3tW+daNTuyA==", + "requires": { + "asn1.js": "^5.0.0", + "http_ece": "1.1.0", + "https-proxy-agent": "^3.0.0", + "jws": "^3.1.3", + "minimist": "^1.2.0", + "urlsafe-base64": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, "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" } @@ -6325,6 +5121,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, "requires": { "string-width": "^2.1.1" }, @@ -6332,17 +5129,20 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -6352,6 +5152,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -6399,15 +5200,6 @@ } } }, - "winston-mongodb": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/winston-mongodb/-/winston-mongodb-5.0.1.tgz", - "integrity": "sha512-ZLwAqh8DO9JrZYOjhbjvRKZU7v+X3qgPEp75uEVvYZPsV6LxgcR0xWlleCpc5hN+AakEMo7klO/WZoUhsmeDqw==", - "requires": { - "mongodb": "^3.3.3", - "winston-transport": "^4.3.0" - } - }, "winston-transport": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", @@ -6418,15 +5210,21 @@ } }, "with-open-file": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.6.tgz", - "integrity": "sha512-SQS05JekbtwQSgCYlBsZn/+m2gpn4zWsqpCYIrCHva0+ojXcnmUEPsBN6Ipoz3vmY/81k5PvYEWSxER2g4BTqA==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz", + "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==", "requires": { "p-finally": "^1.0.0", "p-try": "^2.1.0", "pify": "^4.0.1" } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -6459,6 +5257,7 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -6466,22 +5265,20 @@ } }, "ws": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz", - "integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==", - "requires": { - "async-limiter": "^1.0.0" - } + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==" }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true }, "xmlbuilder": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.1.tgz", - "integrity": "sha1-kc1wiXdVNj66V8Et3uq0o0GmH2U=" + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" }, "xmlhttprequest-ssl": { "version": "1.5.5", @@ -6590,9 +5387,9 @@ } }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "dev": true, "requires": { "p-try": "^2.0.0" diff --git a/package.json b/package.json index 1096248..151eed6 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,12 @@ "name": "e-chauffeur_api", "private": true, "type": "module", - "version": "1.4.2", - "description": "", "scripts": { "test": "mocha --experimental-modules --exit --require @std/esm --recursive \"tests/**/*.mjs\"", "serve": "LOG=database node --experimental-modules --es-module-specifier-resolution=node server.mjs", "nodemon": "nodemon --experimental-modules --es-module-specifier-resolution=node --inspect server.mjs", "lint": "eslint --ext .js,.mjs --ignore-path .gitignore .", + "generate-vapid": "node generate-vapid-key.js", "precommit": "npm run lint", "generate-state-schema": "node --experimental-modules --es-module-specifier-resolution=node tests/generate-state-schema.js", "import-fixtures": "node --experimental-modules --es-module-specifier-resolution=node fixtures" @@ -18,14 +17,14 @@ "dependencies": { "@koa/cors": "^3.0.0", "@rentspree/mongoose-state-machine": "^0.1.1", - "bcrypt": "^3.0.5", + "bcrypt": "^3.0.7", "glob": "^7.1.6", "google-libphonenumber": "^3.2.6", - "handlebars": "^4.4.5", + "handlebars": "^4.7.1", "ioredis": "^4.14.1", "javascript-state-machine": "^3.1.0", "joi": "^14.3.1", - "json-mask": "^0.3.8", + "json-mask": "^0.3.9", "json2csv": "^4.5.4", "jsonwebtoken": "^8.5.1", "koa": "^2.10.0", @@ -45,33 +44,36 @@ "lodash.omit": "^4.5.0", "lodash.omitby": "^4.6.0", "lodash.orderby": "^4.6.0", + "lodash.pickby": "^4.6.0", + "lodash.set": "^4.3.2", "lodash.transform": "^4.6.0", - "luxon": "^1.21.1", - "mongoose": "^5.7.10", - "nanoid": "^2.1.6", + "lodash.xor": "^4.5.0", + "luxon": "^1.21.3", + "mongoose": "^5.8.7", + "nanoid": "^2.1.9", "nconf": "^0.10.0", "node-input-validator": "^3.8.0", - "nodemailer": "^6.3.1", - "nodemon": "^1.19.4", + "nodemailer": "^6.4.2", "qs": "^6.9.1", "socket.io": "^2.3.0", "socket.io-redis": "^5.2.0", "sprintf-lite": "^1.3.0", - "timezone-validator": "^1.0.2", - "twilio": "^3.37.0", + "timezone-validator": "^1.0.3", + "twilio": "^3.39.2", "validator": "^11.1.0", - "winston": "^3.2.1", - "winston-mongodb": "^5.0.1" + "web-push": "^3.4.3", + "winston": "^3.2.1" }, "devDependencies": { "@std/esm": "^0.26.0", - "acorn": "^6.3.0", + "acorn": "^7.1.0", "babel-eslint": "^10.0.3", "chai": "^4.2.0", - "eslint": "^6.5.1", + "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.0.0", - "eslint-plugin-import": "^2.18.2", - "mocha": "^6.2.2", + "eslint-plugin-import": "^2.20.0", + "mocha": "^7.0.0", + "nodemon": "^2.0.2", "supertest": "^4.0.2" }, "peerDependencies": { diff --git a/routes/campuses.mjs b/routes/campuses.mjs index efa5f83..55bf0d4 100644 --- a/routes/campuses.mjs +++ b/routes/campuses.mjs @@ -8,13 +8,13 @@ import carsRoutes from './campuses/cars'; import statsRoutes from './campuses/stats'; import { CAN_CREATE_CAMPUS, - CAN_EDIT_CAMPUS, + CAN_EDIT_CAMPUS, CAN_EDIT_SELF_CAMPUS, CAN_GET_CAMPUS, CAN_GET_CAMPUS_BASIC, CAN_LIST_CAMPUS, CAN_LIST_CAMPUS_BASIC, CAN_REMOVE_CAMPUS, } from '../models/rights'; -const BASIC_OUTPUT_MASK = '_id,id,name,location(coordinates),phone(everybody)'; +const BASIC_OUTPUT_MASK = '_id,id,name,location(coordinates),phone(everybody),defaultReservationScope'; const router = generateCRUD(Campus, { create: { right: CAN_CREATE_CAMPUS, @@ -54,7 +54,8 @@ const router = generateCRUD(Campus, { right: CAN_REMOVE_CAMPUS, }, update: { - right: CAN_EDIT_CAMPUS, + paramId: 'campus_id', + right: [CAN_EDIT_CAMPUS, CAN_EDIT_SELF_CAMPUS], }, }); diff --git a/routes/index.mjs b/routes/index.mjs index 868904d..e86bd66 100644 --- a/routes/index.mjs +++ b/routes/index.mjs @@ -14,6 +14,7 @@ import phones from './phones'; import phoneModels from './phone-models'; import timeSlots from './time-slots'; import config from '../services/config'; +import ratings from './ratings'; const router = new Router(); @@ -35,5 +36,6 @@ router.use('/forms', forms); router.use('/phones', phones); router.use('/phone-models', phoneModels); router.use('/time-slots', timeSlots); +router.use('/ratings', ratings); export default router.routes(); diff --git a/routes/jwt.mjs b/routes/jwt.mjs index f48382a..bb530be 100644 --- a/routes/jwt.mjs +++ b/routes/jwt.mjs @@ -1,7 +1,7 @@ import Router from 'koa-router'; import jwt from 'koa-jwt'; import config from '../services/config'; -import User from '../models/user'; +import User, { ExpiredPasswordError } from '../models/user'; import Campus from '../models/campus'; import maskOutput from '../middlewares/mask-output'; import resolveRights from '../middlewares/check-rights'; @@ -23,7 +23,14 @@ router.post('/generate', resolveRights(CAN_LOGIN), maskOutput, async (ctx) => { ctx.throw_and_log(403, `Username and password do not match for user "${body.email}".`); } - ctx.body = { token: user.emitJWT(!!body.password) }; + try { + ctx.body = { token: user.emitJWT(!!body.password) }; + } catch (e) { + if (e instanceof ExpiredPasswordError) { + ctx.throw_and_log(401, 'Password expired'); + } + throw e; + } }); router.post( @@ -38,7 +45,14 @@ router.post( if (!user) { ctx.throw_and_log(404, `User "${ctx.state.user.id}" not found.`); } - ctx.body = { token: user.emitJWT() }; + try { + ctx.body = { token: user.emitJWT() }; + } catch (e) { + if (e instanceof ExpiredPasswordError) { + ctx.throw_and_log(401, 'Password expired'); + } + throw e; + } }, ); diff --git a/routes/logs.mjs b/routes/logs.mjs index 7919360..85e6829 100644 --- a/routes/logs.mjs +++ b/routes/logs.mjs @@ -1,44 +1,14 @@ import luxon from 'luxon'; -import generateCRUD from '../helpers/abstract-route'; +import Router from 'koa-router'; import resolveRights from '../middlewares/check-rights'; import maskOutput from '../middlewares/mask-output'; -import logger from '../services/logger'; import { CAN_GET_POSITION_HISTORY, - CAN_LIST_LOG, } from '../models/rights'; import GeoTracking from '../models/geo-tracking'; const { DateTime } = luxon; -const fakeModel = { modelName: 'log' }; -const router = generateCRUD(fakeModel, { - list: { - right: CAN_LIST_LOG, - async main(ctx) { - const limit = 100; - - const { mongodb: data } = await new Promise( - (resolve, reject) => logger.query( - { - limit, - order: 'desc', - }, - (err, r) => (err ? reject(err) : resolve(r)), - ), - ); - - ctx.log( - ctx.log.INFO, - `Find query in ${fakeModel.modelName}`, - { - filters: ctx.filters, limit, - }, - ); - - ctx.body = data; - }, - }, -}); +const router = new Router(); router.get( '/positions-history', diff --git a/routes/pois.mjs b/routes/pois.mjs index c1a48f7..9028e48 100644 --- a/routes/pois.mjs +++ b/routes/pois.mjs @@ -30,29 +30,14 @@ const router = generateCRUD(Poi, { right: [CAN_LIST_POI, CAN_LIST_POI_LOCAL], filters: { campus: 'campus._id', + withDisabled: 'enabled', }, - middlewares: [ - async (ctx, next) => { - const searchParams = ctx.filters; - if (ctx.query && ctx.query.search) { - searchParams.$or = [ - { - _id: new RegExp(ctx.query.search, 'i'), - }, - { - label: new RegExp(ctx.query.search, 'i'), - }, - ]; - } - ctx.filters = searchParams; - await next(); - }, - ], async main(ctx) { const { offset, limit } = ctx.parseRangePagination(Poi, { max: 1000 }); + const [total, data] = await Promise.all([ - Poi.countDocuments(ctx.filters), - Poi.find(ctx.filters).skip(offset).limit(limit).lean(), + Poi.countDocumentsWithin(ctx.filters, ctx.query), + Poi.findWithin(ctx.filters, ctx.query).skip(offset).limit(limit).lean(), ]); ctx.log( diff --git a/routes/ratings.mjs b/routes/ratings.mjs new file mode 100644 index 0000000..3ca603f --- /dev/null +++ b/routes/ratings.mjs @@ -0,0 +1,38 @@ +import generateCRUD from '../helpers/abstract-route'; +import Rating from '../models/rating'; +import { + CAN_CREATE_RATING, + CAN_LIST_RATING, +} from '../models/rights'; + +const router = generateCRUD(Rating, { + create: { + right: CAN_CREATE_RATING, + }, + list: { + right: CAN_LIST_RATING, + async main(ctx) { + const { offset, limit } = ctx.parseRangePagination(Rating); + const [total, data] = await Promise.all([ + Rating.countDocuments(ctx.filters), + Rating.find(ctx.filters).skip(offset).limit(limit).sort({ createdAt: 'desc' }) + .lean(), + ]); + + ctx.log( + ctx.log.INFO, + `Find query in ${Rating.modelName}`, + { + filters: ctx.filters, offset, limit, total, + }, + ); + + ctx.setRangePagination(Rating, { + total, offset, count: data.length, limit, + }); + ctx.body = data; + }, + }, +}); + +export default router.routes(); diff --git a/routes/rides.mjs b/routes/rides.mjs index 093c16d..a0784ea 100644 --- a/routes/rides.mjs +++ b/routes/rides.mjs @@ -1,7 +1,9 @@ import camelCase from 'lodash.camelcase'; import lGet from 'lodash.get'; import mask from 'json-mask'; +import Luxon from 'luxon'; import { + CANCEL_REQUESTED_CUSTOMER, CANCELED_STATUSES, CREATE, DELIVERED, DRAFTED, } from '../models/status'; import maskOutput, { cleanObject } from '../middlewares/mask-output'; @@ -9,6 +11,7 @@ import contentNegociation from '../middlewares/content-negociation'; import resolveRights from '../middlewares/check-rights'; import generateCRUD from '../helpers/abstract-route'; import Ride from '../models/ride'; +import NotificationDevice from '../models/notification-device'; import { ensureThatFiltersExists } from '../middlewares/query-helper'; import { CAN_CREATE_RIDE, @@ -16,16 +19,19 @@ import { CAN_EDIT_RIDE_STATUS, CAN_GET_RIDE, CAN_GET_RIDE_POSITION, - CAN_LIST_RIDE, + CAN_LIST_RIDE, CAN_LIST_SELF_RIDE, CAN_REQUEST_RIDE, CAN_GET_OWNED_RIDE, CAN_GET_RIDE_WITH_TOKEN, CAN_EDIT_OWNED_RIDE_STATUS, CAN_EDIT_OWNED_RIDE, + CAN_DELETE_SELF_RIDE, } from '../models/rights'; import { getPrefetchedRide, prefetchRideMiddleware } from '../helpers/prefetch-ride'; +const { DateTime } = Luxon; + function ioEmit(ctx, data, eventName = '', rooms = []) { let { app: { io } } = ctx; rooms.forEach((room) => { @@ -50,7 +56,7 @@ const router = generateCRUD(Ride, { delete body.status; body.owner = user; } - const ride = await Ride.create(Object.assign(body)); + const ride = await Ride.create(body); ctx.body = ride; if (!ctx.may(CAN_CREATE_RIDE)) { ctx.body = mask(ctx.body, REQUEST_POST_MASK); @@ -61,6 +67,20 @@ const router = generateCRUD(Ride, { `campus/${ride.campus.id}`, `driver/${ride.driver.id}`, ]); + // Todo: add this to a queue system to ensure this will be executed + NotificationDevice.findOneByUser(ride.driver.id).then((device) => { + if (device) { + const payload = { + message: `Nouvelle course à ${DateTime.fromJSDate(ride.start).setLocale('fr').toFormat('HH\'h\'mm')}`, + body: `De ${ride.departure.label} à ${ride.arrival.label}`, + }; + device.notify(payload).catch((e) => { + if (e.name === 'WebPushError') { + NotificationDevice.deleteOne({ _id: device._id.toString() }).exec(); + } + }); + } + }); }, }, update: { @@ -115,6 +135,7 @@ const router = generateCRUD(Ride, { preMiddlewares: [ prefetchRideMiddleware(), ], + lean: false, right: [CAN_GET_RIDE, CAN_GET_OWNED_RIDE, CAN_GET_RIDE_WITH_TOKEN], async main(ctx) { const { params: { id } } = ctx; @@ -132,32 +153,41 @@ const router = generateCRUD(Ride, { }, }, list: { - right: CAN_LIST_RIDE, + lean: false, + right: [CAN_LIST_RIDE, CAN_LIST_SELF_RIDE], filters: { campus: 'campus._id', + userId: 'owner._id', }, middlewares: [ contentNegociation, maskOutput, async (ctx, next) => { await next(); - if (lGet(ctx, 'query.csv.flatten', '').toLowerCase() === 'true') { - ctx.body = ctx.body.map((ride) => ({ - ...ride, - departure: { - ...ride.departure, + ctx.body = ctx.body.map((model) => { + const ride = model.toObject({ virtuals: true, aliases: true }); + let departure = { ...ride.departure }; + let arrival = { ...ride.arrival }; + if (lGet(ctx, 'query.csv.flatten', '').toLowerCase() === 'true') { + departure = { + ...departure, location: { longitude: lGet(ride, 'departure.location.coordinates.0', null), latitude: lGet(ride, 'departure.location.coordinates.1', null), }, - }, - arrival: { - ...ride.arrival, + }; + arrival = { + ...arrival, location: { longitude: lGet(ride, 'arrival.location.coordinates.0', null), latitude: lGet(ride, 'arrival.location.coordinates.1', null), }, - }, + }; + } + return { + ...ride, + departure, + arrival, status: { latest: ride.status, ...ride @@ -166,19 +196,18 @@ const router = generateCRUD(Ride, { .map(({ time, status }) => ({ [status]: time })) .reduce((row, acc) => Object.assign(acc, row), {}), }, - })); - } + }; + }); }, ensureThatFiltersExists('start', 'end'), ], async main(ctx) { // @todo: Add right on max const { offset, limit } = ctx.parseRangePagination(Ride, { max: 1000 }); - const start = new Date(ctx.query.filters.start); - const end = new Date(ctx.query.filters.end); - const total = await Ride.countDocumentsWithin(start, end, ctx.filters); - const data = await Ride.findWithin(start, end, ctx.filters).skip(offset).limit(limit).lean(); + const total = await Ride.countDocumentsWithin(ctx.filters, ctx.query.filters); + const data = await Ride.findWithin(ctx.filters, ctx.query.filters).skip(offset).limit(limit); + ctx.setRangePagination(Ride, { total, offset, count: data.length, limit, }); @@ -191,6 +220,9 @@ const router = generateCRUD(Ride, { ); }, }, + delete: { + right: CAN_DELETE_SELF_RIDE, + }, }); /** @@ -240,14 +272,14 @@ router.post( async (ctx) => { // @todo: rights - driver should be able to update only some status const { params: { id, action } } = ctx; - if (!ctx.may(CAN_EDIT_RIDE_STATUS) && action !== CREATE) { + if (!ctx.may(CAN_EDIT_RIDE_STATUS) && action !== CREATE && action !== CANCEL_REQUESTED_CUSTOMER) { ctx.throw_and_log(403, `You're not authorized to mutate to "${action}"`); } const ride = getPrefetchedRide(ctx, id); if (!ride) { ctx.throw_and_log(404, `${Ride.modelName} "${id}" not found`); } - if (!ride.can(action)) { + if (ride.cannot(action)) { ctx.throw_and_log(400, `State violation : ride cannot switch to "${action}"`); } diff --git a/routes/users.mjs b/routes/users.mjs index 6756083..9acc522 100644 --- a/routes/users.mjs +++ b/routes/users.mjs @@ -1,5 +1,6 @@ import generateCRUD from '../helpers/abstract-route'; import User from '../models/user'; +import NotificationDevice from '../models/notification-device'; import { CAN_CREATE_USER, CAN_EDIT_SELF_USER_NAME, CAN_EDIT_SELF_USER_PASSWORD, CAN_SEND_CREATION_TOKEN, @@ -7,7 +8,8 @@ import { CAN_EDIT_USER_SENSITIVE_DATA, CAN_GET_USER, CAN_LIST_USER, - CAN_REMOVE_USER, + CAN_REMOVE_USER, CAN_REMOVE_SELF_USER, + CAN_EDIT_USER_WITHOUT_UPPER_RIGHTS, } from '../models/rights'; import config from '../services/config'; @@ -92,7 +94,8 @@ const router = generateCRUD(User, { lean: false, }, delete: { - right: CAN_REMOVE_USER, + paramId: 'user_id', + right: [CAN_REMOVE_USER, CAN_REMOVE_SELF_USER], }, list: { right: CAN_LIST_USER, @@ -181,7 +184,11 @@ const router = generateCRUD(User, { if (!user.email_confirmed && body.email && body.email_token) { await user.confirmEmail(body.email_token); } - + ctx.assert( + ctx.may(CAN_EDIT_USER_WITHOUT_UPPER_RIGHTS, user), + 403, + 'You\'re not authorized to update this user', + ); ctx.body = await user.save(); if ((ctx.headers[X_SEND_TOKEN] && ctx.headers[X_SEND_TOKEN] !== 'false')) { @@ -215,4 +222,16 @@ const router = generateCRUD(User, { }, }); +router.post( + '/:userId/subscribe-device', + async (ctx) => { + const { request: { body } } = ctx; + body.user = { + _id: ctx.params.userId, + }; + await NotificationDevice.findOneAndUpdateByUser(body); + ctx.status = 204; + }, +); + export default router.routes(); diff --git a/services/logger.mjs b/services/logger.mjs index b379fe6..a3a8db6 100644 --- a/services/logger.mjs +++ b/services/logger.mjs @@ -1,19 +1,8 @@ import winston from 'winston'; -import 'winston-mongodb'; import Transport from 'winston-transport'; import omitBy from 'lodash.omitby'; import isFunction from 'lodash.isfunction'; -import config from './config'; - -export const createMongoDBTransport = (db) => new winston.transports.MongoDB({ db, collection: 'logs' }); - -export const defaultConsoleTransport = new winston.transports.Console({ level: process.env.LOG_LEVEL || 'warn' }); -export const defaultMongoDBTransport = createMongoDBTransport(config.get('mongodb')); - -winston.add(defaultMongoDBTransport); -winston.add(defaultConsoleTransport); - export const ERROR = 'error'; export const WARN = 'warn'; export const INFO = 'info'; @@ -21,6 +10,10 @@ export const VERBOSE = 'verbose'; export const DEBUG = 'debug'; export const SILLY = 'silly'; +export const defaultConsoleTransport = new winston.transports.Console({ level: process.env.LOG_LEVEL || INFO }); +winston.add(defaultConsoleTransport); + + export async function loggerMiddleware(ctx, next) { ctx.log = (level, message, meta = {}) => { const metadata = omitBy({ user: ctx.state.user, ...meta }, isFunction); diff --git a/services/mongoose.mjs b/services/mongoose.mjs index 8fb029d..6b591f9 100644 --- a/services/mongoose.mjs +++ b/services/mongoose.mjs @@ -2,7 +2,12 @@ import mongoose from 'mongoose'; const connect = async (config) => { try { - await mongoose.connect(config, { useNewUrlParser: true }); + const deprecationOptions = { + useNewUrlParser: true, + useCreateIndex: true, + useUnifiedTopology: true, + }; + await mongoose.connect(config, deprecationOptions); // eslint-disable-next-line no-console console.log('MongoDB connected !'); } catch (e) { diff --git a/tests/helpers/crud/create.mjs b/tests/helpers/crud/create.mjs index 1ed65f6..b62b95a 100644 --- a/tests/helpers/crud/create.mjs +++ b/tests/helpers/crud/create.mjs @@ -25,9 +25,9 @@ export const testCreate = (Model, { const object = await Model .findById(id); if (object) { - await object.remove(); + await object.deleteOne(); } - await Promise.all(toDropLater.map((entity) => entity.remove())); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); return { statusCode: expect(statusCode), @@ -96,8 +96,8 @@ export const testCreateUnicity = (Model, { expect(statusCode).to.equal(409); } } finally { - await dummyObject.remove(); - await Promise.all(toDropLater.map((entity) => entity.remove())); + await dummyObject.deleteOne(); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); } }, ]; diff --git a/tests/helpers/crud/delete.mjs b/tests/helpers/crud/delete.mjs index 1062cbc..363207e 100644 --- a/tests/helpers/crud/delete.mjs +++ b/tests/helpers/crud/delete.mjs @@ -25,9 +25,9 @@ export const testDelete = (Model, { const object = await Model.findOne(createdObject.toObject()); if (object) { - await object.remove(); + await object.deleteOne(); } - await Promise.all(toDropLater.map((entity) => entity.remove())); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); return { statusCode: expect(statusCode), diff --git a/tests/helpers/crud/get.mjs b/tests/helpers/crud/get.mjs index 7ecb02c..79d182d 100644 --- a/tests/helpers/crud/get.mjs +++ b/tests/helpers/crud/get.mjs @@ -25,9 +25,9 @@ export const testGet = (Model, { const object = await Model.findOne(createdObject.toObject()); if (object) { - await object.remove(); + await object.deleteOne(); } - await Promise.all(toDropLater.map((entity) => entity.remove())); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); return { statusCode: expect(statusCode), diff --git a/tests/helpers/crud/update.mjs b/tests/helpers/crud/update.mjs index 2a7ea03..ee7856c 100644 --- a/tests/helpers/crud/update.mjs +++ b/tests/helpers/crud/update.mjs @@ -27,9 +27,9 @@ export const testUpdate = (Model, { const object = await Model.findById(createdObject._id); if (object) { - await object.remove(); + await object.deleteOne(); } - await Promise.all(toDropLater.map((entity) => entity.remove())); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); return { statusCode: expect(statusCode), diff --git a/tests/models/rating.mjs b/tests/models/rating.mjs new file mode 100644 index 0000000..9d1708d --- /dev/null +++ b/tests/models/rating.mjs @@ -0,0 +1,22 @@ +import nanoid from 'nanoid'; +import mongoose from 'mongoose'; +import Rating from '../../models/rating'; +import Ride from '../../models/ride'; + +const { Types: { ObjectId } } = mongoose; + +export const generateDummyRating = async () => { + const ride = await Ride.findOne(); + const rideId = ride._id.toString(); + return { + _id: new ObjectId(), + ride: { + _id: rideId, + }, + uxGrade: 0, + recommandationGrade: 1, + message: `Rating from test -- ${nanoid()}`, + }; +}; + +export default Rating; diff --git a/tests/request.mjs b/tests/request.mjs index 6e1a780..15b69b9 100644 --- a/tests/request.mjs +++ b/tests/request.mjs @@ -1,5 +1,4 @@ import request from 'supertest'; -import logger, { defaultMongoDBTransport, createMongoDBTransport } from '../services/logger'; import config from '../services/config'; import MongooseService from '../services/mongoose'; import app from '../app'; @@ -9,9 +8,6 @@ import * as roles from '../models/role'; config.get('whitelist_domains').push('localhost'); const DATABASE = `${config.get('mongodb')}-test`; -logger.remove(defaultMongoDBTransport); -logger.add(createMongoDBTransport(DATABASE)); - const rolesKeys = { ...Object.keys(roles) .map((r) => ({ [r]: r })) diff --git a/tests/routes/jwt.test.mjs b/tests/routes/jwt.test.mjs index 329214d..7b2de18 100644 --- a/tests/routes/jwt.test.mjs +++ b/tests/routes/jwt.test.mjs @@ -13,7 +13,7 @@ describe('Test the JWT route', () => { .post('/jwt/generate') .send({ email: 'foo@bar.com', - password: 'foobar', + password: 'foobarbaz', }); expect(statusCode).to.equal(403); }); @@ -23,13 +23,13 @@ describe('Test the JWT route', () => { .post('/jwt/generate') .send({ email: 'foo@bar.com', - password: 'foobar', + password: 'foobarbaz', }); expect(statusCode).to.equal(403); }); it('It should return a valid token on generate', async () => { - const PASSWORD = 'foobar'; + const PASSWORD = 'foobarbaz'; const user = await createDummyUser({ password: PASSWORD }); try { const { body: { token }, statusCode } = await request() @@ -45,7 +45,7 @@ describe('Test the JWT route', () => { ) .to.deep.include({ email: user.email, id: user.id }); } finally { - await user.remove(); + await user.deleteOne(); } }); }); @@ -76,12 +76,12 @@ describe('Test the JWT route', () => { .set('Authorization', `Bearer ${token}`); expect(statusCode).to.equal(404); } finally { - await user.remove(); + await user.deleteOne(); } }); it('It should return a valid new token on renew', async () => { - const PASSWORD = 'foobar'; + const PASSWORD = 'foobarbaz'; const user = await createDummyUser({ password: PASSWORD }); const authToken = user.emitJWT(); @@ -96,14 +96,14 @@ describe('Test the JWT route', () => { ) .to.deep.include({ email: user.email, id: user.id }); } finally { - await user.remove(); + await user.deleteOne(); } }); }); describe('Test the GET user route', () => { it('It should return a 404 error on get user when user not exists', async () => { - const PASSWORD = 'foobar'; + const PASSWORD = 'foobarbaz'; const user = new User(generateDummyUser({ password: PASSWORD })); const token = user.emitJWT(); @@ -113,12 +113,12 @@ describe('Test the JWT route', () => { .set('Authorization', `Bearer ${token}`); expect(statusCode).to.equal(404); } finally { - await user.remove(); + await user.deleteOne(); } }); it('It should return the user', async () => { - const PASSWORD = 'foobar'; + const PASSWORD = 'foobarbaz'; const u = await createDummyUser({ password: PASSWORD }); const authToken = u.emitJWT(); @@ -131,7 +131,7 @@ describe('Test the JWT route', () => { expect(user) .to.deep.equal({ email: u.email, id: u.id }); } finally { - await u.remove(); + await u.deleteOne(); } }); }); diff --git a/tests/routes/ratings.test.mjs b/tests/routes/ratings.test.mjs new file mode 100644 index 0000000..d04b65a --- /dev/null +++ b/tests/routes/ratings.test.mjs @@ -0,0 +1,54 @@ +import { + testCreate, testList, +} from '../helpers/crud'; +import Rating, { generateDummyRating } from '../models/rating'; +import { + generateSuperAdminJWTHeader, + generateAdminJWTHeader, + generateAnonymousJWTHeader, +} from '../request'; +import Ride, { generateDummyRide } from '../models/ride'; +import { createDummyCampus } from '../models/campus'; +import { createDummyPoi } from '../models/poi'; + +const config = { + route: '/ratings', + generateDummyObject: generateDummyRating, +}; +let toDropAfter = []; + +describe('Test the rating API endpoint', async () => { + before(async () => { + const dummyCampus = await createDummyCampus(); + const dummyDeparture = await createDummyPoi(); + const dummyArrival = await createDummyPoi(); + const newRide = generateDummyRide({ + start: new Date(), + end: new Date(Date.now() + 1000), + campus: dummyCampus, + departure: dummyDeparture, + arrival: dummyArrival, + }); + const dummyRide = await Ride.create(newRide); + toDropAfter = [ + dummyCampus, + dummyDeparture, + dummyArrival, + dummyRide, + ]; + }); + + it(...testCreate(Rating, { + ...config, + canCall: [generateAnonymousJWTHeader], + })); + it(...testList(Rating, { + ...config, + cannotCall: [generateAdminJWTHeader], + canCall: [generateSuperAdminJWTHeader], + })); + + after(async () => { + await Promise.all(toDropAfter.map((entity) => entity.deleteOne())); + }); +}); diff --git a/tests/routes/rides.test.mjs b/tests/routes/rides.test.mjs index 1b7feb8..3bece59 100644 --- a/tests/routes/rides.test.mjs +++ b/tests/routes/rides.test.mjs @@ -48,8 +48,8 @@ describe('Test the rides route', () => { end: date.plus(tenMinutes).toJSDate(), }); const rideModel = new Ride(dummyRide); - await rideModel.save(); - + const savedModel = await rideModel.save(); + toDropLater.push(savedModel); const query = { mask: 'id', filters: { @@ -76,7 +76,7 @@ describe('Test the rides route', () => { expect(response.headers['content-type']).to.contain('application/json'); } } finally { - await Promise.all(toDropLater.map((entity) => entity.remove())); + await Promise.all(toDropLater.map((entity) => entity.deleteOne())); } }); }); diff --git a/tests/routes/users.test.mjs b/tests/routes/users.test.mjs index bd4492c..dc35e73 100644 --- a/tests/routes/users.test.mjs +++ b/tests/routes/users.test.mjs @@ -61,4 +61,25 @@ describe('Test the users route', () => { await User.deleteOne(dummyUser); } }); + + it('User should be able to delete his account', async () => { + const dummyUser = generateDummyUser(); + const user = await User.create(dummyUser); + try { + { + const { statusCode } = await request() + .delete(`/users/${user.id}`) + .set(...generateUserJWTHeader()); + expect(statusCode).to.equal(403); + } + { + const { statusCode } = await request() + .delete(`/users/${user.id}`) + .set('Authorization', `Bearer ${user.emitJWT()}`); + expect(statusCode).to.equal(204); + } + } finally { + await User.deleteOne(dummyUser); + } + }); });