diff --git a/docker-compose.yml b/docker-compose.yml index a43fc7d3a..58c6d1dd8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,6 @@ services: - REDIS_SAFE_BROWSING_URI=redis://redis:6379/4 - SESSION_SECRET=thiscouldbeanything - GA_TRACKING_ID=UA-139330318-1 - - SGID_API_HOSTNAME=https://api.id.gov.sg - OG_URL=https://go.gov.sg - VALID_EMAIL_GLOB_EXPRESSION=*.gov.sg @@ -110,7 +109,7 @@ services: dockerfile: Dockerfile.maildev-logging command: bin/maildev --web 80 --smtp 25 --verbose ports: - - "1080:80" + - '1080:80' volumes: pgdata: diff --git a/package-lock.json b/package-lock.json index f2443dfc5..bc16de8bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@hapi/joi": "^17.1.1", "@material-ui/core": "^4.11.4", "@material-ui/lab": "^4.0.0-alpha.61", - "@opengovsg/sgid-client": "^2.0.0", "@sentry/react": "^6.11.0", "@sentry/tracing": "^6.8.0", "@sentry/webpack-plugin": "^1.15.1", @@ -4773,16 +4772,6 @@ "node": ">= 8" } }, - "node_modules/@opengovsg/sgid-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@opengovsg/sgid-client/-/sgid-client-2.0.0.tgz", - "integrity": "sha512-zqcVQz03zB7dAwWh2MJVRAmHYjK1EryqOPnbBgrkr8Jx8BjtcjFa4cCrHstwWP1kVkGomhi0C7e3TRvf1qYSFQ==", - "dependencies": { - "jose": "4.9.2", - "node-rsa": "1.1.1", - "openid-client": "5.4.0" - } - }, "node_modules/@opentelemetry/api": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.1.0.tgz", @@ -7515,14 +7504,6 @@ "node": ">=0.10.0" } }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -10364,6 +10345,7 @@ "version": "2.23.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz", "integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==", + "dev": true, "engines": { "node": ">=0.11" }, @@ -17185,14 +17167,6 @@ "node": ">= 0.6.0" } }, - "node_modules/jose": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.9.2.tgz", - "integrity": "sha512-EqKvu2PqJCD3Jrg3PvcYZVS7D21qMVLSYMDAFcOdGUEOpJSLNtJO7NjLANvu3SYHVl6pdP2ff7ve6EZW2nX7Nw==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/js-md4": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", @@ -19164,14 +19138,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" }, - "node_modules/node-rsa": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", - "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", - "dependencies": { - "asn1": "^0.2.4" - } - }, "node_modules/node-source-walk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-4.2.0.tgz", @@ -19338,14 +19304,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", @@ -19475,14 +19433,6 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, - "node_modules/oidc-token-hash": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", - "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", - "engines": { - "node": "^10.13.0 || >=12.0.0" - } - }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -19550,28 +19500,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openid-client": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.0.tgz", - "integrity": "sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ==", - "dependencies": { - "jose": "^4.10.0", - "lru-cache": "^6.0.0", - "object-hash": "^2.0.1", - "oidc-token-hash": "^5.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/openid-client/node_modules/jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/opentracing": { "version": "0.14.7", "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", @@ -30020,8 +29948,7 @@ "@material-ui/types": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", - "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", - "requires": {} + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" }, "@material-ui/utils": { "version": "4.11.2", @@ -30065,16 +29992,6 @@ "fastq": "^1.6.0" } }, - "@opengovsg/sgid-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@opengovsg/sgid-client/-/sgid-client-2.0.0.tgz", - "integrity": "sha512-zqcVQz03zB7dAwWh2MJVRAmHYjK1EryqOPnbBgrkr8Jx8BjtcjFa4cCrHstwWP1kVkGomhi0C7e3TRvf1qYSFQ==", - "requires": { - "jose": "4.9.2", - "node-rsa": "1.1.1", - "openid-client": "5.4.0" - } - }, "@opentelemetry/api": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.1.0.tgz", @@ -31982,8 +31899,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", - "dev": true, - "requires": {} + "dev": true }, "@webpack-cli/info": { "version": "1.3.0", @@ -31998,8 +31914,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz", "integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==", - "dev": true, - "requires": {} + "dev": true }, "@xtuc/ieee754": { "version": "1.2.0", @@ -32067,15 +31982,13 @@ "acorn-import-assertions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "requires": {} + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==" }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -32144,8 +32057,7 @@ "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" }, "amdefine": { "version": "1.0.1", @@ -32356,14 +32268,6 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -34265,8 +34169,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", - "dev": true, - "requires": {} + "dev": true }, "crc-32": { "version": "1.2.2", @@ -34604,13 +34507,13 @@ "date-fns": { "version": "2.23.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz", - "integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==" + "integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==", + "dev": true }, "date-fns-tz": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.3.4.tgz", - "integrity": "sha512-O47vEyz85F2ax/ZdhMBJo187RivZGjH6V0cPjPzpm/yi6YffJg4upD/8ibezO11ezZwP3QYlBHh/t4JhRNx0Ow==", - "requires": {} + "integrity": "sha512-O47vEyz85F2ax/ZdhMBJo187RivZGjH6V0cPjPzpm/yi6YffJg4upD/8ibezO11ezZwP3QYlBHh/t4JhRNx0Ow==" }, "dd-trace": { "version": "2.40.0", @@ -35690,15 +35593,13 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-alias": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz", "integrity": "sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.4", @@ -36059,8 +35960,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "requires": {} + "dev": true }, "eslint-scope": { "version": "5.1.1", @@ -36412,8 +36312,7 @@ "express-joi-validation": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/express-joi-validation/-/express-joi-validation-4.0.3.tgz", - "integrity": "sha512-XnEyhlllurczZDx1vLPWnaohTAQzxlvaP7ifEbvRf2zvYC5C5ZZrgFH75g0/XcL7OuaZ0XlVtB0J0E/R0O1L4A==", - "requires": {} + "integrity": "sha512-XnEyhlllurczZDx1vLPWnaohTAQzxlvaP7ifEbvRf2zvYC5C5ZZrgFH75g0/XcL7OuaZ0XlVtB0J0E/R0O1L4A==" }, "express-rate-limit": { "version": "5.3.0", @@ -39089,8 +38988,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "26.0.0", @@ -39734,11 +39632,6 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, - "jose": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.9.2.tgz", - "integrity": "sha512-EqKvu2PqJCD3Jrg3PvcYZVS7D21qMVLSYMDAFcOdGUEOpJSLNtJO7NjLANvu3SYHVl6pdP2ff7ve6EZW2nX7Nw==" - }, "js-md4": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", @@ -41284,14 +41177,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" }, - "node-rsa": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", - "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", - "requires": { - "asn1": "^0.2.4" - } - }, "node-source-walk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-4.2.0.tgz", @@ -41426,11 +41311,6 @@ } } }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" - }, "object-inspect": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", @@ -41521,11 +41401,6 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "dev": true }, - "oidc-token-hash": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", - "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==" - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -41575,24 +41450,6 @@ "is-wsl": "^2.2.0" } }, - "openid-client": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.0.tgz", - "integrity": "sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ==", - "requires": { - "jose": "^4.10.0", - "lru-cache": "^6.0.0", - "object-hash": "^2.0.1", - "oidc-token-hash": "^5.0.1" - }, - "dependencies": { - "jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==" - } - } - }, "opentracing": { "version": "0.14.7", "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", @@ -41879,8 +41736,7 @@ "pg-pool": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", - "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==", - "requires": {} + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" }, "pg-protocol": { "version": "1.5.0", @@ -42605,8 +42461,7 @@ "react-ga": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz", - "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==", - "requires": {} + "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==" }, "react-i18next": { "version": "11.18.6", @@ -42987,14 +42842,12 @@ "redux-devtools-extension": { "version": "2.13.9", "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz", - "integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==", - "requires": {} + "integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==" }, "redux-thunk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "requires": {} + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" }, "reflect-metadata": { "version": "0.1.13", @@ -45896,8 +45749,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "requires": {} + "dev": true }, "ts-jest": { "version": "26.5.6", @@ -46761,8 +46613,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -47048,8 +46899,7 @@ "version": "7.5.3", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index 63de9b869..bde8e4bbe 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "@hapi/joi": "^17.1.1", "@material-ui/core": "^4.11.4", "@material-ui/lab": "^4.0.0-alpha.61", - "@opengovsg/sgid-client": "^2.0.0", "@sentry/react": "^6.11.0", "@sentry/tracing": "^6.8.0", "@sentry/webpack-plugin": "^1.15.1", diff --git a/src/client/app/components/pages/RootPage/index.tsx b/src/client/app/components/pages/RootPage/index.tsx index 09476088c..5e8b51dfa 100644 --- a/src/client/app/components/pages/RootPage/index.tsx +++ b/src/client/app/components/pages/RootPage/index.tsx @@ -10,7 +10,6 @@ import { History } from 'history' import PrivateRoute from '../../PrivateRoute' import HomePage from '../../../../home' import LoginPage from '../../../../login' -import SgidLoginPage from '../../../../sgidLogin' import UserPage from '../../../../user' import NotFoundPage from '../NotFoundPage' import DirectoryPage from '../../../../directory' @@ -31,7 +30,6 @@ import { HOME_PAGE, LOGIN_PAGE, NOT_FOUND_PAGE, - SGID_LOGIN_PAGE, USER_PAGE, } from '../../../util/types' import theme from '../../../theme' @@ -49,7 +47,6 @@ const Root: FunctionComponent = ({ store, history }: RootProps) => ( - diff --git a/src/client/app/util/types.ts b/src/client/app/util/types.ts index 7ca360554..131ab6647 100644 --- a/src/client/app/util/types.ts +++ b/src/client/app/util/types.ts @@ -1,6 +1,5 @@ export const HOME_PAGE = '/' export const LOGIN_PAGE = '/login' -export const SGID_LOGIN_PAGE = '/ogp-login' export const USER_PAGE = '/user' export const SEARCH_PAGE = '/search' export const NOT_FOUND_PAGE = '/404/:shortUrl' diff --git a/src/client/sgidLogin/index.tsx b/src/client/sgidLogin/index.tsx deleted file mode 100644 index e361c1cec..000000000 --- a/src/client/sgidLogin/index.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import React, { useEffect } from 'react' -import i18next from 'i18next' -import { - Button, - Hidden, - Link, - Typography, - createStyles, - makeStyles, -} from '@material-ui/core' -import GoLogo from '@assets/go-logo-graphics/go-main-logo.svg' -import LoginGraphics from '@assets/login-page-graphics/login-page-graphics.svg' -import { useDispatch } from 'react-redux' -import rootActions from '../app/components/pages/RootPage/actions' - -import assetVariant from '../../shared/util/asset-variant' - -import { htmlSanitizer } from '../app/util/format' -import Section from '../app/components/Section' -import BaseLayout from '../app/components/BaseLayout' -import { get } from '../app/util/requests' - -const URL_PREFIX_LENGTH = '#/ogp-login'.length - -const useStyles = makeStyles((theme) => - createStyles({ - container: { - display: 'flex', - flexGrow: 1, - '-ms-flex': '1 1 auto', - }, - loginContainer: { - display: 'flex', - width: '100%', - [theme.breakpoints.up('lg')]: { - width: '50%', - }, - }, - verticalAlign: { - display: 'flex', - width: '100%', - [theme.breakpoints.up('lg')]: { - alignItems: 'center', - }, - }, - signInButton: { - width: '250px', - minWidth: '120px', - marginRight: theme.spacing(2), - }, - loginWrapper: { - display: 'block', - [theme.breakpoints.up('lg')]: { - // Gives the contents slightly more than enough height, - // so that validation messages do not shift the centering. - height: '400px', - maxHeight: '80vh', - }, - }, - headerGroup: { - marginBottom: theme.spacing(4), - }, - logo: { - maxWidth: '130px', - width: '40%', - }, - loginHeader: { - marginTop: theme.spacing(1), - }, - loginReferral: { - fontSize: '0.85rem', - color: '#767676', - marginBottom: theme.spacing(4), - }, - graphicColorFill: { - backgroundColor: theme.palette.primary.dark, - width: '50vw', - height: '100%', - // allocates space for the government masthead when on gov variant - maxHeight: assetVariant === 'gov' ? 'calc(100vh - 28px)' : '100vh', - textAlign: 'center', - overflow: 'hidden', - }, - loginGraphic: { - userDrag: 'none', - height: '100%', - }, - '@media screen\\0': { - // Styles for Internet Explorer compatibility - logoLink: { - marginBottom: '0', - }, - }, - }), -) - -const SgidLoginPage = (): JSX.Element => { - const dispatch = useDispatch() - const classes = useStyles() - const queryParams = new URLSearchParams( - new URL(window.location.href).hash.substring(URL_PREFIX_LENGTH), - ) - - const setLoginStatusMessage = (message: string) => - dispatch(rootActions.setInfoMessage(message)) - - useEffect(() => { - const officerEmail = queryParams.get('officerEmail') - const statusCode = queryParams.get('statusCode') - if (officerEmail) { - setLoginStatusMessage( - `${officerEmail} doesn't look like a valid ${i18next.t( - 'general.emailDomain', - )} email.`, - ) - } else if (statusCode === '403') { - setLoginStatusMessage( - `Unable to fetch a valid work email for authentication.`, - ) - } else if (statusCode === '400') { - setLoginStatusMessage(`Authentication failed. Please try again.`) - } - }, []) - - return ( - -
-
- -
- Login page graphic -
-
-
-
-
-
-
- - - GoGovSG logo - - - {/* NOTE: dangerouslySetInnerHTML is used as copy includes tag */} - - - {i18next.t('login.referrals.1.officerPhrase')} can use their{' '} - {i18next.t('login.referrals.1.emailDomain')} emails at{' '} - - {i18next.t('login.referrals.1.link')} - - , and {i18next.t('login.referrals.2.officerPhrase')} can use - their {i18next.t('login.referrals.2.emailDomain')} emails at{' '} - - {i18next.t('login.referrals.2.link')} - {' '} - to shorten links. - - - -
-
-
-
-
-
- ) -} - -export default SgidLoginPage diff --git a/src/server/api/index.ts b/src/server/api/index.ts index 261da7355..30da753ce 100644 --- a/src/server/api/index.ts +++ b/src/server/api/index.ts @@ -16,7 +16,6 @@ const router = Express.Router() /* Public routes that do not need to be protected */ router.use('/logout', require('./logout')) router.use('/login', require('./login')) -router.use('/sgidLogin', require('./sgidLogin')) router.use('/stats', require('./statistics')) router.use('/sentry', require('./sentry')) router.use('/links', require('./links')) diff --git a/src/server/api/sgidLogin/index.ts b/src/server/api/sgidLogin/index.ts deleted file mode 100644 index 3a3ad9ef5..000000000 --- a/src/server/api/sgidLogin/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Express from 'express' -import { SgidLoginController } from '../../modules/auth' -import { container } from '../../util/inversify' -import { DependencyIds } from '../../constants' - -const router: Express.Router = Express.Router() - -const sgidLoginController = container.get( - DependencyIds.sgidLoginController, -) - -router.get('/authurl', sgidLoginController.generateAuthUrl) - -router.get('/authenticate', sgidLoginController.handleLogin) - -module.exports = router diff --git a/src/server/config.ts b/src/server/config.ts index 1be92b76e..4b58b3711 100644 --- a/src/server/config.ts +++ b/src/server/config.ts @@ -270,10 +270,6 @@ export const ffExternalApi: boolean = process.env.FF_EXTERNAL_API === 'true' export const apiAdmins: string[] = process.env.ADMIN_API_EMAILS ? process.env.ADMIN_API_EMAILS.split(',') : [] -export const sgidClientId = process.env.SGID_CLIENT_ID || '' -export const sgidPrivateKey = process.env.SGID_PRIVATE_KEY || '' -export const sgidClientSecret = process.env.SGID_CLIENT_SECRET || '' -export const sgidApiHostname = process.env.SGID_API_HOSTNAME || '' export const userCount = Number(process.env.USER_COUNT) || 77288 export const clickCount = Number(process.env.CLICK_COUNT) || 666820545 diff --git a/src/server/constants.ts b/src/server/constants.ts index ef8bec673..94a398d0b 100644 --- a/src/server/constants.ts +++ b/src/server/constants.ts @@ -34,7 +34,6 @@ export const DependencyIds = { linksController: Symbol.for('linksController'), authService: Symbol.for('authService'), loginController: Symbol.for('loginController'), - sgidLoginController: Symbol.for('sgidLoginController'), logoutController: Symbol.for('logoutController'), urlManagementService: Symbol.for('urlManagementService'), userController: Symbol.for('userController'), diff --git a/src/server/inversify.config.ts b/src/server/inversify.config.ts index 7ecf3b65f..6ac08ffdb 100644 --- a/src/server/inversify.config.ts +++ b/src/server/inversify.config.ts @@ -48,11 +48,7 @@ import { RotatingLinksController } from './modules/display/RotatingLinksControll import { SentryController } from './modules/sentry/SentryController' import { AuthService, CryptographyBcrypt } from './modules/auth/services' -import { - LoginController, - LogoutController, - SgidLoginController, -} from './modules/auth' +import { LoginController, LogoutController } from './modules/auth' import { UrlManagementService } from './modules/user/services' import { UserController } from './modules/user' import { DirectoryController } from './modules/directory' @@ -135,7 +131,6 @@ export default () => { bindIfUnbound(DependencyIds.linksController, RotatingLinksController) bindIfUnbound(DependencyIds.sentryController, SentryController) bindIfUnbound(DependencyIds.loginController, LoginController) - bindIfUnbound(DependencyIds.sgidLoginController, SgidLoginController) bindIfUnbound(DependencyIds.authService, AuthService) bindIfUnbound(DependencyIds.logoutController, LogoutController) bindIfUnbound(DependencyIds.urlManagementService, UrlManagementService) diff --git a/src/server/modules/auth/SgidLoginController.ts b/src/server/modules/auth/SgidLoginController.ts deleted file mode 100644 index d16011636..000000000 --- a/src/server/modules/auth/SgidLoginController.ts +++ /dev/null @@ -1,95 +0,0 @@ -import Express, { CookieOptions } from 'express' -import { inject, injectable } from 'inversify' -import { SGID_LOGIN_OAUTH_STATE, SgidAuthService } from '../../services/sgid' -import { DependencyIds } from '../../constants' -import { logger } from '../../config' -import { isValidGovEmail } from '../../util/email' -import { AuthService } from './interfaces' -import jsonMessage from '../../util/json' - -export const OFFICER_EMAIL_SCOPE = 'ogpofficerinfo.work_email' -const SGID_STATE_COOKIE_NAME = 'gogovsg_sgid_state' -const SgidStateCookieConfig: CookieOptions = { - httpOnly: true, -} - -@injectable() -export class SgidLoginController { - private sgidService - - private authService: AuthService - - constructor(@inject(DependencyIds.authService) authService: AuthService) { - this.sgidService = SgidAuthService - this.authService = authService - } - - public generateAuthUrl: ( - req: Express.Request, - res: Express.Response, - ) => void = (_req, res) => { - try { - const { url, codeVerifier, nonce } = this.sgidService.authorizationUrl() - - res.cookie( - SGID_STATE_COOKIE_NAME, - { codeVerifier, nonce }, - SgidStateCookieConfig, - ) - res.send(url) - return - } catch (err) { - logger.error(err) - res.status(400) - res.badRequest( - jsonMessage('SGID login not supported by edu and health domains.'), - ) - return - } - } - - public handleLogin = async (req: Express.Request, res: Express.Response) => { - try { - const { code, state } = req.query - const sessionData = req.cookies[SGID_STATE_COOKIE_NAME] - - if (state !== SGID_LOGIN_OAUTH_STATE) { - res.redirect(`/#/ogp-login?statusCode=400`) - return - } - - const { sub, accessToken } = await this.sgidService.callback( - String(code), - String(sessionData.nonce), - String(sessionData.codeVerifier), - ) - - const { data } = await this.sgidService.userinfo(accessToken, sub) - const officerEmail = data[OFFICER_EMAIL_SCOPE] - - if ( - !officerEmail || - !officerEmail.length || - !isValidGovEmail(officerEmail) - ) { - // redirect back to sgid login page, if authentication fails, - // or officer email is not valid - res.redirect(`/#/ogp-login?statusCode=403&officerEmail=${officerEmail}`) - return - } - const dbUser = await this.authService.genDBUserWithOfficerEmail( - data[OFFICER_EMAIL_SCOPE], - ) - - req.session!.user = dbUser - - res.redirect(`/#/user`) - return - } catch (error) { - logger.error(error) - res.status(500).render('error', { error }) - } - } -} - -export default SgidLoginController diff --git a/src/server/modules/auth/index.ts b/src/server/modules/auth/index.ts index eaaff0719..b3025d475 100644 --- a/src/server/modules/auth/index.ts +++ b/src/server/modules/auth/index.ts @@ -1,6 +1,5 @@ export { LoginController } from './LoginController' export { LogoutController } from './LogoutController' -export { SgidLoginController } from './SgidLoginController' export type EmailProperty = { email: string diff --git a/src/server/services/sgid.ts b/src/server/services/sgid.ts deleted file mode 100644 index 895913f34..000000000 --- a/src/server/services/sgid.ts +++ /dev/null @@ -1,110 +0,0 @@ -import SgidClient, { generatePkcePair } from '@opengovsg/sgid-client' -import { - logger, - ogUrl, - sgidApiHostname, - sgidClientId, - sgidClientSecret, - sgidPrivateKey, -} from '../config' - -interface SgidServiceOption { - clientId: string - clientSecret: string - privateKey: string - redirectUri: string - hostname: string -} - -export const SGID_LOGIN_OAUTH_STATE = 'login' - -class SgidService { - // SGID client will be null for other domains like edu, health - // so we will need to handle cases for those as well, so that - // they continue to work in prod without sgid client being initialised - private sgidClient: SgidClient | null - - constructor({ - clientId, - clientSecret, - privateKey, - redirectUri, - hostname, - }: SgidServiceOption) { - try { - this.sgidClient = new SgidClient({ - clientId, - clientSecret, - privateKey, - redirectUri, - hostname, - }) - logger.info('SGID client initialised successfully') - } catch (e) { - logger.error('SGID client initialisation failed', e) - this.sgidClient = null - } - } - - /** - * Fetches the url via sgid SDK. - */ - authorizationUrl(): { url: string; codeVerifier: string; nonce?: string } { - if (!this.sgidClient) { - throw new Error('SGID client not initialised') - } - try { - const { codeChallenge, codeVerifier } = generatePkcePair() - const { url, nonce } = this.sgidClient.authorizationUrl({ - state: SGID_LOGIN_OAUTH_STATE, - scope: ['openid', 'ogpofficerinfo.work_email'].join(' '), - codeChallenge, - }) - return { url, codeVerifier, nonce } - } catch (e) { - throw new Error( - `Error retrieving url via sgid-client: ${(e as Error).message}`, - ) - } - } - - /** - * Fetches the token via sgid SDK. - */ - async callback(code: string, nonce: string, codeVerifier: string) { - if (!code || !this.sgidClient) - throw new Error(`code cannot be empty or sgid client not initialised`) - try { - const { sub, accessToken } = await this.sgidClient.callback({ - code, - nonce, - codeVerifier, - }) - return { sub, accessToken } - } catch (e) { - throw new Error('Error retrieving access token via sgid-client') - } - } - - /** - * Fetches the user info via sgid SDK. - */ - async userinfo(accessToken: string, sub: string) { - if (!accessToken || !this.sgidClient) - throw new Error(`accessToken cannot be empty`) - try { - return await this.sgidClient.userinfo({ accessToken, sub }) - } catch (e) { - throw new Error('Error retrieving user info via sgid-client') - } - } -} - -// Initialised the sgidService object with the different environments -export const SgidAuthService = new SgidService({ - clientId: sgidClientId, - clientSecret: sgidClientSecret, - privateKey: sgidPrivateKey, - redirectUri: `${ogUrl}/api/sgidLogin/authenticate`, - hostname: sgidApiHostname, -})