diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml new file mode 100644 index 000000000..945a62667 --- /dev/null +++ b/.github/workflows/demo.yml @@ -0,0 +1,48 @@ +name: Release to demo + +on: + release: + types: [created] + +# Environment variables available to all jobs and steps in this workflow +env: + GITHUB_SHA: ${{ github.sha }} + GKE_ZONE: europe-west4-c + GKE_CLUSTER: igrant-cluster + REGISTRY_HOSTNAME: eu.gcr.io + +jobs: + setup-build-publish-deploy: + name: Setup, Build, Publish, and Deploy + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Get the version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + + # Setup gcloud CLI + - uses: google-github-actions/setup-gcloud@v0 + with: + version: "270.0.0" + service_account_key: ${{ secrets.GKE_SA_KEY }} + project_id: ${{ secrets.GKE_PROJECT }} + + # Configure Docker to use the gcloud command-line tool as a credential + # helper for authentication + - run: |- + gcloud --quiet auth configure-docker + + # Get the GKE credentials so we can deploy to the cluster + - uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e + with: + cluster_name: ${{ env.GKE_CLUSTER }} + location: ${{ env.GKE_ZONE }} + credentials: ${{ secrets.GKE_SA_KEY }} + + # Build docker image, publish docker image to gcp container registry, deploy to production + - name: Build docker image, publish docker image to gcp container registry, deploy to production + run: | + make build/docker/deployable publish deploy/production diff --git a/.github/workflows/production-gke.yml b/.github/workflows/production-gke.yml deleted file mode 100644 index a6ee0cc5d..000000000 --- a/.github/workflows/production-gke.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: On release build and deploy privacy dashboard docker image to production cluster - -on: - release: - types: [created] - -# Environment variables available to all jobs and steps in this workflow -env: - GKE_PROJECT: ${{ secrets.GKE_PROJECT_JENKINS }} - GKE_EMAIL: ${{ secrets.GKE_EMAIL_JENKINS }} - GITHUB_SHA: ${{ github.sha }} - GKE_ZONE: europe-west3-c - GKE_CLUSTER: igrant-cluster - IMAGE: igrant-privacy - REGISTRY_HOSTNAME: eu.gcr.io - DEPLOYMENT_NAME: gke-test - -jobs: - setup-build-publish-deploy: - name: Setup, Build, Publish, and Deploy - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Get the version - id: get_version - run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - - # Setup gcloud CLI - - uses: google-github-actions/setup-gcloud@master - with: - version: '270.0.0' - service_account_email: ${{ secrets.GKE_EMAIL_JENKINS }} - service_account_key: ${{ secrets.GKE_KEY_JENKINS }} - - # Configure docker to use the gcloud command-line tool as a credential helper - - run: | - # Set up docker to authenticate - # via gcloud command-line tool. - gcloud auth configure-docker - - # Build the Docker image - - name: Build - run: | - docker build -t "$REGISTRY_HOSTNAME"/"$GKE_PROJECT"/"$IMAGE":"$GITHUB_SHA"-${{ steps.get_version.outputs.VERSION }}-release \ - --build-arg GITHUB_SHA="$GITHUB_SHA" \ - --build-arg GITHUB_REF="$GITHUB_REF" -f resources/docker/Dockerfile . - - # Push the Docker image to Google Container Registry - - name: Publish - run: | - docker push $REGISTRY_HOSTNAME/$GKE_PROJECT/$IMAGE:$GITHUB_SHA-${{ steps.get_version.outputs.VERSION }}-release diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 000000000..7c5ca31b5 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,60 @@ +name: Release to staging + +on: + push: + branches: + - main + +# Environment variables available to all jobs and steps in this workflow +env: + GITHUB_SHA: ${{ github.sha }} + GKE_ZONE: europe-west4-c + GKE_CLUSTER: igrant-cluster + REGISTRY_HOSTNAME: eu.gcr.io + +jobs: + setup-build-publish-deploy: + name: Setup, Build, Publish, and Deploy + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Get the version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + + - uses: sonarsource/sonarqube-scan-action@master + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + # If you wish to fail your job when the Quality Gate is red, uncomment the + # following lines. This would typically be used to fail a deployment. + # - uses: sonarsource/sonarqube-quality-gate-action@master + # timeout-minutes: 5 + # env: + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + # Setup gcloud CLI + - uses: google-github-actions/setup-gcloud@v0 + with: + version: "270.0.0" + service_account_key: ${{ secrets.GKE_SA_KEY }} + project_id: ${{ secrets.GKE_PROJECT }} + + # Configure Docker to use the gcloud command-line tool as a credential + # helper for authentication + - run: |- + gcloud --quiet auth configure-docker + + # Get the GKE credentials so we can deploy to the cluster + - uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e + with: + cluster_name: ${{ env.GKE_CLUSTER }} + location: ${{ env.GKE_ZONE }} + credentials: ${{ secrets.GKE_SA_KEY }} + + # Build docker image, publish docker image to gcp container registry, deploy to production + - name: Build docker image, publish docker image to gcp container registry, deploy to production + run: | + make build/docker/deployable publish deploy/staging diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..762628bb6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2025] [LCubed (iGrant.io), Sweden] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile index 5347445d0..7a4dd4c6c 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,14 @@ -PROJECT := igrant +PROJECT := bb-consent APP := privacy NAME = $(PROJECT)-$(APP) -PROJECT_PACKAGE := github.com/igrant/$(APP) - TERM_FLAGS ?= -ti EXTRA_RUN_ARGS ?= VERSION ?= $(shell git describe --tags --abbrev=0) CANDIDATE ?= "dev" -CONTAINER_PRIVACY ?= "igrant_privacy_dev" +CONTAINER_DASHBOARD ?= "bb-consent_privacy_dashboard_dev" CONTAINER_DEFAULT_RUN_FLAGS := \ --rm $(TERM_FLAGS) \ @@ -38,27 +36,21 @@ DOCKER_TAG := $(GIT_BRANCH)-$(shell date +%Y%m%d%H%M%S)-$(GIT_COMMIT) .PHONY: help help: @echo "------------------------------------------------------------------------" - @echo "iGrant privacy" + @echo "BB Consent Individual Privacy Dashboard" @echo "------------------------------------------------------------------------" @grep -E '^[0-9a-zA-Z_/%\-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -.bootstrap: - git clone git@github.com:L3-iGrant/bootstrap.git "$(CURDIR)/.bootstrap" - -.PHONY: bootstrap -bootstrap: .bootstrap ## Boostraps development environment - git -C $(CURDIR)/.bootstrap fetch --all --prune - git -C $(CURDIR)/.bootstrap reset --hard origin/master - make -C .bootstrap bootstrap +bootstrap: resources/ssl/development ## Boostraps development environment + make -C resources/ssl/development bootstrap setup: bootstrap ## Sets up development environment -run: ## Run privacy locally for development purposes +run: ## Run dashboard locally for development purposes docker run \ $(CONTAINER_DEFAULT_RUN_FLAGS) \ --expose 5000 \ -e VIRTUAL_HOST=$(APP).$(PROJECT).dev \ - --name "${CONTAINER_PRIVACY}" \ + --name "${CONTAINER_DASHBOARD}" \ $(DOCKER_IMAGE):dev .PHONY: build/docker/deployable @@ -72,15 +64,14 @@ build: ## Builds the docker image .PHONY: publish publish: $(DEPLOY_VERSION_F ILE) ## Publish latest production Docker image to docker hub - gcloud docker -- push $(DEPLOY_VERSION) + docker push $(DEPLOY_VERSION) deploy/production: $(DEPLOY_VERSION_FILE) ## Deploy to K8s cluster (e.g. make deploy/{preview,staging,production}) - kubectl set image deployment/igrant-privacy igrant-privacy=$(DEPLOY_VERSION) + kubectl set image deployment/demo-consent-bb-privacy-dashboard demo-consent-bb-privacy-dashboard=$(DEPLOY_VERSION) -n govstack-demo deploy/staging: $(DEPLOY_VERSION_FILE) ## Deploy to K8s cluster (e.g. make deploy/{preview,staging,staging}) - kubectl set image deployment/igrant-privacy igrant-privacy=$(DEPLOY_VERSION) -n staging + kubectl set image deployment/staging-consent-bb-privacy-dashboard staging-consent-bb-privacy-dashboard=$(DEPLOY_VERSION) -n govstack $(DEPLOY_VERSION_FILE): @echo "Missing '$(DEPLOY_VERSION_FILE)' file. Run 'make build/docker/deployable'" >&2 - exit 1 - + exit 1 \ No newline at end of file diff --git a/README.md b/README.md index ae78db6bf..d3dacd622 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,39 @@ -# privacyboard -This is the code for deploying privacy dashboard for organisations +

+ GovStack Consent BB Privacy Dashboard (WebClient) +

-# Installation +

+ + + +

-``` bash -# First Clone the repo -$ git clone https://github.com/L3-iGrant/privacyboard.git +

+ About • + Release Status • + Contributing • + Licensing +

-# go to app's directory -$ cd privacyboard +## About -# install app's dependencies -$ npm install -``` -## Basic usage +This repository hosts source code for the reference implementation of the GovStack Consent Building Block Privacy Dashboard (WebClient) towards individuals. -``` bash -# dev server with hot reload at http://localhost:3000 -$ npm start -``` -Navigate to [http://localhost:3000](http://localhost:3000). The app will automatically reload if you change any of the source files. +## Release Status -### Build +Refer to the [wiki page](https://github.com/decentralised-dataexchange/bb-consent-docs/wiki/wps-and-deliverables) for the latest status of the deliverables. -Run `build` to build the project. The build artifacts will be stored in the `build/` directory. +## Other resources -```bash -# build for production with minification -$ npm run build -``` -## What's included +* Wiki - https://github.com/decentralised-dataexchange/consent-dev-docs/wiki -Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this: +## Contributing -``` -privacyboard#v1.0.0 -├── config/ #config files -| ├── jest #jest config -| ├── env.js #node enviornment setup -| ├── paths.js #relative paths -| ├── webpack.config.dev #webpack config for developement enviornment -| ├── webpack.config.prod #webpack config for production enviornment -│ └── webpackDevServer.config.js #webpack developement server config -| -├── public/ #static files -| ├── favicon.ico #icon -| ├── manifest.json #manifest -│ └── index.html #html temlpate -| -├── scripts/ #scripts files -| ├── build.js #build script -| ├── start.js #start script -│ └── test.js #test script -| -├── src/ #project root -│ ├── assets/ #assets folder -│ ├── authorization/ #auth library -│ ├── Components/ #app components -│ ├── helper/ #translator script -│ ├── history/ #browser history -│ ├── localization/ #locale strings -│ ├── Provider/ #Mobx store -│ ├── services/ #API services -│ ├── app.config.js #app config file -│ ├── App.css -│ ├── App.js -│ ├── App.test.js -│ ├── index.js -│ └── serviceWorker.js #service worker -│ -├── .env -├── .gitignore -└── package.json -``` -# Configuration -```html - - +Feel free to improve the plugin and send us a pull request. If you find any problems, please create an issue in this repo. - - - - - - - - iGrant - - - +## Licensing +Copyright (c) 2023-25 - -
- - - +Licensed under the Apache 2.0 License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. - - - - - - - -``` -Now,Application is only run when invoking 'App.Init' method with config. -Make sure 'App.Init' is after all other js script tags.otherwise 'App' is not defined will occur. - -config is an Object having keys. -``` - organizationId:String, - baseUrl:String -``` \ No newline at end of file +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE for the specific language governing permissions and limitations under the License. \ No newline at end of file diff --git a/public/config/config.json b/public/config/config.json index 743fd29b9..239922707 100644 --- a/public/config/config.json +++ b/public/config/config.json @@ -1,9 +1,9 @@ { - "organizationId": "5c1509c75430460001af6232", - "baseUrl": "https://demo-api.igrant.io", - "logoUrl": "", - "subscriptionMethodId": 0, - "iamUrl": "https://staging-iam.igrant.io/auth/", - "iamRealm" : "igrant-users", - "redirectUri": "http://localhost:3000/login" -} \ No newline at end of file + "organizationId": "5c1509c75430460001af6232", + "baseUrl": "https://demo-api.igrant.io", + "logoUrl": "https://demo-api.igrant.io/v1/organizations/5c1509c75430460001af6232/image/5c150a315430460001af6234/web", + "subscriptionMethodId": 0, + "iamUrl": "https://iam.igrant.io/auth", + "iamRealm": "igrant-users", + "redirectUri": "https://privacy.igrant.io/login" +} diff --git a/resources/kubernetes/igrant-privacy.yaml b/resources/kubernetes/igrant-privacy.yaml deleted file mode 100644 index 3a5c3558d..000000000 --- a/resources/kubernetes/igrant-privacy.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# kubectl create configmap igrant-privacy-config-production --from-file config-production.json -# kubectl create secret tls tls-secret --key igrant_io.key --cert igrant_io_chained.crt -# -apiVersion: v1 -kind: Service -metadata: - name: igrant-privacy-svc - labels: - app: igrant-privacy -spec: - type: NodePort - ports: - - name: http - port: 80 - targetPort: 80 - selector: - app: igrant-privacy ---- - -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: igrant-privacy -spec: - replicas: 1 - template: - metadata: - labels: - app: igrant-privacy - spec: - containers: - - name: igrant-privacy - image: eu.gcr.io/jenkins-189019/igrant-privacy:master-20180305185219-b6d0c4a - ports: - - containerPort: 80 - -# Change the frontend ing with the path /admin point to igrant-privacy-svc diff --git a/resources/ssl/development/Makefile b/resources/ssl/development/Makefile new file mode 100644 index 000000000..1f6c9be38 --- /dev/null +++ b/resources/ssl/development/Makefile @@ -0,0 +1,10 @@ +recreate-cert: ## Recreates bb-consent.dev selfsigned certificate + openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout $(CURDIR)/scripts/docker-proxy/certs/bb-consent.dev.key -out $(CURDIR)/scripts/docker-proxy/certs/bb-consent.dev.crt -subj "/C=EU/ST=Europe/L=Europe/O=bb-consent Development/OU=DevOps Department/CN=*.bb-consent.dev" + +bootstrap: ## Bootstraps development environment (proxy) + @./scripts/docker-proxy/main.sh + +.DEFAULT_GOAL := help +.PHONY: help +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/resources/ssl/development/README.md b/resources/ssl/development/README.md new file mode 100644 index 000000000..bf3775afb --- /dev/null +++ b/resources/ssl/development/README.md @@ -0,0 +1,23 @@ +# Boostrap development environment + + +## Usage + + * Add this to your **Makefile** + +``` +.bootstrap: + git clone git@github.com:decentralised-dataexchange/bootstrap.git "$(CURDIR)/.bootstrap" + +.PHONY: bootstrap +bootstrap: .bootstrap ## Boostraps development environment + git -C $(CURDIR)/.bootstrap fetch --all --prune + git -C $(CURDIR)/.bootstrap reset --hard origin/master + make -C .bootstrap bootstrap +``` + + * Add this to your **.gitignore** + +``` +/.bootstrap/ +``` diff --git a/resources/ssl/development/scripts/docker-proxy/certs/README.md b/resources/ssl/development/scripts/docker-proxy/certs/README.md new file mode 100644 index 000000000..e7b5b6bc7 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/README.md @@ -0,0 +1,11 @@ +The certificates are generated by following guidelines + +https://fabianlee.org/2018/02/17/ubuntu-creating-a-trusted-ca-and-san-certificate-using-openssl-on-ubuntu/ + +Nginx needs chained certs and key separately + +mv bb-consent.dev.key.pem bb-consent.dev.key +cat $prefix.crt ca.pem > bb-consent.dev.crt + +After that we need to add ca.pem to the browser + diff --git a/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev-ca-full.pem b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev-ca-full.pem new file mode 100644 index 000000000..9d060b15c --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev-ca-full.pem @@ -0,0 +1,68 @@ +-----BEGIN CERTIFICATE----- +MIIDSTCCAjGgAwIBAgIUMfo2fADylmRGPKXskZbfaiGfPF4wDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwHhcNMjMwODIyMTk1MzI2WhcN +MzMwODE5MTk1MzI2WjAZMRcwFQYDVQQDDA5iYi1jb25zZW50LmRldjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqRiII6LJPXeNhcfFzrOMMXbXjShQ1A +VrhGKOPsDar/kjLlsdtbCoLij+4LG9Bwt5aZwqUXBAQqmI6UkhtAw4noe3T2eujY +EMQgR27S9DslIdLTWMNTj9IVdjRlVhxDhHvGbjhU4wkZCVK/gCrwntLPkV8lPDaN +bkY4+UzwtPOFH1do5MIjN89Sn0q7aMO/LCBWKX8+M99ykq1vuySlrgcAdar+zG4X +Ea+dO+I9r9Y2SRltpCP2xbBcmulGtR4FU9B8Oy/FyKbRWsUbWuVw4g0KcbmlqEqW +zyNJGOiw6bSj9q7XpSpA0IMXeVc8KXKWCiYrTDiCEUgm/0pN5gwQj3MCAwEAAaOB +iDCBhTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DArBgNVHREEJDAigg5iYi1jb25z +ZW50LmRldoIQKi5iYi1jb25zZW50LmRldjAdBgNVHQ4EFgQUg560HcXKx6FJqw6O +3QSYCYSlQrwwHwYDVR0jBBgwFoAUuOMxPpr5BVM8WHE73K0qfLu+PvYwDQYJKoZI +hvcNAQELBQADggEBAHNGdYV4QxfgEchOwf0K+qWc8oUZOOIMJHhnR1Se8IuiN81/ +2NWchusdPG/yp8i7WyFYs9JrLkUGyNRWuyDBoemJy7hrfKgEWoWludffvBLr01bs +ITEqAYAHZlA5IjnC5tlSxRn7tmHa2EC51dX8Kx/fSuQ/4B1GGvjCM2FjeVZYlns7 +/bnmSd1H39j1H6hNJXEErmQUzXFO7kQ3B1w2THuRRmx2EmdZXCgz+P2dG6Aa8EO3 +ESZ6/lF+X5UkH0a9d8kO4VD+otq+rY6un58BN2nV7Zdo7BwwWS1Lx5QgB68rKg9N +nzjSJ0s23tbb0qCFHALhF178N+XgQO9epNy34Mk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOTCCAiGgAwIBAgIUA6UwWdrX0TB7MRQ74TnQSFrID0UwDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwHhcNMjMwODIyMTk1MTQwWhcN +MzMwODE5MTk1MTQwWjAZMRcwFQYDVQQDDA5iYi1jb25zZW50LmRldjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMNfgST/hc36Jw7J/pFR8zFyF7X7y7i5 +CED8TqqZm1D3Iq85AL6X20BIJGSgzrklOiX4FEws3HYNJqLcLvg4pOFQcqF40C98 +fth2c7rB+/AJbNnIAAgiwx+dieqcHgkJ1w9q6e5ulfvcSC/wXLiOoe34Eou6rN3Y ++xzHEd7LEpn4H4DwYMOtEYUc2WVN/rKU3SThexxHmhSAWYLImUhnvR8LJxkHhzyj +NCdKLhmWWww5bitip5zGrJbjeqYKbyY7MdPbznCHKHa57dgxUFYwPynilXmTt3MD +he0G887yosz828oJ84ZHlMRUlcs/sTFEH2XBT/jmb2UKxfMxK7uIoI0CAwEAAaN5 +MHcwHQYDVR0OBBYEFLjjMT6a+QVTPFhxO9ytKny7vj72MB8GA1UdIwQYMBaAFLjj +MT6a+QVTPFhxO9ytKny7vj72MBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/ +BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAhzsT +TWkgjsKc5O2bG19aogk5NJPH4MJ8xNn1pqLtBgdLcODa4pxUprBR8xXLpqARDqxZ +oUBG2eWJStfp+SHpLJn9hfopw1s0ftyKHxXJ6nQCSe6zUimfm2BxOSkmB2/vq9qN +lRn57orISIPJfSgVaqidR35Pxfsa4HZctxhzH2eLKBQkttiE1INGME7LdwPL4ks7 +TQsoDVX4b2gs2gaaNZSMDiScZZQ2uzohmrtd6qrbAlz10vqrjP0ztx6ylzbLXWTQ +fqAfJK9L/my6QWGtq26LWEbbH60qATXmULYwqF4uJHCbSIBLfNSURgn+cCUWfh3x +qT5ISfE8Re4JwnGQXQ== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqkYiCOiyT13jY +XHxc6zjDF2140oUNQFa4Rijj7A2q/5Iy5bHbWwqC4o/uCxvQcLeWmcKlFwQEKpiO +lJIbQMOJ6Ht09nro2BDEIEdu0vQ7JSHS01jDU4/SFXY0ZVYcQ4R7xm44VOMJGQlS +v4Aq8J7Sz5FfJTw2jW5GOPlM8LTzhR9XaOTCIzfPUp9Ku2jDvywgVil/PjPfcpKt +b7skpa4HAHWq/sxuFxGvnTviPa/WNkkZbaQj9sWwXJrpRrUeBVPQfDsvxcim0VrF +G1rlcOINCnG5pahKls8jSRjosOm0o/au16UqQNCDF3lXPClylgomK0w4ghFIJv9K +TeYMEI9zAgMBAAECggEANru4mEFeqJpOFu+moJKChmfwIwM62sO4kC1DVdAbmrGk +El0Os5sFRna5ROOfq0VgRB1XDm7SRRv+FFKsh75CgPBvHVsymaEr0COjiHZ9FLWX +ovVa2GLqFbn5UlrqROuNicJlAAKNUBAOo9T7pcvMy0z8ExH5vm+n4TTLGttq1XFt +WTPIyEGPyHH5n+djrvxmWrDPdxlVxCnZ2k48yE2/kK34pBScdNqKxslgA8GHuExB +Us2eZ6a6FN4VXzxWLrAA8X2s1FLCIE6JZ91yTD5PPZ3DqkoYMHUdlBmRCZxzFjlN +Rg7bkRh/WOHmqAysNQDp/jJtXOZdKC9pTnrMXyC3kQKBgQC6IcchvUJo/AlwbmU3 +A+nXRkt1EZXwaQaIlkTXesdU6O1YuzRI2e1UQm6ZNIgGHt1jvTR7U0CnUmrcrnEH +sUjrpAktknm+ZAZ8YZT3//UFILj82yXn/wYWKs59Js/cE106FtoXY55gzfbtayfm +xI1dzrLpW7s4anCy57n6xrl19wKBgQDqmDIcRYmTOc+AAglc4t3P3BKdi0beSTdB +uDdj1u1GH0wwUMuaX5ArNihxGJINBr2MMRIFOuVHyOUg/Hac21zaSlCM/l7H+kgP +asUNJymURmlAYM17jyikaFwpcA7Qx9w6cmX6pw6HKRKgTO+2t7XDKjSi2jMKc9kY +Ygp5ek3jZQKBgEHFac48SFk8pkE6YT2dfmX5ivRlMGxxUEO3hb/2vLT+UdBG5mTP +zRM3Hkm4zFANXAHAe+kQNApsDyLH6VzkgnXx0uRtm+NxCPGusasooPYc6AFBlxVx +gj8XBTwoGM8VcJ30MUCOjQp7/UNL2B+tWJ7LSWE4buGyivxM8eTxj9tlAoGBAJn5 +sRI7VfQLArWrIIgV466VbKZ5DtfBSIJbLgfavrvCuRgRP8GgLZkfH+YzUVE5dlm4 +r3I9WNYH9tPywMttc4FXO41/O6iYDooH8zQR20mV+Wkm4FfT+8IFOVB9W0wPke3O +vj6JPZDbFX2fYcsUwzlIz2mAO/YFWZ2WY/ednde9AoGAcfivRBchXf84YugubnOU +vySZWcXra7lJRGn2uq2IVrCAMuly8S7omau5E0lFZVAScT33GAdvItbIFIDsSo+O +MuF5c53ZHeVPREH3ZVzDMxpslxZf7DrcdREV7Xu7mQKHyr6iX1tgBYvthz2nBGHU +mctqGLLXv8wOg1Jk9viDaZw= +-----END PRIVATE KEY----- diff --git a/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.cnf b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.cnf new file mode 100644 index 000000000..2dea29374 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.cnf @@ -0,0 +1,409 @@ +# +# OpenSSL example configuration file. +# See doc/man5/config.pod for more info. +# +# This is mostly being used for generation of certificate requests, +# but may be used for auto loading of providers + +# Note that you can include other files from the main configuration +# file using the .include directive. +#.include filename + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . + + # Use this in order to automatically load providers. +openssl_conf = openssl_init + +# Comment out the next line to ignore configuration errors +config_diagnostics = 1 + +# Extra OBJECT IDENTIFIER info: +# oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +# For FIPS +# Optionally include a file that is generated by the OpenSSL fipsinstall +# application. This file contains configuration data required by the OpenSSL +# fips provider. It contains a named section e.g. [fips_sect] which is +# referenced from the [provider_sect] below. +# Refer to the OpenSSL security policy for more information. +# .include fipsmodule.cnf + +[openssl_init] +providers = provider_sect +ssl_conf = ssl_sect + +# List of providers to load +[provider_sect] +default = default_sect +# The fips section name should match the section name inside the +# included fipsmodule.cnf. +# fips = fips_sect + +# If no providers are activated explicitly, the default one is activated implicitly. +# See man 7 OSSL_PROVIDER-default for more details. +# +# If you add a section explicitly activating any other provider(s), you most +# probably need to explicitly activate the default provider, otherwise it +# becomes unavailable in openssl. As a consequence applications depending on +# OpenSSL may not work correctly which could lead to significant system +# problems including inability to remotely access the system. +[default_sect] +# activate = 1 + + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certs with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key + +x509_extensions = usr_cert # The extensions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +req_extensions = v3_req + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +#extendedKeyUsage=serverAuth +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = bb-consent.dev +DNS.2 = *.bb-consent.dev + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +basicConstraints = critical,CA:true + +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer +basicConstraints = critical, CA:TRUE, pathlen:3 +keyUsage = critical, cRLSign, keyCertSign +nsCertType = sslCA, emailCA + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) +signer_digest = sha256 # Signing digest to use. (Optional) +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) +ess_cert_id_alg = sha1 # algorithm to compute certificate + # identifier (optional, default: sha1) + +[insta] # CMP using Insta Demo CA +# Message transfer +server = pki.certificate.fi:8700 +# proxy = # set this as far as needed, e.g., http://192.168.1.1:8080 +# tls_use = 0 +path = pkix/ + +# Server authentication +recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA" # or set srvcert or issuer +ignore_keyusage = 1 # potentially needed quirk +unprotected_errors = 1 # potentially needed quirk +extracertsout = insta.extracerts.pem + +# Client authentication +ref = 3078 # user identification +secret = pass:insta # can be used for both client and server side + +# Generic message options +cmd = ir # default operation, can be overridden on cmd line with, e.g., kur + +# Certificate enrollment +subject = "/CN=openssl-cmp-test" +newkey = insta.priv.pem +out_trusted = insta.ca.crt +certout = insta.cert.pem + +[pbm] # Password-based protection for Insta CA +# Server and client authentication +ref = $insta::ref # 3078 +secret = $insta::secret # pass:insta + +[signature] # Signature-based protection for Insta CA +# Server authentication +trusted = insta.ca.crt # does not include keyUsage digitalSignature + +# Client authentication +secret = # disable PBM +key = $insta::newkey # insta.priv.pem +cert = $insta::certout # insta.cert.pem + +[ir] +cmd = ir + +[cr] +cmd = cr + +[kur] +# Certificate update +cmd = kur +oldcert = $insta::certout # insta.cert.pem + +[rr] +# Certificate revocation +cmd = rr +oldcert = $insta::certout # insta.cert.pem + +[ssl_sect] +system_default = system_default_sect + +[system_default_sect] +CipherString = DEFAULT:@SECLEVEL=2 diff --git a/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.crt b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.crt new file mode 100644 index 000000000..375ccbdc1 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.crt @@ -0,0 +1,40 @@ +-----BEGIN CERTIFICATE----- +MIIDSTCCAjGgAwIBAgIUMfo2fADylmRGPKXskZbfaiGfPF4wDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwHhcNMjMwODIyMTk1MzI2WhcN +MzMwODE5MTk1MzI2WjAZMRcwFQYDVQQDDA5iYi1jb25zZW50LmRldjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKqRiII6LJPXeNhcfFzrOMMXbXjShQ1A +VrhGKOPsDar/kjLlsdtbCoLij+4LG9Bwt5aZwqUXBAQqmI6UkhtAw4noe3T2eujY +EMQgR27S9DslIdLTWMNTj9IVdjRlVhxDhHvGbjhU4wkZCVK/gCrwntLPkV8lPDaN +bkY4+UzwtPOFH1do5MIjN89Sn0q7aMO/LCBWKX8+M99ykq1vuySlrgcAdar+zG4X +Ea+dO+I9r9Y2SRltpCP2xbBcmulGtR4FU9B8Oy/FyKbRWsUbWuVw4g0KcbmlqEqW +zyNJGOiw6bSj9q7XpSpA0IMXeVc8KXKWCiYrTDiCEUgm/0pN5gwQj3MCAwEAAaOB +iDCBhTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DArBgNVHREEJDAigg5iYi1jb25z +ZW50LmRldoIQKi5iYi1jb25zZW50LmRldjAdBgNVHQ4EFgQUg560HcXKx6FJqw6O +3QSYCYSlQrwwHwYDVR0jBBgwFoAUuOMxPpr5BVM8WHE73K0qfLu+PvYwDQYJKoZI +hvcNAQELBQADggEBAHNGdYV4QxfgEchOwf0K+qWc8oUZOOIMJHhnR1Se8IuiN81/ +2NWchusdPG/yp8i7WyFYs9JrLkUGyNRWuyDBoemJy7hrfKgEWoWludffvBLr01bs +ITEqAYAHZlA5IjnC5tlSxRn7tmHa2EC51dX8Kx/fSuQ/4B1GGvjCM2FjeVZYlns7 +/bnmSd1H39j1H6hNJXEErmQUzXFO7kQ3B1w2THuRRmx2EmdZXCgz+P2dG6Aa8EO3 +ESZ6/lF+X5UkH0a9d8kO4VD+otq+rY6un58BN2nV7Zdo7BwwWS1Lx5QgB68rKg9N +nzjSJ0s23tbb0qCFHALhF178N+XgQO9epNy34Mk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOTCCAiGgAwIBAgIUA6UwWdrX0TB7MRQ74TnQSFrID0UwDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwHhcNMjMwODIyMTk1MTQwWhcN +MzMwODE5MTk1MTQwWjAZMRcwFQYDVQQDDA5iYi1jb25zZW50LmRldjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMNfgST/hc36Jw7J/pFR8zFyF7X7y7i5 +CED8TqqZm1D3Iq85AL6X20BIJGSgzrklOiX4FEws3HYNJqLcLvg4pOFQcqF40C98 +fth2c7rB+/AJbNnIAAgiwx+dieqcHgkJ1w9q6e5ulfvcSC/wXLiOoe34Eou6rN3Y ++xzHEd7LEpn4H4DwYMOtEYUc2WVN/rKU3SThexxHmhSAWYLImUhnvR8LJxkHhzyj +NCdKLhmWWww5bitip5zGrJbjeqYKbyY7MdPbznCHKHa57dgxUFYwPynilXmTt3MD +he0G887yosz828oJ84ZHlMRUlcs/sTFEH2XBT/jmb2UKxfMxK7uIoI0CAwEAAaN5 +MHcwHQYDVR0OBBYEFLjjMT6a+QVTPFhxO9ytKny7vj72MB8GA1UdIwQYMBaAFLjj +MT6a+QVTPFhxO9ytKny7vj72MBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/ +BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAhzsT +TWkgjsKc5O2bG19aogk5NJPH4MJ8xNn1pqLtBgdLcODa4pxUprBR8xXLpqARDqxZ +oUBG2eWJStfp+SHpLJn9hfopw1s0ftyKHxXJ6nQCSe6zUimfm2BxOSkmB2/vq9qN +lRn57orISIPJfSgVaqidR35Pxfsa4HZctxhzH2eLKBQkttiE1INGME7LdwPL4ks7 +TQsoDVX4b2gs2gaaNZSMDiScZZQ2uzohmrtd6qrbAlz10vqrjP0ztx6ylzbLXWTQ +fqAfJK9L/my6QWGtq26LWEbbH60qATXmULYwqF4uJHCbSIBLfNSURgn+cCUWfh3x +qT5ISfE8Re4JwnGQXQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.csr b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.csr new file mode 100644 index 000000000..4b2136b17 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqkYiCOiyT13jYXHxc6zjDF2140oUNQFa4 +Rijj7A2q/5Iy5bHbWwqC4o/uCxvQcLeWmcKlFwQEKpiOlJIbQMOJ6Ht09nro2BDE +IEdu0vQ7JSHS01jDU4/SFXY0ZVYcQ4R7xm44VOMJGQlSv4Aq8J7Sz5FfJTw2jW5G +OPlM8LTzhR9XaOTCIzfPUp9Ku2jDvywgVil/PjPfcpKtb7skpa4HAHWq/sxuFxGv +nTviPa/WNkkZbaQj9sWwXJrpRrUeBVPQfDsvxcim0VrFG1rlcOINCnG5pahKls8j +SRjosOm0o/au16UqQNCDF3lXPClylgomK0w4ghFIJv9KTeYMEI9zAgMBAAGgADAN +BgkqhkiG9w0BAQsFAAOCAQEAArjV+HgI1F6HqYnHr3fuwXV8LrMfcQeEw1o1IoCO +xV2N+dCmHI7U9P48eDukhAb+nuo4jMEQOlHPQTHkfFvAaE2ZoakNEaS6ZRerTLLn +a3N06piYnmbMxZ8klWnREt730yTGiHtQ5cmcpDO5FIA6whJRJ9avYAEkfzvy3CIp +r8jppQkID7C9jF+gsueyuL3whKzrrS2rtyac4gs4xBDwKWdyQ+qDRrpC+dASX80Q +OWl65iPCHE4l1RNSZu2Wj5q+8hfc2ApzP70R+0geH28Fw0usqDZr4iuNUSYMS7Jg +UlC7CKDUnjQBmaFCuFL4zLOBTf3uYYnS6lru8u8KsyJqUg== +-----END CERTIFICATE REQUEST----- diff --git a/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.key b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.key new file mode 100644 index 000000000..0ed99d495 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/bb-consent.dev.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqkYiCOiyT13jY +XHxc6zjDF2140oUNQFa4Rijj7A2q/5Iy5bHbWwqC4o/uCxvQcLeWmcKlFwQEKpiO +lJIbQMOJ6Ht09nro2BDEIEdu0vQ7JSHS01jDU4/SFXY0ZVYcQ4R7xm44VOMJGQlS +v4Aq8J7Sz5FfJTw2jW5GOPlM8LTzhR9XaOTCIzfPUp9Ku2jDvywgVil/PjPfcpKt +b7skpa4HAHWq/sxuFxGvnTviPa/WNkkZbaQj9sWwXJrpRrUeBVPQfDsvxcim0VrF +G1rlcOINCnG5pahKls8jSRjosOm0o/au16UqQNCDF3lXPClylgomK0w4ghFIJv9K +TeYMEI9zAgMBAAECggEANru4mEFeqJpOFu+moJKChmfwIwM62sO4kC1DVdAbmrGk +El0Os5sFRna5ROOfq0VgRB1XDm7SRRv+FFKsh75CgPBvHVsymaEr0COjiHZ9FLWX +ovVa2GLqFbn5UlrqROuNicJlAAKNUBAOo9T7pcvMy0z8ExH5vm+n4TTLGttq1XFt +WTPIyEGPyHH5n+djrvxmWrDPdxlVxCnZ2k48yE2/kK34pBScdNqKxslgA8GHuExB +Us2eZ6a6FN4VXzxWLrAA8X2s1FLCIE6JZ91yTD5PPZ3DqkoYMHUdlBmRCZxzFjlN +Rg7bkRh/WOHmqAysNQDp/jJtXOZdKC9pTnrMXyC3kQKBgQC6IcchvUJo/AlwbmU3 +A+nXRkt1EZXwaQaIlkTXesdU6O1YuzRI2e1UQm6ZNIgGHt1jvTR7U0CnUmrcrnEH +sUjrpAktknm+ZAZ8YZT3//UFILj82yXn/wYWKs59Js/cE106FtoXY55gzfbtayfm +xI1dzrLpW7s4anCy57n6xrl19wKBgQDqmDIcRYmTOc+AAglc4t3P3BKdi0beSTdB +uDdj1u1GH0wwUMuaX5ArNihxGJINBr2MMRIFOuVHyOUg/Hac21zaSlCM/l7H+kgP +asUNJymURmlAYM17jyikaFwpcA7Qx9w6cmX6pw6HKRKgTO+2t7XDKjSi2jMKc9kY +Ygp5ek3jZQKBgEHFac48SFk8pkE6YT2dfmX5ivRlMGxxUEO3hb/2vLT+UdBG5mTP +zRM3Hkm4zFANXAHAe+kQNApsDyLH6VzkgnXx0uRtm+NxCPGusasooPYc6AFBlxVx +gj8XBTwoGM8VcJ30MUCOjQp7/UNL2B+tWJ7LSWE4buGyivxM8eTxj9tlAoGBAJn5 +sRI7VfQLArWrIIgV466VbKZ5DtfBSIJbLgfavrvCuRgRP8GgLZkfH+YzUVE5dlm4 +r3I9WNYH9tPywMttc4FXO41/O6iYDooH8zQR20mV+Wkm4FfT+8IFOVB9W0wPke3O +vj6JPZDbFX2fYcsUwzlIz2mAO/YFWZ2WY/ednde9AoGAcfivRBchXf84YugubnOU +vySZWcXra7lJRGn2uq2IVrCAMuly8S7omau5E0lFZVAScT33GAdvItbIFIDsSo+O +MuF5c53ZHeVPREH3ZVzDMxpslxZf7DrcdREV7Xu7mQKHyr6iX1tgBYvthz2nBGHU +mctqGLLXv8wOg1Jk9viDaZw= +-----END PRIVATE KEY----- diff --git a/resources/ssl/development/scripts/docker-proxy/certs/ca.key.pem b/resources/ssl/development/scripts/docker-proxy/certs/ca.key.pem new file mode 100644 index 000000000..8193c9c38 --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/ca.key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,323E1A8DB4120043C513483091306FBE + +XVvkqE4ofPOwQX8WoFh4/3U5Aoz/6TsCtxHL2p6c/aOT5vtuNQVtjk7NY2kzl9T/ +QC4AuscH3bUIW5o5inQDZZNz7u6J38IoDNIvrWiRR9mMkZ0E6ug9sMCraTd0/BYj +o27v52jROVThgrSI/OItPtcil8bIAwE3z/rwlRKvjsmGMvUPqBAvTHam/aGEKrjn +DDvjDt11pCCbzjbYPmfTL3BzA/odKUHxjlDOa6SCCvuMxSOgkB5nVA7N3WvAo6Sm +gQiURQKayfQkThJ7VwRkF+vKA8YvjiBIAkrSpnKe/mdyRaN6BLz5ODntrwYPjPw5 +EqoVcDA3Wa+VQLdUcc5wAXJRkaIh2dzji66BX3dyhGjDLE/07eoHnK2NEDI9lc4V ++3uwH+vISzxy0KNVz10aeAPiTBVoKgMCdLjb0gIfyU5Utt2J6sWXLtEGk5VX5BE6 +Qu2FBBO5ALtNDHCrXos5TuowVW8i+hBNf8A6bX2D/Pgn/pYN/gZkZNiFY9FTCQf9 +E4jXR40S/kXHB25NJP2U4kKIEfCHzVLESS1rYmmMtiFrE/Pus4Vy4ZoDupLqHJSH +M4fne9663dheR258x23mlSAhPwumE5x7u99WRJ5Itj7XkOZorgc9rF8WU0ws3hYh +9kb/y/QRRId5MiqCic5BlIC7PdIsMC1meCjMVRkBI+U4BBGrAATvUThMSSnw1+Bu ++xDtK3unPLVKYcnD8oxg0sfkfkdxQ6rSEyrMv47aaRCtLDEJZLJWE5PrUnn8x6UV +GcKE1xdQsmwkW3VCUq7f6viwvYtT6aBUN+EUQunQtgmt/8CY2moIp1nYMXFjOoKd +13uc+Ge4fQiwczDumMfhDfruxOwciKu6zbsFQpjlPDh/vwP3miLtW3dgzoqQDrv2 +/kjBo2MTPbpFgG27tt611J3Q4TMfy9I7ID6jhS0SlXmrL6dYVee3v5gZkkKvEUGt +hgSWNod7on7I8nvaU7oTZu3yQcBabQnHQGCYYQKUXSy7LQ+cC4pmXhzEpOB32ihf +A+xVYtvLr06gqQL1tClYpntOv5KH7Eu8Tu0WF83P16lRtBo+rXGnm2UY4i96YMri +et33PDiD9W69SCUi7xe6uSrhOZuMWjPaNplXCvKcfZ6s3nrKyu3kAUNIHoirvBfe +cFfbt6vm/HO0GbE1mkNpVZwUKUY73+GJKYe7EJd4v1pkJdydgo99jgOGPE+REfrn +HxLxhpLTCCBcFDoepfBz1kPdjs+LHf9RXM+jum9rIY2sm0busfXmExW+NoQ/IT4O +XCvHnlJjaack947zM/CeJ1n55YyK78zs82+qZp6akMyPOaY8zfFSOXMj6KMuT1YS +HHtx4i0MjM/jUK+weKL1gvD/kPDeodiNC4I5jNPTkiTqNMi88ot4Vc9kbtP8RuiC +tmTXzpMV+uB+YZUiK1Imc5226fL27glTX/f3PiG/0EG5eYiaDpYzLjAhd8QuRKih +3gjgRlqqFJQvV+oJv+KTJq6u6Hoju4E2hS9mgUBAN6jzcKisC1wlEeJbMRbR8mT8 +YoCOjxfCLv+X5x2pfg6+NEUAUwpZiDY48neN8LYquDwv+UNgFl8p3fT5TlqBYslt +-----END RSA PRIVATE KEY----- diff --git a/resources/ssl/development/scripts/docker-proxy/certs/ca.pem b/resources/ssl/development/scripts/docker-proxy/certs/ca.pem new file mode 100644 index 000000000..bc1dec79c --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/certs/ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOTCCAiGgAwIBAgIUA6UwWdrX0TB7MRQ74TnQSFrID0UwDQYJKoZIhvcNAQEL +BQAwGTEXMBUGA1UEAwwOYmItY29uc2VudC5kZXYwHhcNMjMwODIyMTk1MTQwWhcN +MzMwODE5MTk1MTQwWjAZMRcwFQYDVQQDDA5iYi1jb25zZW50LmRldjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMNfgST/hc36Jw7J/pFR8zFyF7X7y7i5 +CED8TqqZm1D3Iq85AL6X20BIJGSgzrklOiX4FEws3HYNJqLcLvg4pOFQcqF40C98 +fth2c7rB+/AJbNnIAAgiwx+dieqcHgkJ1w9q6e5ulfvcSC/wXLiOoe34Eou6rN3Y ++xzHEd7LEpn4H4DwYMOtEYUc2WVN/rKU3SThexxHmhSAWYLImUhnvR8LJxkHhzyj +NCdKLhmWWww5bitip5zGrJbjeqYKbyY7MdPbznCHKHa57dgxUFYwPynilXmTt3MD +he0G887yosz828oJ84ZHlMRUlcs/sTFEH2XBT/jmb2UKxfMxK7uIoI0CAwEAAaN5 +MHcwHQYDVR0OBBYEFLjjMT6a+QVTPFhxO9ytKny7vj72MB8GA1UdIwQYMBaAFLjj +MT6a+QVTPFhxO9ytKny7vj72MBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/ +BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAhzsT +TWkgjsKc5O2bG19aogk5NJPH4MJ8xNn1pqLtBgdLcODa4pxUprBR8xXLpqARDqxZ +oUBG2eWJStfp+SHpLJn9hfopw1s0ftyKHxXJ6nQCSe6zUimfm2BxOSkmB2/vq9qN +lRn57orISIPJfSgVaqidR35Pxfsa4HZctxhzH2eLKBQkttiE1INGME7LdwPL4ks7 +TQsoDVX4b2gs2gaaNZSMDiScZZQ2uzohmrtd6qrbAlz10vqrjP0ztx6ylzbLXWTQ +fqAfJK9L/my6QWGtq26LWEbbH60qATXmULYwqF4uJHCbSIBLfNSURgn+cCUWfh3x +qT5ISfE8Re4JwnGQXQ== +-----END CERTIFICATE----- diff --git a/resources/ssl/development/scripts/docker-proxy/main.sh b/resources/ssl/development/scripts/docker-proxy/main.sh new file mode 100755 index 000000000..d72ea966e --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/main.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# set -x +set -e +set -u + +## Settings +readonly RESOLVER_TLD="dev" +readonly DOCKER_VM_NAME="docker-vm" +readonly CONTAINER_NGINX="proxy_nginx" +readonly CONTAINER_DNSMASQ="proxy_dns" + +readonly ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +## Flags +readonly FLAG_OSX=1 +readonly FLAG_LINUX=2 +readonly FLAG_DOCKER_MACHINE=4 +readonly FLAG_DOCKER_BETA=8 +readonly FLAG_DOCKER_UNKNOWN=16 +readonly FLAG_PROXY_NGINX=32 +readonly FLAG_PROXY_DNS=64 + +readonly BB_CONSENT_DOMAIN="bb-consent.dev" +readonly BB_CONSENT_SUBDOMAINS="api.${BB_CONSENT_DOMAIN} dashboard.${BB_CONSENT_DOMAIN} privacy.${BB_CONSENT_DOMAIN} docs.${BB_CONSENT_DOMAIN}" +ENVIRONMENT_FLAGS=0 +DOCKER_IP=127.0.0.1 + + +function detect_flags { + which docker > /dev/null || (echo "docker command not found"; exit 1) + + ENVIRONMENT_FLAGS=$FLAG_PROXY_NGINX + ## OS + case $(uname -s) in + "Darwin") + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_OSX + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_PROXY_DNS + ;; + "Linux") + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_LINUX + ;; + *) + echo "Unsupported OS" + exit 1 + ;; + esac + + if (((ENVIRONMENT_FLAGS & FLAG_OSX)>0)); then + case $(docker info 2>/dev/null | sed -n "s/Operating System: \(.*\)/\1/p") in + "Alpine Linux v"*) + # Docker beta + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_DOCKER_BETA + ;; + "Boot2Docker "*) + # Docker machine + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_DOCKER_MACHINE + ;; + *) + ENVIRONMENT_FLAGS=$ENVIRONMENT_FLAGS+$FLAG_DOCKER_UNKNOWN + ;; + esac + fi +} + +function create_proxy_dns { + local host_ip=$1 + + if [[ -z "${host_ip}" ]]; then + echo "misssing host ip" + exit 1 + fi + + (docker ps -af "name=${CONTAINER_DNSMASQ}" | grep "${CONTAINER_DNSMASQ}"> /dev/null) && docker rm -f "${CONTAINER_DNSMASQ}" > /dev/null + docker run \ + -d \ + -p "${host_ip}:53:53/tcp" \ + -p "${host_ip}:53:53/udp" \ + --cap-add NET_ADMIN \ + --restart "always" \ + --name "${CONTAINER_DNSMASQ}" \ + andyshinn/dnsmasq \ + "--address=/${RESOLVER_TLD}/${host_ip}" \ + > /dev/null + + echo "Create resolver directory" + sudo mkdir -p /etc/resolver && sudo chmod 755 /etc/resolver + + echo "Create ${RESOLVER_TLD} resolver file at /etc/resolver/${RESOLVER_TLD}" + echo "nameserver ${host_ip}" | sudo tee "/etc/resolver/${RESOLVER_TLD}" > /dev/null + + set +e + sleep 1 + ping -c1 "undefined.${RESOLVER_TLD}" > /dev/null 2>&1 + pingExitCode=$? + set -e + if [[ $pingExitCode -gt 0 ]]; then + echo "Problem resolving .${RESOLVER_TLD} TLD" + exit 1 + fi + + echo "TLD ${RESOLVER_TLD} points to ${host_ip}" + echo +} + +function create_proxy_nginx { + local host_ip=$1 + + if [[ -z "${host_ip}" ]]; then + echo "misssing host ip" + exit 1 + fi + (docker ps -af "name=${CONTAINER_NGINX}" | grep "${CONTAINER_NGINX}" > /dev/null) && docker rm -f "${CONTAINER_NGINX}" > /dev/null + docker run \ + -d \ + -p "${host_ip}:443:443" \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + -v "${ROOT_DIR}/certs":/etc/nginx/certs:ro \ + -v "${ROOT_DIR}/vhost.d":/etc/nginx/vhost.d:ro \ + -v "${ROOT_DIR}/proxy.conf":/etc/nginx/proxy.conf:ro \ + --restart "always" \ + --name "${CONTAINER_NGINX}" \ + jwilder/nginx-proxy \ + > /dev/null +} + +function set_hosts { + local host_ip=$1 + + if [[ -z "${host_ip}" ]]; then + echo "misssing host ip" + exit 1 + fi + sed "/# bb-consent/d" /etc/hosts | sudo tee /etc/hosts > /dev/null + echo -e "${host_ip}\t${BB_CONSENT_SUBDOMAINS} # bb-consent" | sudo tee -a /etc/hosts > /dev/null +} + +detect_flags + +## Prepare environment +if ! docker info >/dev/null 2>&1; then + echo "Docker daemon is not running" + if (( (ENVIRONMENT_FLAGS & FLAG_OSX)>0 )); then + echo "Options:" + echo + + set +e + docker-machine inspect "${DOCKER_VM_NAME}" > /dev/null 2>&1 + machineExitCode=$? + set -e + + if [[ $machineExitCode -gt 0 ]]; then + echo " - start docker beta" + echo " - create docker machine: run 'docker-machine create --driver virtualbox --virtualbox-memory 2048 ${DOCKER_VM_NAME}'" + elif [[ -z "${DOCKER_HOST:-}" ]]; then + echo " - set docker env: run 'eval \$(docker-machine env ${DOCKER_VM_NAME})'" + else + echo " - start docker machine: run 'docker-machine start ${DOCKER_VM_NAME}'" + fi + + echo + fi + exit 1 +fi + +if (( (ENVIRONMENT_FLAGS & FLAG_DOCKER_MACHINE)>0 )); then + DOCKER_IP=$(docker-machine ip "${DOCKER_VM_NAME}") +fi + +if (( (ENVIRONMENT_FLAGS & FLAG_PROXY_NGINX)>0 )); then + create_proxy_nginx "${DOCKER_IP}" +fi + +set_hosts "${DOCKER_IP}" + +echo "Done" +exit 0 diff --git a/resources/ssl/development/scripts/docker-proxy/proxy.conf b/resources/ssl/development/scripts/docker-proxy/proxy.conf new file mode 100644 index 000000000..dd6d3347f --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/proxy.conf @@ -0,0 +1,13 @@ +# HTTP 1.1 support +proxy_http_version 1.1; +proxy_buffering off; +proxy_set_header Host $http_host; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $proxy_connection; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; + +proxy_ignore_client_abort on; + +proxy_read_timeout 200s; diff --git a/resources/ssl/development/scripts/docker-proxy/vhost.d/api.bb-consent.dev_location b/resources/ssl/development/scripts/docker-proxy/vhost.d/api.bb-consent.dev_location new file mode 100644 index 000000000..3fad07f0d --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/vhost.d/api.bb-consent.dev_location @@ -0,0 +1,20 @@ +add_header 'Access-Control-Allow-Origin' "*" always; +add_header 'Access-Control-Allow-Credentials' 'true' always; +add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always; +add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + +# required to be able to read Authorization header in frontend +#add_header 'Access-Control-Expose-Headers' 'Authorization' always; + +if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' "*" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + + # Tell client that this pre-flight info is valid for 20 days + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain, application/json, */* charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; +} \ No newline at end of file diff --git a/resources/ssl/development/scripts/docker-proxy/vhost.d/default_location b/resources/ssl/development/scripts/docker-proxy/vhost.d/default_location new file mode 100644 index 000000000..3fad07f0d --- /dev/null +++ b/resources/ssl/development/scripts/docker-proxy/vhost.d/default_location @@ -0,0 +1,20 @@ +add_header 'Access-Control-Allow-Origin' "*" always; +add_header 'Access-Control-Allow-Credentials' 'true' always; +add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always; +add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + +# required to be able to read Authorization header in frontend +#add_header 'Access-Control-Expose-Headers' 'Authorization' always; + +if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' "*" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; + + # Tell client that this pre-flight info is valid for 20 days + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain, application/json, */* charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 5e31a3f4d..1415742b1 100644 --- a/src/App.js +++ b/src/App.js @@ -1,22 +1,11 @@ import React, { Component } from "react"; -//Styles import "./App.css"; -//Router import { Route, Switch, Router, Redirect } from "react-router-dom"; -//history import { history } from "./history"; -//Containers -import { Login, Register, ForgotPassword, DefaultLayout } from "./Components"; -//Authorization -// import Store from "Provider/store"; -// import Auth from "./authorization/auth"; +import { Login, ForgotPassword, DefaultLayout } from "./Components"; import { auth, store } from 'Provider/store'; -import PrivacyPolicy from "./Components/PrivacyPolicy/PrivacyPolicy"; -import SubscribeToOrganization from "./Components/SubscribeToOrganization/SubscribeToOrganization"; - import axios from 'axios'; -const supportsHistory = "pushState" in window.history; const PrivateRoute = ({ component: Component, ...rest }) => ( ( /> ); -// listening to path changes and checking if it came from QR code scan -history.listen((location, action) => { - if (location.state !== undefined) { - if (location.state.from !== undefined) { - store.setFromPath(location.state.from.search); - } - - } - -}); // Add a request interceptor @@ -73,9 +52,6 @@ class App extends Component { - - - { - - if (this.elemRefs[refId] !== undefined) { - if (!store.qrStore.isPurposeScrolled) { - this.elemRefs[refId].current.scrollIntoView({ - behavior: 'smooth', - block: 'start', - }); - const elem = document.getElementsByClassName("panel-usage-" + refId); - if (elem !== undefined) { - elem[0].style.border = "1px solid"; - } - - // updating scroll status. - store.qrStore.isPurposeScrolled = true; - } - - } - }; - - - componentDidUpdate(prevProps, prevState, snapshot) { - - this.scrollToMyRef(store.qrStore.purposeId); - - } handleSwitch = (purposeId, value, e) => { @@ -74,8 +47,6 @@ class CollapseUsage extends Component { }; changeAttributeStatus = (purposeId, attributeId, e) => { - console.log('DEBUG :', `PURPOSE ID : ${purposeId}`, `ATTRIBUTE ID : ${attributeId}`, `Value : ${e.target.value}`); - // console.log(e); const currentStatus = e.target.value; if (currentStatus === 'Allow' || currentStatus === 'Disallow') { store.updateAttribute(currentStatus, 0, purposeId, attributeId); @@ -99,16 +70,6 @@ class CollapseUsage extends Component {
) - } else { - data.forEach(function (purpose, index) { - if (purpose['Purpose']['ID'] === store.qrStore.purposeId) { - if (!store.qrStore.isPurposeToggled) { - openKey = index; - store.qrStore.isPurposeToggled = true; - } - return - } - }); } this.elemRefs = data.reduce((acc, value) => { @@ -126,7 +87,7 @@ class CollapseUsage extends Component { defaultActiveKey={openKey.toString()} expandIcon={({ isActive }) => } > - + {!data ? null : data.map((purpose, i) => @@ -135,7 +96,7 @@ class CollapseUsage extends Component { - + { - // Should provide an event to pass value to Form. - const { onChange } = this.props; - if (onChange) { - onChange({ - ...this.state, - ...changedValue - }); - } - }; - - render() { - const handleOnChange = value => { - this.setState({ rawValue: value }); - this.triggerChange({ rawValue: value }); - }; - - return ( - -} - shouldAutoFocus - /> - ); - } -} - -export default CustomOtpInput; diff --git a/src/Components/CustomPhoneNumber/CustomPhoneNumber.jsx b/src/Components/CustomPhoneNumber/CustomPhoneNumber.jsx deleted file mode 100644 index fccd58d09..000000000 --- a/src/Components/CustomPhoneNumber/CustomPhoneNumber.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, {Component} from "react"; - -import PhoneInput from 'react-phone-input-2' -import 'react-phone-input-2/dist/style.css' -import {observer} from "mobx-react"; - -@observer -class CustomPhoneNumber extends Component { - - constructor(props) { - super(props); - - const value = props.value || {}; - - this.state = { - rawValue: "+1" - }; - - this.triggerChange({rawValue: "+46"}); - } - - - componentDidMount() { - this.setState({rawValue: '+46'}); - this.triggerChange({rawValue: "+46"}); - } - - triggerChange = changedValue => { - // Should provide an event to pass value to Form. - const {onChange} = this.props; - if (onChange) { - onChange({ - ...this.state, - ...changedValue, - }); - } - }; - - render() { - - const handleOnChange = (value) => { - this.setState({rawValue: value}); - this.triggerChange({rawValue: value}); - }; - - return ( - - ) - } -} - -export default CustomPhoneNumber; \ No newline at end of file diff --git a/src/Components/DataRequestTable/NewRequest.jsx b/src/Components/DataRequestTable/NewRequest.jsx deleted file mode 100644 index 86a69f65b..000000000 --- a/src/Components/DataRequestTable/NewRequest.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, {Component} from 'react'; -import {Form, Input, Radio} from 'antd'; -import {store, RequestTypes} from '../../Provider/store'; -import {withNamespaces} from "react-i18next"; - -const onFieldsChange = (props, changeValue, allValue) => { - // console.log(props,changeField,allFields); -}; - -const RequestForm = Form.create({name: 'requestForm', onValuesChange: onFieldsChange})( - // eslint-disable-next-line - class extends React.Component { - - componentWillMount() { - store.dataRequest.form = this.props.form; - // this.props.form.onFieldsChange = this.onFieldsChange; - } - - render() { - const {visible, onCancel, onCreate, form, t} = this.props; - const {getFieldDecorator} = form; - return ( - -
- {/* - {getFieldDecorator('title', { - rules: [{ required: true, message: 'Please input the title of collection!' }], - })()} - - - {getFieldDecorator('description')()} - */} - - {getFieldDecorator('requestType', { - initialValue: RequestTypes.dataDownload, - })( - - {t('landingPage.downloadData')} - {t('landingPage.deleteData')} - {/* Update Data */} - , - )} - -
- - ); - } - }, -); - -export const RequestFormWithNamespace = withNamespaces()(RequestForm); \ No newline at end of file diff --git a/src/Components/DataRequestTable/index.js b/src/Components/DataRequestTable/index.js deleted file mode 100644 index 485deff69..000000000 --- a/src/Components/DataRequestTable/index.js +++ /dev/null @@ -1,153 +0,0 @@ -import React, {Component} from "react"; -import {observer} from "mobx-react"; -import {withNamespaces, Trans} from "react-i18next"; -import {Table, Button, Tag, Modal} from "antd"; -import {RequestForm, RequestFormWithNamespace} from "./NewRequest"; -import {store, Status} from "Provider/store"; -import moment from "moment"; - -const columns = [ - { - title: Request Type, - dataIndex: "requestType", - key: "requestType", - width: "25%" - }, - { - title: Requested Time, - dataIndex: "requested", - key: "requested", - sorter: (a, b) => - moment(a.requested, "MMM-DD-YYYY HH:mm:ss A") - - moment(b.requested, "MMM-DD-YYYY HH:mm:ss A"), - sortDirections: [], - sortOrder: "descend", - defaultSortOrder: "descend", - width: "25%" - }, - { - title: Status, - key: "status", - dataIndex: "status", - width: "25%", - render: status => ( - - - {status} - - - ) - }, - { - title: Closed, - dataIndex: "closed", - key: "closed" - } -]; - -@observer -class DeleteData extends Component { - state = {visible: false, status: null, visibleForm: false}; - - showModal = () => { - this.setState({ - visible: true - }); - }; - - handleOk = e => { - // console.log(e); - store.sendDataRequest(); - this.setState({ - visible: false - }); - }; - - handleCancel = e => { - this.setState({ - visible: false - }); - }; - // handleRowClick = (record,dataIndex)=>{ - // return { - // onClick: event => { - // // console.log(record,dataIndex); - // this.setState({status:record['status'],visibleForm:null},()=>{ - // console.log('Status : ',this.state.status); - // this.showModal(); - // }) - // }, // click row - // }; - // } - handleNewRequest = () => { - // console.log('OnNewRequest'); - this.setState({visibleForm: true, status: null}, () => { - this.showModal(); - }); - }; - - componentDidMount() { - store.fetchDataRequest(); - } - - render() { - const {isFetching, data} = store.dataRequest; - - console.log("DEBUG FROM DATAREQUEST COMPONENT : ", data); - - const {status, visibleForm} = this.state; - const {t} = this.props; - - return ( - - - {/* {status && - {Status.initiated} - {Status.acknowledged} - {'Request processed'} - } */} - {visibleForm && } - -
- - - - - ); - } -} - -export default withNamespaces()(DeleteData); diff --git a/src/Components/DefaultLayout/DefaultLayout.jsx b/src/Components/DefaultLayout/DefaultLayout.jsx index a21c4b202..988086b6d 100644 --- a/src/Components/DefaultLayout/DefaultLayout.jsx +++ b/src/Components/DefaultLayout/DefaultLayout.jsx @@ -1,84 +1,56 @@ -import React, {Component} from "react"; -import {observer} from 'mobx-react'; -import {Spin, Icon} from 'antd'; -// import Auth from "authorization/auth"; -import {history} from "../../history"; -import {store, auth} from "../../Provider/store"; - -import Header from '../Header'; -import CoverImage from '../CoverImage'; -import {Logo} from '../Login/Logo'; -import OrganizationInfo from '../OrganizationInfo'; -import {OrganizationOverview} from '../OrganizationInfo/organizationOverview'; -import ManageMenu from '../ManageMenu'; -//dashboard css -import './dashboard.css'; -import {withNamespaces} from "react-i18next"; - -const antIcon = ; +import React, { Component } from "react"; +import { observer } from "mobx-react"; +import { Spin, Icon } from "antd"; +import { store } from "../../Provider/store"; +import Header from "../Header"; +import CoverImage from "../CoverImage"; +import { Logo } from "../Login/Logo"; +import OrganizationInfo from "../OrganizationInfo"; +import { OrganizationOverview } from "../OrganizationInfo/organizationOverview"; +import ManageMenu from "../ManageMenu"; +import "./dashboard.css"; +import { withNamespaces } from "react-i18next"; + +const antIcon = ; @observer class DefaultLayout extends Component { - componentDidMount() { - - store.fetchOrganization(); - if (!store.subscriptionStore.isSubscribed) { - store.handleSubscription(); - } - console.log("DEBUG SUBSCRIPTION STATUS"); - } - - componentDidUpdate(prevProps, prevState, snapshot) { - - } - - render() { - - const {from} = this.props.location.state || {from: {pathname: '/'}}; - const {isSubscribed} = store.subscriptionStore; - const {t} = this.props; - - const {isFetching, error} = store.organizationStore; - const isLoading = store.subscriptionStore.isFetching; - const subscriptionMethod = store.subscriptionStore.method; - - if (!isSubscribed && subscriptionMethod === "Key-Based") { - return ( -
- {isFetching && isSubscribed ? -
-
: ( - - - )} - {error &&
{error}
} -
- -
-
- ) - } else { - return ( -
-
- {isFetching ? -
-
: ( - !error && - - - - - )} - {error &&
{error}
} -
- -
-
- ) - } - - } + componentDidMount() { + store.fetchOrganization(); + } + + componentDidUpdate(prevProps, prevState, snapshot) {} + + render() { + const { from } = this.props.location.state || { from: { pathname: "/" } }; + const { t } = this.props; + + const { isFetching, error } = store.organizationStore; + + return ( +
+
+ {isFetching ? ( +
+ +
+ ) : ( + !error && ( + + + + + + + ) + )} + {error &&
{error}
} +
+ +
+
+ ); + } } export default withNamespaces()(DefaultLayout); diff --git a/src/Components/ForgotPassword/ForgotPassword.jsx b/src/Components/ForgotPassword/ForgotPassword.jsx index 85fa6718c..82d834d51 100644 --- a/src/Components/ForgotPassword/ForgotPassword.jsx +++ b/src/Components/ForgotPassword/ForgotPassword.jsx @@ -1,233 +1,230 @@ -import React, {Component} from "react"; +import React, { Component } from "react"; import ReactDOM from "react-dom"; // Antd -import {Button, Divider, Form, Input, Spin} from "antd"; +import { Button, Divider, Form, Input, Spin } from "antd"; //i18n -import {withNamespaces} from "react-i18next"; -import {LanguageSelector} from "../Login/LanguageSelector"; +import { withNamespaces } from "react-i18next"; +import { LanguageSelector } from "../Login/LanguageSelector"; -import {history} from "../../history"; +import { history } from "../../history"; // Authorization -import {auth} from 'Provider/store'; -import {getSession} from "authorization/utils"; +import { auth } from "Provider/store"; +import { getSession } from "authorization/utils"; //Store -import {store} from "Provider/store"; -import {observer} from "mobx-react"; -import {antIcon} from "../Login/antIcon"; +import { store } from "Provider/store"; +import { observer } from "mobx-react"; +import { antIcon } from "../Login/antIcon"; // assets -import defaultLogo from 'assets/icons/igrant.io_200X200.jpg'; -import {Logo} from "../Login/Logo"; +import defaultLogo from "assets/icons/igrant.io_200X200.jpg"; +import { Logo } from "../Login/Logo"; //Styles import "./forgotpassword.css"; -import {Link} from "react-router-dom"; +import { Link } from "react-router-dom"; @observer class ForgotPassword extends Component { - - state = { - showForgotPasswordScreen: true, - showSuccessScreen: false, - values: {} - }; - - - componentWillMount() { - if (auth.isLoginValid()) { - auth.isAuthenticated = true; - auth.accessToken = getSession('access_token'); - auth.refreshToken = getSession('refresh_token'); - auth.userId = getSession('userId'); - store.user.name = getSession('username'); - store.user.email = getSession('email'); - store.user.lastVisit = new Date(getSession('lastVisit')).toLocaleString(); - history.push("/dashboard"); - } + state = { + showForgotPasswordScreen: true, + showSuccessScreen: false, + values: {}, + }; + + componentWillMount() { + if (auth.isLoginValid()) { + auth.isAuthenticated = true; + auth.accessToken = getSession("access_token"); + auth.refreshToken = getSession("refresh_token"); + auth.userId = getSession("userId"); + store.user.name = getSession("username"); + store.user.email = getSession("email"); + store.user.lastVisit = new Date(getSession("lastVisit")).toLocaleString(); + history.push("/dashboard"); } - - componentDidMount() { - const element = ReactDOM.findDOMNode(this); - element.addEventListener("keydown", e => { - this.handleKeydown(e); - }); + } + + componentDidMount() { + const element = ReactDOM.findDOMNode(this); + element.addEventListener("keydown", (e) => { + this.handleKeydown(e); + }); + } + + // handling form submission when enter key is pressed + handleKeydown(e) { + if (this.state.showForgotPasswordScreen) { + if (e.keyCode === 13 && e.shiftKey === false) { + e.preventDefault(); + this.handleForgotPassword(); + } } + } - // handling form submission when enter key is pressed - handleKeydown(e) { - - if (this.state.showForgotPasswordScreen) { - if ((e.keyCode === 13) && (e.shiftKey === false)) { - e.preventDefault(); - this.handleForgotPassword(); - } - } - + // clears error + clearError = () => { + if (store.authStore.error) { + store.authStore.error = ""; } - - // clears error - clearError = () => { - if (store.authStore.error) { - store.authStore.error = ''; - } - }; - - // handles forgot password - handleForgotPassword = () => { - - - this.clearError(); - - this.props.form.validateFields((err, values) => { - - this.setState({values}); - - if (!err) { - - if (values.Email) { - store.authStore.isLoading = true; - - const forgotPasswordRequest = auth.forgotPassword(values.Email); - - if (forgotPasswordRequest) { - - forgotPasswordRequest.then((res) => { - - store.authStore.isLoading = false; - - // Todo: redirect to success page. - this.setState({showForgotPasswordScreen: false}); - this.setState({showSuccessScreen: true}); - - - }).catch((error) => { - this.handleError(error); - }) - - - } - - - } - - } - - - }); - - - }; - - handleError = (error) => { - if (error.response.data.Message !== undefined) { - store.authStore.error = error.response.data.Message - } else { - store.authStore.error = error.response.data.error_description + }; + + // handles forgot password + handleForgotPassword = () => { + this.clearError(); + + this.props.form.validateFields((err, values) => { + this.setState({ values }); + + if (!err) { + if (values.Email) { + store.authStore.isLoading = true; + + const forgotPasswordRequest = auth.forgotPassword(values.Email); + + if (forgotPasswordRequest) { + forgotPasswordRequest + .then((res) => { + store.authStore.isLoading = false; + + // Todo: redirect to success page. + this.setState({ showForgotPasswordScreen: false }); + this.setState({ showSuccessScreen: true }); + }) + .catch((error) => { + this.handleError(error); + }); + } } - store.authStore.isLoading = false; - console.error(error); - }; - - render() { - const {t} = this.props; - const {url} = store.config.logo; - const {error} = store.authStore; - - const {getFieldDecorator} = this.props.form; - const formValues = this.state.values; - const {showForgotPasswordScreen, showSuccessScreen} = this.state; - const loading = store.authStore.isLoading; - - return ( - -
-
-
-

{t("forgotPasswordPageTitle")}

- - {/* Forgot Password Screen */} -
- -
-

Enter the email address you registered with us. We'll send you an email in order to let - you choose a new password

-
- - -
-
- - {getFieldDecorator("Email", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - -
- {/* Registration continue */} -
- {loading ? : - } - -
- - {/* Registration input errors */} - {error &&
{error}
} - - - - {/* Sign in section */} -
- Click - here - to go back to login -
- - - - -
- - {/* User created successfully */} -
-
-

Password reset e-mail has been sent to {formValues.Email !== undefined ? formValues.Email : ""}. - Click here to go back to login. -

-
-
- -
- - -
-
-

Copyright © 2019 LCubed AB, Sweden. All rights reserved.

- - -
-
-
- ) + } + }); + }; + + handleError = (error) => { + if (error.response.data.Message !== undefined) { + store.authStore.error = error.response.data.Message; + } else { + store.authStore.error = error.response.data.error_description; } + store.authStore.isLoading = false; + console.error(error); + }; + + render() { + const { t } = this.props; + const { url } = store.config.logo; + const { error } = store.authStore; + + const { getFieldDecorator } = this.props.form; + const formValues = this.state.values; + const { showForgotPasswordScreen, showSuccessScreen } = this.state; + const loading = store.authStore.isLoading; + + return ( +
+
+
+ +
+

+ {t("forgotPasswordPageTitle")} +

+ + {/* Forgot Password Screen */} +
+
+

+ Enter the email address you registered with us. We'll send you + an email in order to let you choose a new password +

+
+
+
+ + {getFieldDecorator("Email", { + rules: [], //[{ required: true, message: t("messages.username") }] + })( + + )} + +
+ {/* Registration continue */} +
+ {loading ? ( + + ) : ( + + )} +
+ + {/* Registration input errors */} + {error &&
{error}
} + + + + {/* Sign in section */} +
+ Click + here + to go back to login +
+ +
+ + {/* User created successfully */} +
+
+

+ Password reset e-mail has been sent to{" "} + + {formValues.Email !== undefined ? formValues.Email : ""} + + . Click here to go back to login. +

+
+
+
+ +
+
+

+ Copyright © 2023 LCubed AB, Sweden. All rights reserved. +

+ + +
+
+
+ ); + } } +const WrappedForgotPassword = Form.create({ name: "forgot_password" })( + ForgotPassword +); -const WrappedForgotPassword = Form.create({name: "forgot_password"})(ForgotPassword); - -export default withNamespaces()(WrappedForgotPassword) +export default withNamespaces()(WrappedForgotPassword); diff --git a/src/Components/Header/HomeButton.jsx b/src/Components/Header/HomeButton.jsx index 3717a7497..775c727fa 100644 --- a/src/Components/Header/HomeButton.jsx +++ b/src/Components/Header/HomeButton.jsx @@ -1,18 +1,17 @@ -import React, { Component } from 'react'; +import React from "react"; -import {Icon} from 'antd'; -import {history} from '../../history'; +import { Icon } from "antd"; +import { history } from "../../history"; -const goToHome = ()=>{ - // console.log('goto home'); - history.push('/dashboard/menu'); -} +const goToHome = () => { + // console.log('goto home'); + history.push("/dashboard/menu"); +}; -const HomeButton = ()=>( - - - -) +const HomeButton = () => ( + + + +); - -export default HomeButton; \ No newline at end of file +export default HomeButton; diff --git a/src/Components/Header/UserSettings.jsx b/src/Components/Header/UserSettings.jsx index 87dfac1eb..652789b3e 100644 --- a/src/Components/Header/UserSettings.jsx +++ b/src/Components/Header/UserSettings.jsx @@ -1,94 +1,98 @@ -import React, {Component} from 'react'; -import {Link} from 'react-router-dom'; +import React, { Component } from "react"; +import { Link } from "react-router-dom"; //Store -import {observer} from 'mobx-react'; +import { observer } from "mobx-react"; //i18n -import {withNamespaces} from "react-i18next"; +import { withNamespaces } from "react-i18next"; -import {Popover, Icon, Menu, Avatar} from 'antd'; +import { Popover, Icon, Menu, Avatar } from "antd"; // import Auth from 'authorization/auth'; -import {store, auth} from 'Provider/store'; -import {resources} from 'localization/resources'; +import { store, auth } from "Provider/store"; +import { resources } from "localization/resources"; //languages -import {lngList} from 'localization/languages'; -import {history} from '../../history'; +import { lngList } from "localization/languages"; +import { history } from "../../history"; -const items = Object.keys(resources).map((lng, i) => - - { - e.preventDefault(); - store.changeLanguage(lng); - }}>{lngList[lng]} - -); -const UserDetails = observer(({t}) => ( -
- -

{store.user.name ? store.user.name : 'No name'}

-

{store.user.email ? store.user.email : 'No email'}

-

{store.user.lastVisit ? `${t('lastVisit')} : ${store.user.lastVisit}` : 'No last visit'}

-
+const items = Object.keys(resources).map((lng, i) => ( + + { + e.preventDefault(); + store.changeLanguage(lng); + }} + > + {lngList[lng]} + + +)); +const UserDetails = observer(({ t }) => ( +
+ +

{store.user.name ? store.user.name : "No name"}

+

{store.user.email ? store.user.email : "No email"}

+

+ {store.user.lastVisit + ? `${t("lastVisit")} : ${store.user.lastVisit}` + : "No last visit"} +

+
)); const UserDetailsWithNamespace = withNamespaces()(UserDetails); -const MenuList = ({t, hide, logout, changeRoute}) => ( - - - - { - history.push('/dashboard/managedata'); - hide() - }}>{t('dashboard.userRequest')} - - {items} - - {/* {t('dashboard.logs')} */} - {t('dashboard.logout')} - - +const MenuList = ({ t, hide, logout, changeRoute }) => ( + + + + {items} + + {t("dashboard.logout")} + + + ); const MenuListWithNamespace = withNamespaces()(MenuList); class UserSettings extends React.Component { - state = { - visible: false, - }; - - logout = () => { - auth.logout(); - this.hide(); - }; - - hide = () => { - this.setState({ - visible: false, - }); - }; + state = { + visible: false, + }; - handleVisibleChange = (visible) => { - this.setState({visible}); - }; + logout = () => { + auth.logout(); + this.hide(); + }; + hide = () => { + this.setState({ + visible: false, + }); + }; - render() { - const {t} = this.props; - return ( - - } - trigger="click" - visible={this.state.visible} - onVisibleChange={this.handleVisibleChange} - placement="bottomRight" - > - - - - ) - } + handleVisibleChange = (visible) => { + this.setState({ visible }); + }; + render() { + const { t } = this.props; + return ( + + + } + trigger="click" + visible={this.state.visible} + onVisibleChange={this.handleVisibleChange} + placement="bottomRight" + > + + + + ); + } } -export default withNamespaces()(UserSettings); \ No newline at end of file +export default withNamespaces()(UserSettings); diff --git a/src/Components/Login/Login.jsx b/src/Components/Login/Login.jsx index 89ed43b08..6b52824b8 100644 --- a/src/Components/Login/Login.jsx +++ b/src/Components/Login/Login.jsx @@ -1,275 +1,255 @@ import React, { Component } from "react"; import ReactDOM from "react-dom"; -import { Link, Redirect } from "react-router-dom"; -//Mobx +import { Link } from "react-router-dom"; import { observer } from "mobx-react"; - -//Store import { store, services } from "Provider/store"; - -//i18n import { withNamespaces } from "react-i18next"; - -//Authorization -// import Auth from "authorization/auth"; -import { auth } from 'Provider/store'; +import { auth } from "Provider/store"; import { getSession } from "authorization/utils"; -//history import { history } from "../../history"; - -//Antd -import { Form, Icon, Input, Button, Checkbox, Divider, Spin } from "antd"; +import { Form, Icon, Input, Checkbox, Divider, Spin } from "antd"; import { antIcon } from "./antIcon"; import { LanguageSelector } from "./LanguageSelector"; -import { Logo } from './Logo'; - -//Styles +import { Logo } from "./Logo"; import "./login.css"; -import loginIcon from 'assets/icons/arrow.svg'; -import defaultLogo from 'assets/icons/igrant.io_200X200.jpg'; -import OpenInApp from "../OpenInApp/OpenInApp"; - -import OauthPopup from 'react-oauth-popup'; - -import Keycloak from 'keycloak-js'; -import qs from 'qs'; +import loginIcon from "assets/icons/arrow.svg"; +import defaultLogo from "assets/icons/igrant.io_200X200.jpg"; +import Keycloak from "keycloak-js"; +import qs from "qs"; -/////////////////// Chech token expiry /////////// -/*eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICItYUR1dmxoUE92M2k0MTVWSnU4cHQ5cVZqREZ0VDdFSWNVRzByeXc1cjZVIn0.eyJqdGkiOiI5OTU1MTFjNC01NDYxLTRkYTYtYjY5My0xZGQ0ZTAzODMwOTkiLCJleHAiOjE1NDg4MjQ1NTcsIm5iZiI6MCwiaWF0IjoxNTQ4Nzg4NTU3LCJpc3MiOiJodHRwczovL2lhbS5pZ3JhbnQuaW8vYXV0aC9yZWFsbXMvaWdyYW50LXVzZXJzIiwiYXVkIjoiaWdyYW50LWlvcy1hcHAiLCJzdWIiOiJlNDI5ZTk1Yy04MmIxLTRlMGYtYTQ2OS1jNTM2M2RkMzFlYzAiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJpZ3JhbnQtaW9zLWFwcCIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6ImJkZmI2MWQ3LWY3MDMtNDNiYS1iOGVmLTU1ZDBhYTVlYjFkNCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOltdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IlVzZXIxIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcjFAaWdyYW50LmNvbSIsImdpdmVuX25hbWUiOiJVc2VyMSIsImZhbWlseV9uYW1lIjoiIiwiZW1haWwiOiJ1c2VyMUBpZ3JhbnQuY29tIn0.SK4Dvigdllaf_1YK7PPq15Psd5hqu7xnPJpoPvgzoaEIIVENs2V5OKXNXbXobpVrRjTQjEgpauFs0fsf7Nv4Vr2Iq2hzn6ae_uXCgb_ij9ZRi6mfMfeeb8CS42s1xxGIYAWHGDueVQPBTAyTn0EAX8a8p3eBeD4Ka0KDQYSDkVJse4fliG0kC5V-LF_jnA3dOOhgzTJcHajacLdNTZTBZdg6B37liG3qh3zjLg9JWB9Jm5WUWGkrBDRGd4jrc4kX0j50sOwlZSnGeCzeNmzevUOSe_sHuf_Ud-X8yXamVsIH6qsdeAnArew_UgT9H_92LPl_DjgPMnhWQXCvqDuEnA*/ @observer class Login extends Component { + constructor(props) { + super(props); - constructor(props) { - super(props); - - - // Don't show login for OpenID connect subscription method - let showLogin = true; - if (store.config.subscriptionMethodId === 2) { - showLogin = false; - } - - this.state = { showLogin: showLogin, openIdLoaderText: "" }; + // Don't show login for OpenID connect subscription method + let showLogin = true; + if (store.config.subscriptionMethodId === 2) { + showLogin = false; } - - componentWillMount() { - - - if (auth.isLoginValid()) { - auth.isAuthenticated = true; - auth.accessToken = getSession('access_token'); - auth.refreshToken = getSession('refresh_token'); - auth.userId = getSession('userId'); - store.user.name = getSession('username'); - store.user.email = getSession('email'); - store.user.lastVisit = new Date(getSession('lastVisit')).toLocaleString(); - - - // This is for handling QR code redirection if already authenticated. - history.push("/dashboard"); - + this.state = { showLogin: showLogin, openIdLoaderText: "" }; + } + + componentWillMount() { + if (auth.isLoginValid()) { + auth.isAuthenticated = true; + auth.accessToken = getSession("access_token"); + auth.refreshToken = getSession("refresh_token"); + auth.userId = getSession("userId"); + store.user.name = getSession("username"); + store.user.email = getSession("email"); + store.user.lastVisit = new Date(getSession("lastVisit")).toLocaleString(); + + // This is for handling QR code redirection if already authenticated. + history.push("/dashboard"); + } else { + // Handling OpenID connect subscription method + if (store.config.subscriptionMethodId === 2) { + const sessionState = qs.parse(this.props.location.hash, { + ignoreQueryPrefix: true, + }).session_state; + const authorizationCode = qs.parse(this.props.location.hash, { + ignoreQueryPrefix: true, + }).code; + + if (sessionState) { + // Updating the loader text to be shown while waiting for the redirection towards org login page. + this.setState({ + openIdLoaderText: + "Successfully logged in, setting up your account...", + }); + + // Exchanging authorization code to fetch the access token and user details. + + const request = services.exchangeAuthorizationCodeWeb( + encodeURIComponent(store.config.redirectUri), + authorizationCode + ); + if (request) { + request + .then((res) => { + if (res.status === 200) { + // Updating the loader text to be shown while waiting for the redirection towards org login page. + this.setState({ + openIdLoaderText: + "Successfully logged in, setting up your account...", + }); + + store.authStore.isLoading = true; + auth.handleAuthentication(res); + + // TODO: Check if profile information is complete + // TODO: If not complete then redirect to complete profile information + } + }) + .catch((error) => { + console.log(error); + }); + } } else { + // Updating the loader text to be shown while waiting for the redirection towards org login page. + this.setState({ + openIdLoaderText: "Redirecting to organization login page...", + }); + // Redirecting user to configured external identity provider login - // Handling OpenID connect subscription method - if (store.config.subscriptionMethodId === 2) { - - const sessionState = qs.parse(this.props.location.hash, { ignoreQueryPrefix: true }).session_state; - const authorizationCode = qs.parse(this.props.location.hash, { ignoreQueryPrefix: true }).code; - - - if (sessionState) { - - // Updating the loader text to be shown while waiting for the redirection towards org login page. - this.setState({ openIdLoaderText: "Successfully logged in, setting up your account..." }) - - // Exchanging authorization code to fetch the access token and user details. - - const request = services.exchangeAuthorizationCodeWeb(encodeURIComponent(store.config.redirectUri), authorizationCode); - if (request) { - request.then((res) => { - if (res.status === 200) { - - // Updating the loader text to be shown while waiting for the redirection towards org login page. - this.setState({ openIdLoaderText: "Successfully logged in, setting up your account..." }) - - - store.authStore.isLoading = true; - auth.handleAuthentication(res); - - // TODO: Check if profile information is complete - // TODO: If not complete then redirect to complete profile information - } + const keycloakConfig = { + realm: store.config.iamRealm, + url: store.config.iamUrl, + clientId: store.config.organizationId, + }; - }).catch(error => { - console.log(error) - }); - } - - } else { - - // Updating the loader text to be shown while waiting for the redirection towards org login page. - this.setState({ openIdLoaderText: "Redirecting to organization login page..." }) - - - // Redirecting user to configured external identity provider login - - const keycloakConfig = { - "realm": store.config.iamRealm, - "url": store.config.iamUrl, - "clientId": store.config.organizationId - } - - const keycloak = Keycloak(keycloakConfig); - keycloak.init(); - - keycloak.login({ - "idpHint": store.config.organizationId - }) - - } - } + const keycloak = Keycloak(keycloakConfig); + keycloak.init(); + keycloak.login({ + idpHint: store.config.organizationId, + }); } + } } - - componentDidMount() { - - const element = ReactDOM.findDOMNode(this); - element.addEventListener("keydown", e => { - this.handleKeydown(e); - }); + } + + componentDidMount() { + const element = ReactDOM.findDOMNode(this); + element.addEventListener("keydown", (e) => { + this.handleKeydown(e); + }); + } + + handleKeydown(e) { + if (e.keyCode === 13 && e.shiftKey === false) { + this.handleLogin(); } + } - handleKeydown(e) { - if ((e.keyCode === 13) && (e.shiftKey === false)) { - this.handleLogin(); - } + clearError = () => { + if (store.authStore.error) { + store.authStore.error = ""; } - - clearError = () => { - if (store.authStore.error) { - store.authStore.error = ''; + }; + + handleLogin = () => { + this.props.form.validateFields((err, values) => { + if (!err) { + if (values.username && values.password) { + store.authStore.isLoading = true; + store.authStore.isRemember = values.remember; + auth.login(values.username, values.password); } - }; - - handleLogin = () => { - this.props.form.validateFields((err, values) => { - if (!err) { - if (values.username && values.password) { - store.authStore.isLoading = true; - store.authStore.isRemember = values.remember; - auth.login(values.username, values.password); - } - } - }); - }; - - render() { - const { t } = this.props; - const { from } = this.props.location.state || { from: { pathname: '/' } }; - const { error } = store.authStore; - - const { getFieldDecorator } = this.props.form; - const loading = store.authStore.isLoading; - const { url } = store.config.logo; - - - if (this.state.showLogin) { - return ( - - -
-
-
-

{t("signin")}

-
-
- - {getFieldDecorator("username", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - } - placeholder={t("username")} - size="large" - onChange={this.clearError} - /> - )} - - - - {getFieldDecorator("password", { - rules: []// [{ required: true, message: t("messages.password") }] - })( - - } - type="password" - placeholder={t("password")} - size="large" - className="password-input" - suffix={ - loading ? ( - - ) : ( -
- ) - } - onChange={this.clearError} - /> - )} -
-
- {error &&
{error}
} - -
- {getFieldDecorator("remember", { - valuePropName: "checked", - initialValue: true - })({t("rememberme")})} -
-
- -
- {t("forgot")} -
-
- {t("noAccount")} - {t("createAccount")} -
- -
-
-
-

Copyright © 2019 LCubed AB, Sweden. All rights reserved.

- - -
-
- - - -
- ); - } else { - return ( -
-
-
-

{this.state.openIdLoaderText}

-
+ } + }); + }; + + render() { + const { t } = this.props; + const { from } = this.props.location.state || { from: { pathname: "/" } }; + const { error } = store.authStore; + + const { getFieldDecorator } = this.props.form; + const loading = store.authStore.isLoading; + const { url } = store.config.logo; + + if (this.state.showLogin) { + return ( +
+
+
+ +
+

{t("signin")}

+
+
+ + {getFieldDecorator("username", { + rules: [], //[{ required: true, message: t("messages.username") }] + })( + + } + placeholder={t("username")} + size="large" + onChange={this.clearError} + /> + )} + + + + {getFieldDecorator("password", { + rules: [], // [{ required: true, message: t("messages.password") }] + })( + + } + type="password" + placeholder={t("password")} + size="large" + className="password-input" + suffix={ + loading ? ( + + ) : ( +
+ +
+ ) + } + onChange={this.clearError} + /> + )} +
+
+ {error &&
{error}
} + +
+ {getFieldDecorator("remember", { + valuePropName: "checked", + initialValue: true, + })({t("rememberme")})}
- ) - } - - +
+ +
+ {t("forgot")} +
+ +
+
+
+

+ Copyright © 2023 LCubed AB, Sweden. All rights reserved. +

+ + +
+
+
+ ); + } else { + return ( +
+
+
+

{this.state.openIdLoaderText}

+
+
+ ); } + } } const WrappedLogin = Form.create({ name: "normal_login" })(Login); diff --git a/src/Components/ManageMenu/MenuGrid.jsx b/src/Components/ManageMenu/MenuGrid.jsx index 33842f03d..1ee232542 100644 --- a/src/Components/ManageMenu/MenuGrid.jsx +++ b/src/Components/ManageMenu/MenuGrid.jsx @@ -1,95 +1,67 @@ -import React, {Component} from 'react'; -import {Row, Col} from 'antd'; -import usagePurposeIcon from 'assets/icons/UsagePurposes.png'; -import downloadData from 'assets/icons/downloadData.png'; -import deleteData from 'assets/icons/deleteData.png'; -import {withNamespaces} from "react-i18next"; +import React, { Component } from "react"; +import { Row, Col } from "antd"; +import usagePurposeIcon from "assets/icons/UsagePurposes.png"; +import { withNamespaces } from "react-i18next"; //Store -import {store} from "Provider/store"; +import { store } from "Provider/store"; -import './menuGrid.css'; +import "./menuGrid.css"; -import {history} from '../../history'; - -const overview = { - usagePurpose: 'You will have the ability to view data agreements and mark your preferences.', - manageData: 'View/Modify/Download your personal data.', - downloadData: 'You can request downloading your personal data.', - deleteData: 'Permanently or temporarily delete your account and the associated data', - viewLogs: 'View your consent history/logs', - userRequests: 'View/Modify/Download your personal data.' -}; +import { history } from "../../history"; class MenuGrid extends Component { - changeRoute = (path) => { - history.push(`/dashboard/${path}`); - }; - - render() { - const {t} = this.props; - if (store.subscriptionStore.isSubscribed) { - return ( -
- {/*

Manage your data

*/} - -
- -
this.changeRoute('dataagreements')}> - -
-

{t("landingPage.usagePurpose")}

-

{t("userRequests.description")}

- - - - -
this.changeRoute('downloaddata')}> - -
-

{t("landingPage.downloadData")}

-

{t('downloadData.description')}

- - - -
this.changeRoute('deletedata')}> - -
-

{t("landingPage.deleteData")}

-

{t('deleteData.description')}

- - {/* - -
this.changeRoute('managedata')}> - -
-

Manage your data

-

{overview.manageData}

- - */} - {/* - -
this.changeRoute('managedata')}> - -
-

User Requests

-

{overview.userRequests}

- - */} - + changeRoute = (path) => { + history.push(`/dashboard/${path}`); + }; -
this.changeRoute('logs')}> - -
-

{t("landingPage.viewLogs")}

-

{t('viewlogs.description')}

- - - - ); - } else { - return
- } - } + render() { + const { t } = this.props; + return ( +
+ {/*

Manage your data

*/} + +
+
this.changeRoute("dataagreements")} + > + +
+

{t("landingPage.usagePurpose")}

+

+ {t("userRequests.description")} +

+ + +
this.changeRoute("logs")} + > + +
+

{t("landingPage.viewLogs")}

+

+ {t("viewlogs.description")} +

+ + + + ); + } } -export default withNamespaces()(MenuGrid); \ No newline at end of file +export default withNamespaces()(MenuGrid); diff --git a/src/Components/ManageMenu/index.js b/src/Components/ManageMenu/index.js index 0af635bc4..27d639384 100644 --- a/src/Components/ManageMenu/index.js +++ b/src/Components/ManageMenu/index.js @@ -1,198 +1,20 @@ import React, { Component } from "react"; -import { observer } from "mobx-react"; -import { Route, Link, Switch, Router, Redirect } from "react-router-dom"; - +import { Route, Switch, Redirect } from "react-router-dom"; import MenuGrid from "./MenuGrid"; import Tab from "Components/Tab"; - -import { Row, Col, Icon, Spin } from "antd"; -import { history } from "../../history"; +import { Row } from "antd"; import CollapseUsage from "Components/CollapseUsage"; -import DataRequestTable from "Components/DataRequestTable"; import LogsTable from "Components/Table"; -import Timeline from "Components/Timeline"; -import { store, Status } from "../../Provider/store"; -import OpenInApp from "../OpenInApp/OpenInApp"; -import SubscribeToOrganization from "../SubscribeToOrganization/SubscribeToOrganization"; +import { store } from "../../Provider/store"; import { withNamespaces } from "react-i18next"; -//Data for timeline component -const data = { - nodes: [ - { - title: "Acknowledged", - dataIndex: Status.acknowledged - }, - { - title: "Processed", - dataIndex: "processed" - } - ] -}; - const DataAgreements = withNamespaces()(({ t }) => ( )); -const deleteData = observer( - withNamespaces()(({ t }) => { - const dataDeleteRequest = store.dataDeleteRequest; - let status = null; - let requestedTime = null; - if (store.dataRequest.isFetching) { - const antIcon = ( - - ); - return ( -
- -
- ); - } - if (dataDeleteRequest.length > 0) { - status = - dataDeleteRequest[dataDeleteRequest.length - 1]["status"] === - (Status.processedWithAction || Status.processedWithoutAction) - ? "processed" - : dataDeleteRequest[dataDeleteRequest.length - 1]["status"]; - requestedTime = - dataDeleteRequest[dataDeleteRequest.length - 1]["requested"]; - } - - return ( - - {/*
*/} -
- -
- {status && status.length > 0 && ( - - )} - {!status && ( -
-

{t("deleteData.emptyMessage")}

-
-

- {t("deleteData.createOne")}{" "} - - {t("dashboard.userRequest")} - {" "} - {t("deleteData.andThen")}{" "} - {t("userRequests.newRequest")}!. -

-
- )} - - - - - ); - }) -); -const downloadData = observer( - withNamespaces()(({ t }) => { - const dataDownloadRequest = store.dataDownloadRequest; - let status = null; - let requestedTime = null; - if (store.dataRequest.isFetching) { - const antIcon = ( - - ); - return ( -
- -
- ); - } - if (dataDownloadRequest.length > 0) { - status = - dataDownloadRequest[dataDownloadRequest.length - 1]["status"] === - (Status.processedWithAction || Status.processedWithoutAction) - ? "processed" - : dataDownloadRequest[dataDownloadRequest.length - 1]["status"]; - requestedTime = - dataDownloadRequest[dataDownloadRequest.length - 1]["requested"]; - } - return ( - - {/*
*/} -
- -
- {status && ( - - )} - {!status && ( -
-

{t("downloadData.emptyMessage")}

-
-

- {t("deleteData.createOne")}{" "} - - {t("dashboard.userRequest")} - {" "} - {t("deleteData.andThen")}{" "} - {t("userRequests.newRequest")}!. -

-
- )} - - - - - ); - }) -); -const manageData = withNamespaces()(({t}) => ( - -
- - - -
-
-)); -const Logs = withNamespaces()(({t}) => ( +const Logs = withNamespaces()(({ t }) => (
@@ -205,7 +27,6 @@ const Logs = withNamespaces()(({t}) => ( class index extends Component { componentDidMount() { // console.log('match',this.props.match); - store.fetchDataRequest(); } render() { @@ -213,19 +34,11 @@ class index extends Component { return (
- - - - -
); } diff --git a/src/Components/OpenInApp/OpenInApp.jsx b/src/Components/OpenInApp/OpenInApp.jsx deleted file mode 100644 index a485194c6..000000000 --- a/src/Components/OpenInApp/OpenInApp.jsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, {Component} from "react"; - -//Store -import {store} from "../../Provider/store"; -import {observer} from "mobx-react"; - -//Styles -import "./openinapp.css"; - -@observer -class OpenInApp extends Component { - - state = { - isOpen: true - }; - - getOS = () => { - let userAgent = window.navigator.userAgent, - platform = window.navigator.platform, - macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], - windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'], - iosPlatforms = ['iPhone', 'iPad', 'iPod'], - os = null; - - if (macosPlatforms.indexOf(platform) !== -1) { - os = 'Mac OS'; - } else if (iosPlatforms.indexOf(platform) !== -1) { - os = 'iOS'; - } else if (windowsPlatforms.indexOf(platform) !== -1) { - os = 'Windows'; - } else if (/Android/.test(userAgent)) { - os = 'Android'; - } else if (!os && /Linux/.test(platform)) { - os = 'Linux'; - } - - return os; - }; - - handleClose = () => { - localStorage.setItem("isOpen", "0"); - this.setState({isOpen: false}); - }; - - render() { - - const redirectUrl = store.qrStore.shortLink === "" ? store.config.firebase.deeplink : store.qrStore.shortLink; - - if (this.getOS() === "iOS" && localStorage.getItem("isOpen") === null) { - return ( - - ) - } else if (this.getOS() === "Android" && localStorage.getItem("isOpen") === null) { - return ( - - ) - } else { - return ( -
- ) - } - - } - -} - - -export default OpenInApp diff --git a/src/Components/OpenInApp/openinapp.css b/src/Components/OpenInApp/openinapp.css deleted file mode 100644 index f0d2dfcfe..000000000 --- a/src/Components/OpenInApp/openinapp.css +++ /dev/null @@ -1,63 +0,0 @@ -.openInAppSliver { - width: 100%; - position: fixed; - bottom: 0; - z-index: 10000; - color: white !important; - text-decoration: none; - background-color: #1a8ffd; - height: 6vh; - display: flex; - justify-content: center; - align-items: center; - opacity: 0.8; - /* This timing applies on the way IN */ - transition-timing-function: ease-out; - - /* A litttttle slower on the way in */ - transition: 0.25s; - - /* Move into place */ - transform: translateY(0); -} - -.openInAppSliver a { - color: #ffffff; -} - -.openInAppSliver a:visited { - color: #ffffff; - font-weight: bold; -} - -.appLinkContainer { - position: relative; - width: 100%; - text-align: center; -} - -.close { - position: absolute; - right: 32px; - width: 32px; - height: 32px; - opacity: 1; - color: #fff; -} -.close:hover { - opacity: 1; -} -.close:before, .close:after { - position: absolute; - left: 15px; - content: ' '; - height: 15px; - width: 2px; - background-color: #fff; -} -.close:before { - transform: rotate(45deg); -} -.close:after { - transform: rotate(-45deg); -} diff --git a/src/Components/OrganizationInfo/index.js b/src/Components/OrganizationInfo/index.js index 2c2431644..bd5554732 100644 --- a/src/Components/OrganizationInfo/index.js +++ b/src/Components/OrganizationInfo/index.js @@ -1,21 +1,21 @@ -import React, {Component} from 'react'; -import {observer} from 'mobx-react'; +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; import './orgInfo.css'; -import {Avatar, Empty} from 'antd'; +import { Avatar, Empty } from 'antd'; -import {store} from 'Provider/store'; +import { store } from 'Provider/store'; // import test from 'Components/CoverImage/test.png'; @observer class OrganizationInfo extends Component { render() { - const {Name, Location, PolicyURL, Type, CoverImageURL} = store.organizationStore.data; - const {logoImageURI, logoImageDescription} = store.organizationStore; + const { Name, Location, PolicyURL } = store.organizationStore.data; + const { logoImageURI, logoImageDescription } = store.organizationStore; return (
- {logoImageURI ? : - } + {logoImageURI ? : + }

{Name || 'No Name'}

{/*

{`Type : ${Type && Type.Type || 'No Type'}`}

*/} diff --git a/src/Components/PrivacyPolicy/PrivacyPolicy.jsx b/src/Components/PrivacyPolicy/PrivacyPolicy.jsx deleted file mode 100644 index b01e4e5f4..000000000 --- a/src/Components/PrivacyPolicy/PrivacyPolicy.jsx +++ /dev/null @@ -1,279 +0,0 @@ -import React, {Component} from "react"; - -//Store -import {store, auth} from "../../Provider/store"; -import {observer} from "mobx-react"; - -//Styles -import "./privacypolicy.css"; - -import defaultLogo from "assets/icons/igrant.io_200X200.jpg"; - -@observer -class PrivacyPolicy extends Component { - getPrivacyPolicy(orgID) { - if (orgID === "5de11ef088ae12000184f7c4") { - return "

This is TABY

"; - } else { - return "

This is not TABY

"; - } - } - - render() { - const {url} = store.config.logo; - console.log(store.config.organizationId); - - return store.config.organizationId !== "5de11ef088ae12000184f7c4" ? ( -
-
-
-
- -
-
-
-
-

DEFAULT POLICY

-

- This is the default policy page for all the usage purposes. This - is to inform you that we use your data only for the purpose we - have shown. For each of your personal data attributes, you can - view and will be used only if you consent us to use it. You can - view the current status for all your personal data, the purposes - for which they are used and provide you the choice to opt-in or - opt-out. -

-
- -
-

MEETING AND EVENT REGISTRATIONS

-

- For the meetings and events registrations conducted by us, we - use your personal data. You may, at any time opt-out of the - usage of your data at the attribute level or at the purpose - level via our privacy dashboard or by using the opt-out features - available in the iGrant.io app. -

-
- -
-

NEWSLETTERS AND INFORMATION MAILS

-

- As a member you receive timely information via our newsletters. - You may, at any time opt-out of the usage of your data at the - attribute level or at the purpose level via our privacy - dashboard or by using the opt-out features available in the - iGrant.io app. -

-
-
-
-
- ) : ( -
-
-
-
- -
-
-
-
-

Personuppgiftshantering på Täby Golf

-

- Det finns tre regelverk som styr databehandling av - personuppgifter i Golfsverige. Dessa regler gäller för alla - fysiska personer (golfspelare, ledare och anställda inom golfen) - samt alla juridiska personer (alla golforganisationer). De - styrande regelverken är Dataskyddsförordningen (GDPR), Idrottens - Uppförandekod samt GIT-bestämmelserna. Genom att använda våra - tjänster accepterar du vår dataskyddspolicy och vår behandling - av dina personuppgifter. Du godkänner att Täby Golf AB och Täby - Golfklubb (nedan kallade Täby Golf) använder elektroniska - kommunikationskanaler för att skicka information till dig. Du - kan enkelt kontrollera vilken data som hanteras kring dig samt - för vilket syfte. Detta gör du genom att logga in på din - integritetspanel (här). Har du frågor om GDPR eller någon av de - andra regelverken kan du alltid kontakta klubbens kansli - info@xxxxxxxxxx.se -

-
- -
-

Allmänna villkor

-

- 1. Golf-ID och personuppgifter som hanteras i kontraktuellt - syfte -

-

- När golfspelaren blir medlem och får ett Golf-ID blir han/hon - automatiskt bunden av stadgar, GIT bestämmelserna och beslut som - fattas av golforganisationen. GIT bestämmelserna styr all - behandling av personuppgifter som återfinns i GIT. Genom - GIT-bestämmelserna regleras också att golfklubben/golfbolaget är - personuppgiftsansvarig för huvuddelen av databehandlingarna i - GIT. SGF är i de fallen personuppgiftsbiträde till - golfklubbarna/golfbolagen. I en del andra fall som exempelvis - förbundstävlingar och tidningen Svensk Golf är SGF - personuppgiftsansvarig. SGF, GDF, golfklubbarna, golfbolagen, - golfspelarna och ett antal andra organisationer och bolag (tex - klubbarnas egna driftsbolag) är juridiskt bundna av - GIT-bestämmelserna. Medlemsinformation delas endast med tredje - part om uttryckligt samtycke finns (se paragraf 3 nedan) med - undantag för företag som agerar biträden till klubben eller är - en naturlig del av klubbens verksamhet, så som -

-
    -
  • SGF
  • -
  • GDF
  • -
  • Teeview (golfträning)
  • -
  • Kansliet.se (redovisning)
  • -
  • iGrantX (GDPR, samtyckeshantering)
  • -
  • Svensk Golf (Golftidning)
  • -
  • Kommunen (LOK-stöd samt Aktivitetsstöd….)
  • -
  • ...
  • -
- -

- Täby Golf tillämpar strikt GIT access dvs endast de individer - som har ett uttryckligt ansvar att behandla medlemsdata t ex i - samband med tävlingar, juniorverksamhet, styrelsearbete etc, har - access till GIT. Dessa individer ha även genomgått utbildning i - GDPR. Medlemsdata som behandlas i GIT är följande: -

-
    -
  • Golf-ID
  • -
  • Namn
  • -
  • Adress
  • -
  • Telefonnummer
  • -
  • E-postadress
  • -
  • Handikapp (gällande samt revisionshistorik)
  • -
  • - Historik kring sällskapsrundor (tidpunkt, spelsällskap samt - registrerad score) -
  • -
  • - Information kring tävlingsrundor (tidpunkt, spelsällskap, - registrerad score samt placering) -
  • -
-

- Informationen finns lagrad 24 månader efter avslutat medlemskap. -

-

- 2. Behandling av personuppgifter utanför GIT - legitimt intresse -

-

- E-post hantering faller utanför GIT-bestämmelsen och RF:s - Uppförandekod. Täby Golf kommer att spara e-post högst 24 - månader om det behövs, annars raderar vi informationen direkt. -

-

Persondata som behandlas:

-
    -
  • Namn
  • -
  • Golf-ID
  • -
  • E-postadress
  • -
-

3. Hantering av personuppgifter som kräver samtycke

-

- På Täby Golf använder vi samtycke som laglig grund för viss - hantering av dina personuppgifter. Vi anser att detta ökar - transparensen kring klubbens hantering av personlig data men det - stärker också individens kontroll över vilken persondata som - används och till vilket syfte. All samtyckeshantering kan ske - via Täby Golfs integritetspanel. En uppdateringe i - integritetspanelen medför automatisk uppdatering av - samtyckeshantering i min Golf där det finns överlapp (TBC). -

-

- 3.1 Delning av data med tredje part i syfte att generera - sponsorintäkter -

-

- Delning av medlemsdata till tredje part sker på dina villkor och - med ditt uttryckliga samtycke. Täby Golf har, i enlighet med - gällande dataskyddsförordning, för avsikt att generera intäkter - genom sponsoring. Medlemmar som samtycker till delning av deras - data till medverkande sponsorföretag, bidrar till - sponsorintäkter till klubben och/ eller kan komma att erhålla - erbjudanden från medverkande företag. Medlemmar som samtycker - till datadelning har rätt att bestämma vilka företag hens data - delas med. Du kan när som helst samtycka till delning av data - och du kan när som helst dra tillbaka ditt samtycke. Ditt - samtycke dras automatiskt tillbaka när du avregistreras som - medlem i klubben. Följande data kan komma att delas (se varje - företag). Notera att du endast kan dra tillbaka samtycke på - ändamålsnivå och ej per attribut när det gäller sponsoravtal. -

-

- 3.2 Delning av data med tredje part i syfte att underlätta - arbetet på klubben (?) -

-

- Täby Golf kan komma att dela data med externa aktörer som verkar - på eller i nära samarbete med klubben. Hit räknas följande - bolag…..Restaurangen….? -

-

- Information som kan delas, efter medlemmens samtycke, är: -

-
    -
  • Namn
  • -
  • Matpreferenser (?)/ allergier
  • -
-

3.3 Medlemskommunikation

-

- Täby Golf använder elektroniska kommunikationskanaler för att - skicka ut information. Man har alltid rätt att kontakta oss och - radera sina personuppgifter från våra listor. -

-

- Personuppgifter som används i medlemskommunikationen. -

-
    -
  • Golf-ID
  • -
  • E-mail
  • -
  • Telefonnummer (?)
  • -
-

- 3.4 Fotografering, bildpublicering -

-

- Publicering av namn och bild på hemsida eller sociala medier kan - vara integritetskänsligt för många människor. Det gäller - särskilt för barn. Det finns varken ett generellt tillstånd - eller förbud i GDPR och Idrottens uppförandekod mot att - publicera vimmelbilder, spelbilder från banan eller bilder på - pristagare. Tvärtom är det viktigt med bilder och texter om - medlemmarna för att skapa en inkluderande anda och klubbkänsla. - Täby Golf behöver ett samtycke innan bilder publiceras. -

-

4. ÖVRIGT

-

- 4.1 Andra rättigheter som registrerad medlem -

-

- Portabilitet, rättning av data eller samtycken (min Golf) vs - iGrantX (måste automatiseras…), access till data….kontakta - kanslien? -

-

4.2 Greenfeeboken

-

- Den klassiska greenfeeboken som ligger i greenfee efter - stängningsdags uppfyller inte dataskyddsförordningens - bestämmelser. Boken innehåller personuppgifter som är - strukturerade och ger mycket information till den som tar del av - uppgifterna. Så vi kommer inte längre lägga ut en greenfeebok, - utan man får skriva namn, golf id och betalsätt på ett kuvert - som skickas in i brevinkastet i receptionen (som är låst). -

- -
-
-
-
- ); - } -} - -export default PrivacyPolicy; diff --git a/src/Components/PrivacyPolicy/privacypolicy.css b/src/Components/PrivacyPolicy/privacypolicy.css deleted file mode 100644 index 12aee16dd..000000000 --- a/src/Components/PrivacyPolicy/privacypolicy.css +++ /dev/null @@ -1,40 +0,0 @@ -/*CSS*/ -html { scroll-behavior: smooth; } - -.page-container { - display: flex; - justify-content: center; - align-items: center; -} - -.content-container { - width: 600px; -} - -.content-container .logo { - text-align: center; - width: 150px; - height: 150px; - padding: 16px; -} - -.content-container .logo img { - width: 100%; - border-radius: 50%; -} - -.privacy-content { - line-height: 21px; - text-align: justify; -} - -.logo-container { - margin-top: 40px; - display: flex; - justify-content: center; -} - -.privacy-policy-text { - margin-top: 40px; - padding: 15px; -} \ No newline at end of file diff --git a/src/Components/Register/Register.jsx b/src/Components/Register/Register.jsx deleted file mode 100644 index 287ca773b..000000000 --- a/src/Components/Register/Register.jsx +++ /dev/null @@ -1,671 +0,0 @@ -import React, {Component} from "react"; -import ReactDOM from "react-dom"; -//Store -// Authorization -import {auth, store} from "Provider/store"; -//Mobx -import {observer} from "mobx-react"; -//i18n -import {withNamespaces} from "react-i18next"; -import {LanguageSelector} from "../Login/LanguageSelector"; -//Styles -import "./register.css"; -// assets -import defaultLogo from 'assets/icons/igrant.io_200X200.jpg'; -import {Logo} from "../Login/Logo"; -// custom components -import CustomPhoneNumber from "../CustomPhoneNumber/CustomPhoneNumber"; -import CustomOtpInput from "../CustomOtpInput/CustomOtpInput"; -// Antd -import {Button, Checkbox, Divider, Form, Input, Spin} from "antd"; -import {getSession} from "authorization/utils"; - - -import {antIcon} from "../Login/antIcon"; -import {history} from "../../history"; -import {setSession} from "../../authorization/utils"; -import {Link} from "react-router-dom"; -import {services} from "../../Provider/store"; -import axios from "axios"; - -@observer -class Register extends Component { - - state = { - showOtpScreen: false, - showPasswordScreen: false, - registrationScreen: true, - showSuccessScreen: false, - consentToNewsletters: false, - values: {} - }; - - componentWillMount() { - if (auth.isLoginValid()) { - auth.isAuthenticated = true; - auth.accessToken = getSession('access_token'); - auth.refreshToken = getSession('refresh_token'); - auth.userId = getSession('userId'); - store.user.name = getSession('username'); - store.user.email = getSession('email'); - store.user.lastVisit = new Date(getSession('lastVisit')).toLocaleString(); - history.push("/dashboard"); - } - } - - componentDidMount() { - const element = ReactDOM.findDOMNode(this); - element.addEventListener("keydown", e => { - this.handleKeydown(e); - }); - - - console.log("ORGANIZATION ID : ", store.config.organizationId); - - } - - // handling form submission when enter key is pressed - handleKeydown(e) { - - if (this.state.registrationScreen) { - if ((e.keyCode === 13) && (e.shiftKey === false)) { - this.handleRegistration(); - } - } - - if (this.state.showPasswordScreen) { - if ((e.keyCode === 13) && (e.shiftKey === false)) { - e.preventDefault(); - this.handleCreateAccount(); - } - } - } - - clearError = () => { - if (store.authStore.error) { - store.authStore.error = ''; - } - }; - - handleRegistration = () => { - - - this.clearError(); - - this.props.form.validateFields((err, values) => { - - // saving the state - this.setState({values}); - - console.log("Current consent value : ", values.consentToNewsletters); - - // saving consent to newsletter value - if (store.config.organizationId === store.config.iGrantOrganizationId) { - this.setState({consentToNewsletters: values.consentToNewsletters}); - console.log("Storing consent value...."); - } - - if (!err) { - - if (values.MobileNumber.rawValue && values.Email) { - store.authStore.isLoading = true; - - // validating email - const validateEmailRequest = auth.validateEmail(values.Email); - if (validateEmailRequest) { - validateEmailRequest.then((res) => { - - // debug - console.log(res); - - if (res.data.Result !== undefined) { - if (!res.data.Result) { - // Email is already in use - store.authStore.isLoading = false; - store.authStore.error = res.data.Message - - } else { - - // Validate phone before proceeding. - const validatePhoneRequest = auth.validatePhone(values.MobileNumber.rawValue); - if (validatePhoneRequest) { - validatePhoneRequest.then((res) => { - if (res.data.Result !== undefined) { - if (!res.data.Result) { - - // Phone is already in use - store.authStore.isLoading = false; - store.authStore.error = res.data.Message - - } else { - - // Phone is not in use. - // proceeding to send otp. - this.handleSendOtp(values.MobileNumber.rawValue, values.Email) - } - } else { - store.authStore.isLoading = false; - } - }).catch((error) => { - this.handleError(error); - }) - } - } - } else { - store.authStore.isLoading = false; - } - }).catch((error) => { - this.handleError(error); - }); - } - } - } - }); - - }; - - handleSendOtp = (mobileNumber, email) => { - - console.log("Current consent value : ", this.state.consentToNewsletters); - - if (mobileNumber && email) { - store.authStore.isLoading = true; - - // sending otp - const sendOtpRequest = auth.sendOtp(mobileNumber, email); - if (sendOtpRequest) { - sendOtpRequest.then((res) => { - store.authStore.isLoading = false; - - // toggling to otp screen. - this.setState({showOtpScreen: true}); - this.setState({registrationScreen: false}); - this.setState({showPasswordScreen: false}); - - }).catch((error) => { - this.handleError(error); - }); - } - } - - - }; - - reSendOtp = () => { - - this.clearError(); - - this.props.form.validateFields((err, values) => { - if (!err) { - this.handleSendOtp(values.MobileNumber.rawValue, values.Email); - } - }); - }; - - verifyOtp = () => { - - this.clearError(); - - console.log("Current consent value : ", this.state.consentToNewsletters); - - - this.props.form.validateFields((err, values) => { - if (!err) { - - if (values.otp !== undefined) { - if (values.otp.rawValue.length === 6) { - store.authStore.isLoading = true; - - // debug - console.log(values); - - // sending otp - const verifyOtpRequest = auth.validateOtp(values.MobileNumber.rawValue, values.otp.rawValue); - if (verifyOtpRequest) { - verifyOtpRequest.then((res) => { - store.authStore.isLoading = false; - - - if (res.data.Result !== undefined) { - if (!res.data.Result) { - // Email is already in use - store.authStore.isLoading = false; - store.authStore.error = res.data.Message - - } else { - // Todo: Redirect set password page. - // toggling to password screen. - this.setState({showOtpScreen: false}); - this.setState({registrationScreen: false}); - this.setState({showPasswordScreen: true}); - } - } else { - store.authStore.isLoading = false; - } - - - }).catch((error) => { - this.handleError(error); - }); - } - } - } - } - }); - }; - - handleCreateAccount = () => { - - this.clearError(); - - console.log("Current consent value : ", this.state.consentToNewsletters); - - this.props.form.validateFields((err, values) => { - - - if (!err) { - - - if (values.Password !== undefined) { - if (values.Password.length > 0) { - - store.authStore.isLoading = true; - - const registerRequest = auth.register(values.Email, values.Name, values.Password, values.MobileNumber.rawValue); - - if (registerRequest) { - registerRequest.then((res) => { - - // handle redirection or showing success message and background login - this.handleLoginRedirection(); - - - }).catch((error) => { - this.handleError(error); - }); - } - } - - } - - - } - - - }); - - }; - - // for background login after account creation. - handleLoginRedirection = () => { - this.props.form.validateFields((err, values) => { - - console.log("Current consent value : ", this.state.consentToNewsletters); - - if (!err) { - - store.authStore.isLoading = true; - - const backgroundLoginRequest = auth.backgroundLogin(values.Email, values.Password); - - if (backgroundLoginRequest) { - - backgroundLoginRequest.then((res) => { - - if (res.status === 200) { - - // login success - - let result = res.data; - store.authStore.error = null; - - // Storing authentication details. - if (result.Token) { - - - // handling remember me. - if (store.authStore.isRemember) { - setSession({ - ...result.Token, - userId: result.User.ID, - username: result.User.Name, - email: result.User.Email, - lastVisit: result.User.LastVisit - }); - } - - // handling auth details. - store.authStore.accessToken = result.Token.access_token; - store.authStore.refreshToken = result.Token.refresh_token; - store.authStore.userId = result.User.ID; - store.authStore.isAuthenticated = true; - - // Todo: If organization is iGrant.io handle consent to newsletter - // Todo: Send welcome email (From backend) - // api url for consenting -> https://demo-api.igrant.io/v1/organizations/5c1509c75430460001af6232/users/5dc036c327a4ad00011f93b2/consents/5dc036ca27a4ad00011f93b3/purposes/5c150a405430460001af6237/status - // api payload -> {Consented: "Allow"} - - // only update consent if user has consented to it. - if (this.state.consentToNewsletters) { - const endpoint = store.config.serviceUrls.organization.purposesAndConsents; - const token = store.authStore.accessToken; - const userId = store.authStore.userId; - if (token) { - try { - const request = axios.get(`${endpoint}/${userId}/consents`, {headers: {'Authorization': `Bearer ${token}`}}); - if (request) { - request - .then(res => { - if (res.status === 200) { - store.purposesAndConsents.data = res.data['ConsentsAndPurposes']; - store.purposesAndConsents.ID = res.data['ID']; - store.purposesAndConsents.loadingUiStore = store.mapToLoadingUiStore([...store.purposesAndConsents.data]); - store.purposesAndConsents.isFetching = false; - - // update the purpose to allow - // store.updateAllAttribute("Allow", "5c150a405430460001af6237"); - - - let consentsId = store.purposesAndConsents.ID; - - - const endpoint = store.config.serviceUrls.organization.purposesAndConsents; - const token = store.authStore.accessToken; - const userId = store.authStore.userId; - const purposeId = store.config.newsLetterConsentId; - - let body = {Consented: "Allow"}; - - if (token) { - try { - const request = axios.post(`${endpoint}/${userId}/consents/${consentsId}/purposes/${purposeId}/status`, body, {headers: {'Authorization': `Bearer ${token}`}}); - - - if (request) { - request - .then(res => { - if (res.status === 200) { - let responseData = res.data; - if (responseData['ConsentsAndPurposes']) { - store.purposesAndConsents.data = responseData['ConsentsAndPurposes'];//Push updated purpose into store - // message.success('Successfully updated all attributes.'); - store.purposesAndConsents.loadingUiStore[purposeId]['isLoading'] = false;//Set loading mask as true - } else { - console.log('failed to update all attribute.Response doesnt contain "ConsentsAndPurposes"'); - store.purposesAndConsents.loadingUiStore[purposeId]['isLoading'] = false;//Set loading mask as true - } - } - }) - .catch(error => { - store.purposesAndConsents.loadingUiStore[purposeId]['isLoading'] = false;//Set loading mask as true - // message.error('Failed to update all attribute.'); - store.restore(); - console.error(error); - }) - } - } catch (error) { - console.error('Axios Error :', error); - } - } else { - console.log('token doesnt exist'); - } - } - }) - .catch(error => console.error(error)) - } - } catch (error) { - console.error('Axios Error :', error); - } - } else { - console.log('token doesnt exist'); - } - - } - - - } else { - // message.error("Error from server response"); - console.error("no access_token in login response"); - } - - store.authStore.isLoading = false; - - // Toggle to registration success section. - this.setState({showOtpScreen: false}); - this.setState({registrationScreen: false}); - this.setState({showPasswordScreen: false}); - this.setState({showSuccessScreen: true}); - - - } - - - }).catch((error) => { - this.handleError(error); - }); - - - } - - - } - - }); - }; - - handleError = (error) => { - if (error.response !== undefined) { - if (error.response.data.Message !== undefined) { - store.authStore.error = error.response.data.Message - } else { - store.authStore.error = error.response.data.error_description - } - } - - store.authStore.isLoading = false; - console.error(error); - }; - - redirectToDashboard = () => { - history.replace('/dashboard'); - }; - - - render() { - const {t} = this.props; - const {url} = store.config.logo; - const {error} = store.authStore; - - const {showOtpScreen, registrationScreen, showPasswordScreen, showSuccessScreen} = this.state; - const formValues = this.state.values; - const {getFieldDecorator} = this.props.form; - - const loading = store.authStore.isLoading; - - - return ( -
-
-
-

{t("createAccountPageTitle")}

- - - {/* Registration form */} -
-
- - {getFieldDecorator("Name", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - - - - {getFieldDecorator("Email", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - - - - {getFieldDecorator('MobileNumber', { - rules: [], - })( - - )} - - -
- - {/* Handling consent to newsletter and other info for iGrant.io organization */} - { - (store.config.organizationId === store.config.iGrantOrganizationId) ? - -
- : null - } - - - {/* Registration continue */} -
- {loading ? : - } - -
- - {/* Registration input errors */} - {error &&
{error}
} - - - - {/* Forgot password section */} -
- {t("forgot")} -
- - {/* Sign in section */} -
- {t("haveAccount")} - {t("signinLink")} -
- - - {/* OTP Screen */} -
-
-

We'll need to verify you

-

A text message with 6 digit verification code was just send to {formValues.MobileNumber !== undefined ? formValues.MobileNumber.rawValue : ""} -

-
-
- - {getFieldDecorator("otp", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - - - {/* OTP continue */} -
- {loading ? : - } -
- - {/* OTP input errors */} - {error &&
{error}
} - - -
- Haven't received yet ? Resend - OTP -
- -
- - {/* Password Screen */} -
-
-

You'll need a password

-

Make sure it's 8 character or more.

-
-
-
- - {getFieldDecorator("Password", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - -
- {/* Registration continue */} -
- {loading ? : - } - -
- - {/* Registration input errors */} - {error &&
{error}
} - -
- - {/* User created successfully */} -
-
-

You are now a registered user.

-

Proceed to {t("dashboardLink")}

-
-
-
- -
-
-

Copyright © 2019 LCubed AB, Sweden. All rights reserved.

- - -
-
-
- ); - } -} - -const WrappedRegistration = Form.create({name: "normal_registration"})(Register); - -export default withNamespaces()(WrappedRegistration) diff --git a/src/Components/Register/register.css b/src/Components/Register/register.css deleted file mode 100644 index 7e94fa003..000000000 --- a/src/Components/Register/register.css +++ /dev/null @@ -1,288 +0,0 @@ -.registration-container { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - flex-direction: column; -} - -.registration-error { - color: #ff4b4b; - position: absolute; - text-align: center; - left: 0; - width: 100%; - font-size: 13px; -} - -/* .registration-rememberme{ - margin-top: 27px; -} */ -.registration-container-main { - flex-grow: 1; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 100%; - padding: 0px 10px; -} - -.registration-container-main .logo { - width: 150px; - height: 150px; - padding: 16px; -} - -.registration-container-main .logo > img { - width: 100%; - border-radius: 50%; -} - -.registration-form { - max-width: 400px; - padding: 1rem; - width: 100%; -} - -.registration-form .label-small { - font-size: 10px; -} - -.registration-form input { - font-size: 15px; - border: none; - outline: 0; -} - -.registration-btn { - width: 20px; - cursor: pointer; - margin-top: 4px; -} - -.right-arrow { - filter: opacity(0.6); -} - -.right-arrow:hover { - filter: opacity(0.9) -} - -.ant-input-affix-wrapper:hover { - border: none; - outline: none; -} - -.registration-form .ant-input:focus { - border: none; - outline: none; - box-shadow: none; -} - -.registration-form .registration-form-button { - width: 100%; - height: 42px; - font-size: 18px; -} - -.registration-footer { - width: 100%; - height: 100px; - /* position: fixed; - bottom: 0; */ - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - padding: 10px 0px 0px 0px; - flex-direction: column; -} - -.registration-footer p { - margin: 0; -} - -.registration-footer a { - margin-left: 8px; - margin-right: 8px; -} - -.registration-footer .copyright { - font-size: 10px; -} - -.registration-form .registration-input-group { - box-sizing: border-box; - padding: 5px; - border: 1px solid #cecece; - border-radius: 7px; -} - -.registration-form .ant-form-item { - margin: 0; -} - -.registration-form .registration-checkbox { - display: flex; - justify-content: center; - margin-top: 27px; -} - -.registration-form .registration-checkbox .ant-checkbox-wrapper { - display: flex; - align-items: center; - line-height: 20px; -} - - -.registration-form .registration-checkbox .ant-checkbox-wrapper span:nth-of-type(2) { - font-size: 15px; -} - -.registration-form .registration-divider { - width: 80%; - min-width: 80%; - margin: 0 auto; -} - -.registration-form .registration-divider-m0 { - margin: 0; -} - -.registration-form label { - font-size: 17px; -} - -.registration-form .forgot-password-actions { - margin-top: 10px; - text-align: center; -} - -.registration-form .forgot-password-actions a, -p { - line-height: 30px; - font-size: 14px; -} - -.registration-title { - font-size: 20px; - /* font-weight: 500; */ - margin: 0 0 0 0; - color: black; -} - -.anticon-right-circle { - cursor: pointer; - color: #8e8e8e; - transition: color 0.3s; - font-size: 1.7rem; -} - -.anticon-right-circle:hover { - color: rgb(92, 92, 92); -} - -.anticon-right-circle:active { - color: rgb(92, 92, 92); -} - -.ant-form-explain-holder { - display: none; -} - -@media only screen and (max-width: 600px) { - - .registration-title { - font-size: 20px; - } - - .registration-form input { - font-size: 14px; - } -} - -@media only screen and (max-height: 500px) { - .registration-footer-container { - display: none; - } - -} - -/*Register*/ -.register-actions { - text-align: center; -} - -.register-actions > a { - margin-left: 4px; -} - -.register-continue-box { - margin-top: 27px; - margin-bottom: 10px; - text-align: center; -} - -.register-continue-button { - line-height: 1.47059; - font-weight: 400; - letter-spacing: -.022em; - background: #0070c9 linear-gradient(#42a1ec, #0070c9); - border: 1px solid #07c; - border-radius: 4px; - color: #fff; - cursor: pointer; - display: inline-block; - min-width: 30px; - padding: 4px 15px; - text-align: center; - white-space: nowrap; -} - -/* Phone number input field */ -.mobile-number-input #phone-form-control { - width: 100%; - border: 0; -} - -.flag-dropdown { - border: 0 !important; - background-color: transparent !important; -} - -/* OTP Screen */ -.registration-otp-screen-message { - text-align: center; - margin-top: 10px; -} - -.register-otp-resend { - text-align: center; - margin-top: 15px; -} - -.otp-phone-number { - font-weight: bold; -} - -.registration-otp-screen-message p { - line-height: 20px; -} - -.registration-form.otp-form { - margin: 0 auto; -} - -/* Password scree */ -.registration-password-screen { - max-width: 400px; - padding: 1rem; - width: 100%; -} - -/* Registration success screen */ -.registration-user-screen { - text-align: center; -} \ No newline at end of file diff --git a/src/Components/SubscribeToOrganization/SubscribeToOrganization.jsx b/src/Components/SubscribeToOrganization/SubscribeToOrganization.jsx deleted file mode 100644 index 95b530c6d..000000000 --- a/src/Components/SubscribeToOrganization/SubscribeToOrganization.jsx +++ /dev/null @@ -1,219 +0,0 @@ -import React, {Component} from "react"; - -//Store -import {store, auth} from "../../Provider/store"; -import {observer} from "mobx-react"; - -import {LanguageSelector} from "../Login/LanguageSelector"; - -import {Logo} from "../Login/Logo"; -import defaultLogo from 'assets/icons/igrant.io_200X200.jpg'; - -import OpenInApp from "../OpenInApp/OpenInApp"; - -//Styles -import "./subscribetoorganization.css"; - -//i18n -import {withNamespaces} from "react-i18next"; -import {Button, Divider, Form, Input, Spin} from "antd"; -import {antIcon} from "../Login/antIcon"; -import {Link} from "react-router-dom"; -import ReactDOM from "react-dom"; -import {history} from "../../history"; - - -@observer -class SubscribeToOrganization extends Component { - - state = { - values: {} - }; - - componentDidMount() { - const element = ReactDOM.findDOMNode(this); - element.addEventListener("keydown", e => { - this.handleKeydown(e); - }); - } - - // handling form submission when enter key is pressed - handleKeydown(e) { - - if ((e.keyCode === 13) && (e.shiftKey === false)) { - e.preventDefault(); - this.handleSubscribe(); - } - - } - - // clears error - clearError = () => { - if (store.subscriptionStore.error) { - store.subscriptionStore.error = ''; - } - }; - - toInputUppercase = e => { - e.target.value = ("" + e.target.value).toUpperCase(); - - if (e.target.value.length === 4 || e.target.value.length === 9) { - e.target.value = e.target.value + "-" - } - }; - - // handles subscription - handleSubscribe = () => { - - - this.clearError(); - - this.props.form.validateFields((err, values) => { - - this.setState({values}); - - if (!err) { - - if (values.SubscriptionKey) { - store.subscriptionStore.isLoading = true; - - const subscribeToOrgRequest = store.handleSubscribeToOrg(values.SubscriptionKey); - - if (subscribeToOrgRequest) { - - subscribeToOrgRequest.then((res) => { - - if (res.status === 200) { - console.log(res); - - store.subscriptionStore.isSubscribed = true; - store.subscriptionStore.isLoading = false; - - // redirecting to dashboard - history.push("/"); - - // check if the qrType is not empty - if (store.qrStore.qrType !== "") { - - // checking if not yet redirected - if (store.qrStore.isRedirected !== true) { - - if (store.qrStore.qrType === "purpose") { - store.qrStore.isRedirected = true; - history.push("/dashboard/usagepurpose"); - } else if (store.qrStore.qrType === "organization") { - store.qrStore.isRedirected = true; - history.push("/dashboard/usagepurpose"); - } else { - store.qrStore.isRedirected = true; - history.push("/dashboard"); - } - } - - } else { - store.qrStore.isRedirected = true; - history.push("/"); - } - } - - }).catch((error) => { - this.handleError(error); - }) - - - } - - - } - - } - - - }); - - - }; - - handleError = (error) => { - if (error.response.data.Message !== undefined) { - store.subscriptionStore.error = error.response.data.Message - } else { - store.subscriptionStore.error = error.response.data.error_description - } - store.subscriptionStore.isLoading = false; - console.error(error); - }; - - handleLogout = () => { - auth.logout() - }; - - render() { - const {t} = this.props; - const {url} = store.config.logo; - const {error} = store.subscriptionStore; - const loading = store.subscriptionStore.isLoading; - const {getFieldDecorator} = this.props.form; - - return ( -
-
-
-

Subscribe to organization

-
-

Enter the 12-digit subscription key

-

To subscribe, enter the subscription key provided by us

-
-
-
- - {getFieldDecorator("SubscriptionKey", { - rules: []//[{ required: true, message: t("messages.username") }] - })( - - )} - -
- {/* Registration continue */} -
- {loading ? : - } - -
- - {/* Registration input errors */} - {error &&
{error}
} - - - - {/* Sign in section */} -
- Click - here - to logout -
- - -
- - - -
- ) - - } - -} - - -const WrappedLogin = Form.create({name: "subscribe_to_organization"})(SubscribeToOrganization); - -export default withNamespaces()(WrappedLogin); diff --git a/src/Components/SubscribeToOrganization/subscribetoorganization.css b/src/Components/SubscribeToOrganization/subscribetoorganization.css deleted file mode 100644 index 4427615aa..000000000 --- a/src/Components/SubscribeToOrganization/subscribetoorganization.css +++ /dev/null @@ -1,204 +0,0 @@ -.router-content-container { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - flex-direction: column; -} - -.router-content-container .router-container { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - flex-direction: column; -} -.subscribe-org-container { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - flex-direction: column; -} -.login-error{ - color: #ff4b4b; - position: absolute; - text-align: center; - left: 0; - width: 100%; - font-size: 13px; -} -/* .login-rememberme{ - margin-top: 27px; -} */ -.subscribe-org-container-main { - flex-grow: 1; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 100%; - padding: 0px 10px; -} -.subscribe-org-container-main .logo{ - width: 150px; - height: 150px; - padding: 16px; -} -.subscribe-org-container-main .logo > img { - width: 100%; - border-radius: 50%; -} -.login-form { - max-width: 400px; - padding: 1rem; - width: 100%; -} -.login-form .label-small{ - font-size : 10px; -} -.login-form input { - font-size: 15px; - border: none; - outline: 0; -} -.login-btn{ - width: 20px; - cursor: pointer; - margin-top: 4px; -} -.right-arrow{ - filter:opacity(0.6); -} -.right-arrow:hover{ - filter: opacity(0.9) -} -.ant-input-affix-wrapper:hover{ - border: none; - outline: none ; -} - -.login-form .ant-input:focus{ - border: none; - outline: none; - box-shadow: none; -} - -.login-form .login-form-button { - width: 100%; - height: 42px; - font-size: 18px; -} -.login-footer { - width: 100%; - height: 100px; - /* position: fixed; - bottom: 0; */ - display: flex; - align-items: center; - justify-content:center; - box-sizing: border-box; - padding: 10px 0px 0px 0px; - flex-direction: column; -} -.login-footer p{ - margin: 0; -} -.login-footer a{ - margin-left: 8px; - margin-right: 8px; -} -.login-footer .copyright{ - font-size: 10px; -} -.login-form .login-input-group{ - box-sizing: border-box; - padding: 5px; - border: 1px solid #cecece; - border-radius: 7px; -} -.login-form .ant-form-item{ - margin: 0; -} -.login-form .login-checkbox { - display: flex; - justify-content: center; - margin-top: 27px; -} -.login-form .login-divider { - width: 80%; - min-width: 80%; - margin: 0 auto; -} -.login-form .login-divider-m0{ - margin: 0; -} -.login-form label { - font-size: 17px; -} -.login-form .login-actions { - margin-top: 10px; - text-align: center; -} -.login-form .login-actions a, -p { - line-height: 30px; - font-size: 14px; -} -.login-title { - font-size: 20px; - /* font-weight: 500; */ - margin: 0 0 0 0; - color: black; -} -.anticon-right-circle { - cursor: pointer; - color: #8e8e8e; - transition: color 0.3s; - font-size: 1.7rem; -} -.anticon-right-circle:hover { - color: rgb(92, 92, 92); -} -.anticon-right-circle:active { - color: rgb(92, 92, 92); -} -.ant-form-explain-holder{ - display: none; -} -@media only screen and (max-width: 600px) { - - .login-title { - font-size: 20px; - } - .login-form input { - font-size: 14px; - } -} -@media only screen and (max-height: 500px) { - .login-footer-container{ - display: none; - } - -} - -/*Register actions*/ -.register-actions { - text-align: center; -} -.register-actions>a { - margin-left: 4px; -} - -.subscribe-org-content-header { - margin-top: 15px; - text-align: center; -} - -.subscribe-org-content-header p { - line-height: 15px; - font-size: 12px; -} \ No newline at end of file diff --git a/src/Components/Timeline/index.js b/src/Components/Timeline/index.js deleted file mode 100644 index 50867fd57..000000000 --- a/src/Components/Timeline/index.js +++ /dev/null @@ -1,83 +0,0 @@ -import React, { Component } from 'react'; -import {withNamespaces, Trans} from "react-i18next"; -import { Timeline as TimelineAntd, Icon } from 'antd'; -import {store,Status} from 'Provider/store'; -import { observer } from 'mobx-react'; - -//Style -import './timeline.css'; - -// @observer -// class Timeline extends Component { -// render() { -// const {status} = this.props; -// return ( -// -// {Status.initiated} -// {Status.acknowledged} -// {'Request processed'} -// -// ) -// } -// } - -class Timeline extends Component { - static defaultProps={ - mode: "horizontal" || "vertical" - } - - render() { - const { data, mode } = this.props; - - console.log("DEBUG FROM TIMELINE : ", data.nodes) - - const lastNode = data.nodes.find(x => x.dataIndex === data.status); - const lastNodeIndex = lastNode && data.nodes.indexOf(lastNode); - return ( - -
- {data && - data.nodes.map((node, i) => ( -
- {i !== 0 && ( -
- )} -
-
-
-
- {node.title} - -
- {node.subtitle &&
{node.subtitle}
} -
-
-
- {i <= lastNodeIndex && ( -
- )} -
-
-
- ))} -
- - ); - } -} - -export default withNamespaces()(Timeline); \ No newline at end of file diff --git a/src/Components/Timeline/timeline.css b/src/Components/Timeline/timeline.css deleted file mode 100644 index c0efb7bb2..000000000 --- a/src/Components/Timeline/timeline.css +++ /dev/null @@ -1,106 +0,0 @@ - - .timeline-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 0px 10px; - margin: 50px 0px; - } - .timeline-container.vertical { - flex-direction: column; - min-height: 400px; - } - .wrapper { - display: flex; - align-items: center; - flex: 1; - } - .wrapper.vertical { - flex-direction: column; - } - .wrapper:nth-child(1) { - flex: unset; - } - .circle { - width: 100%; - height: 100%; - background-color: rgb(19, 92, 161); - border-radius: 50%; - } - - .animate { - animation: scale 1s infinite ease-in-out; - } - - .node-container { - position: relative; - display: flex; - align-items: center; - justify-content: center; - } - - .node-title { - position: absolute; - min-width: 150px; - bottom: 100%; - padding-bottom: 2px; - line-height: 18px; - text-align: center - } - .node-title.vertical { - min-width: unset; - bottom: unset; - left: 100%; - padding-left: 5px; - } - .node-title .main-heading{ - font-size: 15px; - font-weight: 500; - } - .node-title .subtitle{ - font-size: 10px; - } - .node { - width: 35px; - height: 35px; - border-radius: 50%; - border: solid 2px rgb(19, 92, 161); - padding: 3px; - box-sizing: border-box; - position: relative; - } - - .line { - border: none; - margin: 0px 5px; - flex-grow: 1; - } - .line.vertical { - margin: 5px 0px; - } - .line-solid { - border-top: 2px solid rgb(19, 92, 161); - } - .line-dotted { - border-top: 2px dotted rgb(19, 92, 161); - } - .line-solid.vertical { - border-left: 2px solid rgb(19, 92, 161); - } - .line-dotted.vertical { - border-left: 2px dotted rgb(19, 92, 161); - } - - @keyframes scale { - 0% { - transform: scale(0.9); - } - 50% { - transform: scale(1); - } - 100% { - transform: scale(0.9); - } - } - \ No newline at end of file diff --git a/src/Components/index.js b/src/Components/index.js index 0b36b8e3c..6fba26843 100644 --- a/src/Components/index.js +++ b/src/Components/index.js @@ -1,11 +1,9 @@ import Login from './Login/Login'; -import Register from "./Register/Register"; import ForgotPassword from "./ForgotPassword/ForgotPassword" import DefaultLayout from './DefaultLayout/DefaultLayout'; export { Login, - Register, ForgotPassword, DefaultLayout } \ No newline at end of file diff --git a/src/Provider/store.js b/src/Provider/store.js index 1232efe70..35dca88be 100644 --- a/src/Provider/store.js +++ b/src/Provider/store.js @@ -1,23 +1,8 @@ -import { observable, computed, action } from "mobx"; +import { observable, action } from "mobx"; import i18n from "../localization/i18n"; import Auth from "../authorization/auth"; import Services from "../services"; import moment from "moment"; -import { history } from "../history"; -import { getSession } from "../authorization/utils"; - -export const Status = { - initiated: "Request initiated", - acknowledged: "Request acknowledged", - cancelled: "Request cancelled by user", - processedWithoutAction: "Request processed without action", - processedWithAction: "Request processed with action" -}; -export const RequestTypes = { - dataDownload: "Download Data", - dataDelete: "Delete Data", - dataUpdate: "Update Data" -}; class Store { @observable user = { @@ -26,30 +11,13 @@ class Store { lastVisit: "" }; @observable config = {}; + @observable authStore = { isLoading: false, isRemember: true, error: "" }; - @observable qrStore = { - isRedirected: false, - fromPath: "", - qrType: "", - purposeId: "", - shortLink: "", - isPurposeToggled: false, - isPurposeScrolled: false - }; - - @observable subscriptionStore = { - isFetching: true, - isLoading: false, - isSubscribed: false, - method: "", - error: "" - }; - @observable organizationStore = { isFetching: true, error: null, @@ -59,194 +27,19 @@ class Store { coverImageDescription: "No Data", logoImageDescription: "No Data" }; + @observable purposesAndConsents = { isFetching: true, data: null, ID: null, loadingUiStore: {} }; - @observable dataRequest = { - isFetching: true, - data: null, - form: null - }; + @observable historyLogs = { logs: [], isFetching: true }; - @computed get dataDeleteRequest() { - if (this.dataRequest.data) { - return this.dataRequest.data.filter( - item => item["requestType"] === RequestTypes.dataDelete - ); - } - } - - @computed get dataDownloadRequest() { - if (this.dataRequest.data) { - return this.dataRequest.data.filter( - item => item["requestType"] === RequestTypes.dataDownload - ); - } - } - - // QR store actions - @action setFromPath = fromPath => { - try { - // extracting shortlink from the path - let shortlink = fromPath.split("&"); - shortlink = shortlink[shortlink.length - 1]; - shortlink = shortlink.split("="); - shortlink = shortlink[shortlink.length - 1]; - - // extracting qrType from the path. - let qrType = fromPath.split("&"); - qrType = qrType[qrType.length - 2]; - qrType = qrType.split("="); - qrType = qrType[qrType.length - 1]; - - try { - // extracting purpose id from the path. - let purposeId = fromPath.split("&"); - purposeId = purposeId[purposeId.length - 3]; - purposeId = purposeId.split("="); - purposeId = purposeId[purposeId.length - 1]; - - if (qrType === "purpose") { - this.qrStore.purposeId = purposeId; - } - } catch (e) { - } - - if (qrType !== "") { - this.qrStore.qrType = qrType; - this.qrStore.fromPath = fromPath; - this.qrStore.shortLink = shortlink; - } - } catch (e) { - } - }; - - // QR store computations - @computed get getFromPath() { - return this.qrStore.fromPath; - } - - @computed get getQrType() { - return this.qrStore.qrType; - } - - @action handleSubscription = () => { - const request = services.fetchSubscriptionStatus(); - - if (request) { - request - .then(res => { - // if subscribed - // Todo : handle QR redirection - - // updating subscription status - this.subscriptionStore.isSubscribed = true; - - // check if the qrType is not empty - if (store.qrStore.qrType !== "") { - // checking if not yet redirected - if (store.qrStore.isRedirected !== true) { - if (store.qrStore.qrType === "purpose") { - store.qrStore.isRedirected = true; - history.push("/dashboard/usagepurpose"); - } else if (store.qrStore.qrType === "organization") { - store.qrStore.isRedirected = true; - history.push("/dashboard/usagepurpose"); - } else { - store.qrStore.isRedirected = true; - history.push("/dashboard"); - } - } - } else { - store.qrStore.isRedirected = true; - history.push("/"); - } - }) - .catch(error => { - if (error.request.status === 404) { - // not subscribed - - // not subscribed. - // check subscription method - - const request = services.fetchSubscribeMethods(); - - if (request) { - request - .then(res => { - this.subscriptionStore.method = res.data["Method"]; - - // updating fetching status - this.subscriptionStore.isFetching = false; - - if (this.subscriptionStore.method === "Key-Based") { - // redirect to subscription page - history.push("/dashboard/subscribe"); - } else { - // subscribing users without subscription key - const subscribeToOrgRequest = store.handleSubscribeToOrg( - "" - ); - - if (subscribeToOrgRequest) { - subscribeToOrgRequest - .then(res => { - if (res.status === 200) { - console.log(res); - - store.subscriptionStore.isSubscribed = true; - } - }) - .catch(error => { - console.log(error); - }); - } - } - }) - .catch(error => { - console.log(error); - }); - } - } else { - console.log(error); - } - }); - } - }; - - @action handleSubscribeToOrg = subscriptionKey => { - const request = services.addUserToOrg(subscriptionKey); - return request; - }; - - @action fetchDataRequest = () => { - let dataRequestsList = []; - Promise.all([services.getAlldataDelete(), services.getAlldataDownload()]) - .then(values => { - console.log("Promise all : ", values); - values.forEach(res => { - if (res.status === 200 && res.data !== null) { - dataRequestsList = [ - ...dataRequestsList, - ...this.toDataRequestTableModal(res.data) - ]; - } - }); - this.dataRequest.data = dataRequestsList; - console.log(dataRequestsList); - this.dataRequest.isFetching = false; - }) - .catch(error => { - console.error("Error in fetch data requests", error); - }); - }; @action fetchLogs = () => { const request = services.fetchLogs(); if (request) { @@ -266,6 +59,7 @@ class Store { }); } }; + @action fetchOrganization = () => { const request = services.fetchOrganization(); if (request) { @@ -350,6 +144,7 @@ class Store { getPurposeById = (id, purposeAndConsents) => { return purposeAndConsents.find(x => x["Purpose"]["ID"] === id); }; + getAttributeById = (purposeId, attributeId) => { const purpose = this.getPurposeById( purposeId, @@ -357,6 +152,7 @@ class Store { ); return purpose["Consents"].find(x => x["ID"] === attributeId); }; + getAttributesById = purposeId => { const purpose = this.getPurposeById( purposeId, @@ -370,6 +166,7 @@ class Store { let attribute = this.getAttributeById(purposeId, attributeId); attribute["Status"][key] = value; }; + @action updateAllAttributeUiStore = (purposeId, value, key) => { let attributes = this.getAttributesById(purposeId); @@ -377,6 +174,7 @@ class Store { att["Status"][key] = value; }); }; + @action filterPurposeById = purposeId => { let filtered = this.purposesAndConsents.data.filter( @@ -385,6 +183,7 @@ class Store { console.log("filterred", filtered); this.purposesAndConsents.data = filtered; }; + @action maintainCount = (purposeId, value) => { let purpose = this.getPurposeById(purposeId, this.purposesAndConsents.data); @@ -399,6 +198,7 @@ class Store { console.warn("value should be Allow or Disallow "); } }; + updateAllAttribute = (value, purposeId) => { this.purposesAndConsents.loadingUiStore[purposeId]["isLoading"] = true; //Set loading mask as true let consentsId = this.purposesAndConsents.ID; @@ -419,7 +219,7 @@ class Store { this.purposesAndConsents.data = - responseData["ConsentsAndPurposes"].filter(purpose => purpose.Consents !== null); //Push updated purpose into store + responseData["ConsentsAndPurposes"].filter(purpose => purpose.Consents !== null); //Push updated purpose into store // message.success('Successfully updated all attributes.'); @@ -500,45 +300,11 @@ class Store { }); } }; - sendDataRequest = () => { - const form = this.dataRequest.form; - if (form) { - form.validateFields((err, values) => { - if (!err) { - // console.log('Received values of form: ', values); - let requestType = values["requestType"]; - switch (requestType) { - case RequestTypes.dataDelete: - //Call data delete API - services.postDataDelete().then(res => { - if (res.status === 200) { - console.log("data-delete requested successfully"); - store.fetchDataRequest(); //Update Table - } - }); - break; - case RequestTypes.dataDownload: - //Call data download API - services.postDataDownload().then(res => { - if (res.status === 200) { - console.log("data-download requested successfully"); - store.fetchDataRequest(); //Update Table - } - }); - break; - case RequestTypes.dataUpdate: - //Call data update API - break; - default: - console.warn("Unknown data request type!"); - } - } - }); - } - }; + save = () => { this.saved = [...this.purposesAndConsents.data]; }; + restore = () => { if (this.saved) { action(() => (this.purposesAndConsents.data = [...this.saved])); @@ -560,6 +326,7 @@ class Store { return loader; }; + toLogsTableModal = arr => { let rows = [...arr]; let tableData = rows.map(row => { @@ -572,38 +339,6 @@ class Store { console.log(tableData); return tableData; }; - toDataRequestTableModal = (arr = []) => { - return arr.map(row => { - return { - requested: moment(row["RequestedDate"], "YYYY-MM-DD HH:mm:ss Z").format( - "MMM-DD-YYYY HH:mm:ss A" - ), - closed: - row["StateStr"] == Status.acknowledged || - row["StateStr"] == Status.initiated - ? "N/A" - : moment(row["ClosedDate"], "YYYY-MM-DD HH:mm:ss Z").format( - "MMM-DD-YYYY HH:mm:ss A" - ), - requestType: row["TypeStr"], - status: row["StateStr"], - ID: row["ID"], - key: row["ID"] - }; - }); - }; - - // computed((purposeId)=>{ - // let purpose = this.getPurposeById(purposeId); - // let consentsArr = [...purpose['Consents']]; - // let consentedCount = consentsArr.reduce((acc,cur)=>{ - // if(cur['Status']['Consented'] === 'Allow'){ - // acc.count++; - // } - // return acc; - // },{count:0}) - // return consentedCount.count; - // }) } export const store = new Store(); diff --git a/src/authorization/auth.js b/src/authorization/auth.js index de0474cc7..fa3bc5e79 100644 --- a/src/authorization/auth.js +++ b/src/authorization/auth.js @@ -1,8 +1,5 @@ import axios from "axios"; -// import {store} from "Provider/store"; -// import Config from "app.config.js"; import { setSession } from "./utils"; -import { message } from "antd"; import { history } from "../history"; @@ -90,10 +87,6 @@ class Auth { const currentDateInUTC = Math.floor((new Date()).getTime() / 1000); const refreshTokenExpiresIn = this.parseJwt(this.refreshToken).exp; - console.log("[DEBUG] Refresh token expires in (seconds): ", refreshTokenExpiresIn - currentDateInUTC); - - console.log("[DEBUG] Access token expires in (seconds) : ", accessTokenExpiresIn - currentDateInUTC); - if (refreshTokenExpiresIn - currentDateInUTC < 10) { // Refresh token is expired. @@ -103,7 +96,6 @@ class Auth { // Check if access token is expired if (accessTokenExpiresIn - currentDateInUTC < 60) { - console.log("[DEBUG] Access token expired"); let body = { refreshtoken: this.refreshToken, @@ -133,7 +125,6 @@ class Auth { }).catch(error => { - console.log("[DEBUG] Error while refreshing token : ", error); }); } } @@ -264,7 +255,6 @@ class Auth { endpoint = this.store.config.serviceUrls.logoutForOpenIDSubscriptionMethod; } - // console.log('DEBUG :',body); axios.post(endpoint, body, { headers: { "Content-Type": "application/json", @@ -296,7 +286,6 @@ class Auth { // parses the result after authentication from URL hash handleAuthentication = res => { - // console.log("DEBUG", store); this.store.authStore.isLoading = false; if (res.status === 200) { let result = res.data; @@ -322,9 +311,6 @@ class Auth { // message.success("Logged in successfully"); this.isAuthenticated = true; - // Todo : check if user is subscribed to this organization or not - // Todo : Update the store accordingly - this.store.subscriptionStore.isSubscribed = false; } else { // message.error("Error from server response"); console.error("no access_token in login response"); diff --git a/src/helper/translator.js b/src/helper/translator.js deleted file mode 100644 index 5136812eb..000000000 --- a/src/helper/translator.js +++ /dev/null @@ -1,5 +0,0 @@ -// Object.keys(jsonStrings).map(key=>jsonStrings[key]).join('\n') - -//jsonKeys = Object.keys(jsonStrings) - -// result.split('\n').reduce((acc,cur,i)=>{acc[jsonKeys[i]]=cur;return acc;},{}) \ No newline at end of file diff --git a/src/index.js b/src/index.js index d962fc627..d25fdc2aa 100644 --- a/src/index.js +++ b/src/index.js @@ -13,9 +13,7 @@ import App from "./App"; export const Init = (config = {}) => { const completeConfig = toConfigModal(config); if (completeConfig) { - //console.log(completeConfig); store.config = completeConfig; - //console.log(store.config) ReactDOM.render( , document.getElementById("root") diff --git a/src/localization/resources/index.js b/src/localization/resources/index.js index 8480d1f66..eb66dd3ad 100644 --- a/src/localization/resources/index.js +++ b/src/localization/resources/index.js @@ -1,5 +1,4 @@ import translationEN from '../locales/en/translation.json'; -import translationDE from '../locales/de/translation.json'; import translationSV from '../locales/sv/translation.json'; import translationPT from '../locales/pt/translation.json';