From a9441370dd076243987a08fb461760d49e6f7c42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 07:33:49 +0000 Subject: [PATCH 01/10] Bump the typescript-eslint group with 2 updates Bumps the typescript-eslint group with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 8.13.0 to 8.14.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.14.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.13.0 to 8.14.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.14.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript-eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript-eslint ... Signed-off-by: dependabot[bot] --- package-lock.json | 88 +++++++++++++++++++++++------------------------ package.json | 4 +-- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index 78afc9c5..0919ff76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,8 +54,8 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.0", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", + "@typescript-eslint/eslint-plugin": "^8.14.0", + "@typescript-eslint/parser": "^8.14.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-config-next": "^14.2.14", @@ -4596,16 +4596,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", + "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/type-utils": "8.13.0", - "@typescript-eslint/utils": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/type-utils": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4629,15 +4629,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", + "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4" }, "engines": { @@ -4657,13 +4657,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", + "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0" + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4674,13 +4674,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", + "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/utils": "8.14.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4698,9 +4698,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", + "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4711,13 +4711,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", + "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4739,15 +4739,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", + "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0" + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4761,12 +4761,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", + "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/types": "8.14.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { diff --git a/package.json b/package.json index 6379c69b..63e63cf8 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.0", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", + "@typescript-eslint/eslint-plugin": "^8.14.0", + "@typescript-eslint/parser": "^8.14.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-config-next": "^14.2.14", From 90ef3dd6221f54dc9cebd6f63ccb9c0edcf439d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:24:28 +0000 Subject: [PATCH 02/10] Bump @octokit/auth-app from 7.1.2 to 7.1.3 in the octokit group Bumps the octokit group with 1 update: [@octokit/auth-app](https://github.com/octokit/auth-app.js). Updates `@octokit/auth-app` from 7.1.2 to 7.1.3 - [Release notes](https://github.com/octokit/auth-app.js/releases) - [Commits](https://github.com/octokit/auth-app.js/compare/v7.1.2...v7.1.3) --- updated-dependencies: - dependency-name: "@octokit/auth-app" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: octokit ... Signed-off-by: dependabot[bot] --- package-lock.json | 27 +++++++++++++-------------- package.json | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0919ff76..5afa6d26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^6.1.6", "@mui/material": "^6.0.1", - "@octokit/auth-app": "^7.1.2", + "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", "@octokit/webhooks": "^13.3.0", "@stoplight/elements": "^8.4.5", @@ -2454,16 +2454,16 @@ } }, "node_modules/@octokit/auth-app": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.2.tgz", - "integrity": "sha512-5cfWRr1hr0w/EW3StFIIOkMtYhOyGZ6/R3T0xeN6UgC/uL5pIyeood9N/8Z7W4NZUdz2QK1Fv0oM/1AzTME3/Q==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.3.tgz", + "integrity": "sha512-GZdkOp2kZTIy5dG9oXqvzUAZiPvDx4C/lMlN6yQjtG9d/+hYa7W8WXTJoOrXE8UdfL9A/sZMl206dmtkl9lwVQ==", "dependencies": { "@octokit/auth-oauth-app": "^8.1.0", "@octokit/auth-oauth-user": "^5.1.0", "@octokit/request": "^9.1.1", "@octokit/request-error": "^6.1.1", "@octokit/types": "^13.4.1", - "lru-cache": "npm:@wolfy1339/lru-cache@^11.0.2-patch.1", + "toad-cache": "^3.7.0", "universal-github-app-jwt": "^2.2.0", "universal-user-agent": "^7.0.0" }, @@ -2471,15 +2471,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/auth-app/node_modules/lru-cache": { - "name": "@wolfy1339/lru-cache", - "version": "11.0.2-patch.1", - "resolved": "https://registry.npmjs.org/@wolfy1339/lru-cache/-/lru-cache-11.0.2-patch.1.tgz", - "integrity": "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA==", - "engines": { - "node": "18 >=18.20 || 20 || >=22" - } - }, "node_modules/@octokit/auth-oauth-app": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz", @@ -19262,6 +19253,14 @@ "node": ">=8.0" } }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "engines": { + "node": ">=12" + } + }, "node_modules/toggle-selection": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", diff --git a/package.json b/package.json index 63e63cf8..85f2d84f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^6.1.6", "@mui/material": "^6.0.1", - "@octokit/auth-app": "^7.1.2", + "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", "@octokit/webhooks": "^13.3.0", "@stoplight/elements": "^8.4.5", From 089947ef8e8d8482f9d75f98403d590a6ba7b73b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:30:14 +0000 Subject: [PATCH 03/10] Bump core-js from 3.38.1 to 3.39.0 Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.38.1 to 3.39.0. - [Release notes](https://github.com/zloirock/core-js/releases) - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/zloirock/core-js/commits/v3.39.0/packages/core-js) --- updated-dependencies: - dependency-name: core-js dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5afa6d26..1d3f3a7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@octokit/core": "^6.1.2", "@octokit/webhooks": "^13.3.0", "@stoplight/elements": "^8.4.5", - "core-js": "^3.38.1", + "core-js": "^3.39.0", "encoding": "^0.1.13", "figma-squircle": "^1.1.0", "install": "^0.13.0", @@ -6125,9 +6125,9 @@ } }, "node_modules/core-js": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", - "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", "hasInstallScript": true, "funding": { "type": "opencollective", diff --git a/package.json b/package.json index 85f2d84f..ac0dc7b0 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@octokit/core": "^6.1.2", "@octokit/webhooks": "^13.3.0", "@stoplight/elements": "^8.4.5", - "core-js": "^3.38.1", + "core-js": "^3.39.0", "encoding": "^0.1.13", "figma-squircle": "^1.1.0", "install": "^0.13.0", From 918d36d179685db9eb1e6ded3d28c9a8a448cb20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:34:15 +0000 Subject: [PATCH 04/10] Bump the mui group with 2 updates Bumps the mui group with 2 updates: [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) and [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material). Updates `@mui/icons-material` from 6.1.6 to 6.1.7 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v6.1.7/packages/mui-icons-material) Updates `@mui/material` from 6.1.6 to 6.1.7 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v6.1.7/packages/mui-material) --- updated-dependencies: - dependency-name: "@mui/icons-material" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: mui - dependency-name: "@mui/material" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: mui ... Signed-off-by: dependabot[bot] --- package-lock.json | 62 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d3f3a7b..56b24ac9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@fortawesome/free-regular-svg-icons": "^6.6.0", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "@mui/icons-material": "^6.1.6", + "@mui/icons-material": "^6.1.7", "@mui/material": "^6.0.1", "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", @@ -2031,18 +2031,18 @@ "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.6.tgz", - "integrity": "sha512-nz1SlR9TdBYYPz4qKoNasMPRiGb4PaIHFkzLzhju0YVYS5QSuFF2+n7CsiHMIDcHv3piPu/xDWI53ruhOqvZwQ==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.7.tgz", + "integrity": "sha512-POuIBi80BZBogQkG4PQKIGwy4QFwB+kOr+OI4k7Znh7LqMAIhwB9OC00l6M+w1GrZJYj3T8R5WX8G6QAIvoVEw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.6.tgz", - "integrity": "sha512-5r9urIL2lxXb/sPN3LFfFYEibsXJUb986HhhIeu1gOcte460pwdSiEhBSxkAuyT8Dj7jvu9MjqSBmSumQELo8A==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.7.tgz", + "integrity": "sha512-RGzkeHNArIVy5ZQ12bq/8VYNeICEyngngsFskTJ/2hYKhIeIII3iRGtaZaSvLpXh7h3Fg3VKTulT+QU0w5K4XQ==", "dependencies": { "@babel/runtime": "^7.26.0" }, @@ -2054,7 +2054,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.1.6", + "@mui/material": "^6.1.7", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2065,15 +2065,15 @@ } }, "node_modules/@mui/material": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.6.tgz", - "integrity": "sha512-1yvejiQ/601l5AK3uIdUlAVElyCxoqKnl7QA+2oFB/2qYPWfRwDgavW/MoywS5Y2gZEslcJKhe0s2F3IthgFgw==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.7.tgz", + "integrity": "sha512-KsjujQL/A2hLd1PV3QboF+W6SSL5QqH6ZlSuQoeYz9r69+TnyBFIevbYLxdjJcJmGBjigL5pfpn7hTGop+vhSg==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.1.6", - "@mui/system": "^6.1.6", + "@mui/core-downloads-tracker": "^6.1.7", + "@mui/system": "^6.1.7", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.6", + "@mui/utils": "^6.1.7", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", @@ -2092,7 +2092,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.1.6", + "@mui/material-pigment-css": "^6.1.7", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2113,12 +2113,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.6.tgz", - "integrity": "sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.7.tgz", + "integrity": "sha512-uLbfUSsug5K0LVkv0PI6Flste3le8+6WSL2omdTiYde93P89Qr7pKr8TA6d2yXfr+Bm+SvD8/fGnkaRwFkryuQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.1.6", + "@mui/utils": "^6.1.7", "prop-types": "^15.8.1" }, "engines": { @@ -2139,9 +2139,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.6.tgz", - "integrity": "sha512-I+yS1cSuSvHnZDBO7e7VHxTWpj+R7XlSZvTC4lS/OIbUNJOMMSd3UDP6V2sfwzAdmdDNBi7NGCRv2SZ6O9hGDA==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.7.tgz", + "integrity": "sha512-Ou4CxN7MQmwrfG1Pu6EYjPgPChQXxPDJrwgizLXlRPOad5qAq4gYXRuzrGQ2DfGjjwmJhjI8T6A0SeapAZPGig==", "dependencies": { "@babel/runtime": "^7.26.0", "@emotion/cache": "^11.13.1", @@ -2172,15 +2172,15 @@ } }, "node_modules/@mui/system": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.6.tgz", - "integrity": "sha512-qOf1VUE9wK8syiB0BBCp82oNBAVPYdj4Trh+G1s+L+ImYiKlubWhhqlnvWt3xqMevR+D2h1CXzA1vhX2FvA+VQ==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.7.tgz", + "integrity": "sha512-qbMGgcC/FodpuRSfjXlEDdbNQaW++eATh0vNBcPUv2/YXSpReoOpoT9FhogxEBNks+aQViDXBRZKh6HX2fVmwg==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.1.6", - "@mui/styled-engine": "^6.1.6", + "@mui/private-theming": "^6.1.7", + "@mui/styled-engine": "^6.1.7", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.6", + "@mui/utils": "^6.1.7", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2224,9 +2224,9 @@ } }, "node_modules/@mui/utils": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.6.tgz", - "integrity": "sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.7.tgz", + "integrity": "sha512-Gr7cRZxBoZ0BIa3Xqf/2YaUrBLyNPJvXPQH3OsD9WMZukI/TutibbQBVqLYpgqJn8pKSjbD50Yq2auG0wI1xOw==", "dependencies": { "@babel/runtime": "^7.26.0", "@mui/types": "^7.2.19", diff --git a/package.json b/package.json index ac0dc7b0..cb17d35a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@fortawesome/free-regular-svg-icons": "^6.6.0", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "@mui/icons-material": "^6.1.6", + "@mui/icons-material": "^6.1.7", "@mui/material": "^6.0.1", "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", From 6862e49bee907bacca22224ad0c119e62d27b161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:48:03 +0000 Subject: [PATCH 05/10] Bump the fontawesome group with 4 updates Bumps the fontawesome group with 4 updates: [@fortawesome/fontawesome-svg-core](https://github.com/FortAwesome/Font-Awesome), [@fortawesome/free-brands-svg-icons](https://github.com/FortAwesome/Font-Awesome), [@fortawesome/free-regular-svg-icons](https://github.com/FortAwesome/Font-Awesome) and [@fortawesome/free-solid-svg-icons](https://github.com/FortAwesome/Font-Awesome). Updates `@fortawesome/fontawesome-svg-core` from 6.6.0 to 6.7.1 - [Release notes](https://github.com/FortAwesome/Font-Awesome/releases) - [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md) - [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.1) Updates `@fortawesome/free-brands-svg-icons` from 6.6.0 to 6.7.1 - [Release notes](https://github.com/FortAwesome/Font-Awesome/releases) - [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md) - [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.1) Updates `@fortawesome/free-regular-svg-icons` from 6.6.0 to 6.7.1 - [Release notes](https://github.com/FortAwesome/Font-Awesome/releases) - [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md) - [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.1) Updates `@fortawesome/free-solid-svg-icons` from 6.6.0 to 6.7.1 - [Release notes](https://github.com/FortAwesome/Font-Awesome/releases) - [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md) - [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.1) --- updated-dependencies: - dependency-name: "@fortawesome/fontawesome-svg-core" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fontawesome - dependency-name: "@fortawesome/free-brands-svg-icons" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fontawesome - dependency-name: "@fortawesome/free-regular-svg-icons" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fontawesome - dependency-name: "@fortawesome/free-solid-svg-icons" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: fontawesome ... Signed-off-by: dependabot[bot] --- package-lock.json | 46 +++++++++++++++++++++++----------------------- package.json | 8 ++++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56b24ac9..5972a77d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,10 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/poppins": "^5.1.0", - "@fortawesome/fontawesome-svg-core": "^6.6.0", - "@fortawesome/free-brands-svg-icons": "^6.6.0", - "@fortawesome/free-regular-svg-icons": "^6.6.0", - "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/fontawesome-svg-core": "^6.7.1", + "@fortawesome/free-brands-svg-icons": "^6.7.1", + "@fortawesome/free-regular-svg-icons": "^6.7.1", + "@fortawesome/free-solid-svg-icons": "^6.7.1", "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^6.1.7", "@mui/material": "^6.0.1", @@ -939,52 +939,52 @@ "integrity": "sha512-tpLXlnNi2fwQjiipvuj4uNFHCdoLA8izRsKdoexZuEzjx0r/g1aKLf4ta6lFgF7L+/+AFdmaXFlUwwvmDzYH+g==" }, "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", - "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.1.tgz", + "integrity": "sha512-gbDz3TwRrIPT3i0cDfujhshnXO9z03IT1UKRIVi/VEjpNHtSBIP2o5XSm+e816FzzCFEzAxPw09Z13n20PaQJQ==", "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", - "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.1.tgz", + "integrity": "sha512-8dBIHbfsKlCk2jHQ9PoRBg2Z+4TwyE3vZICSnoDlnsHA6SiMlTwfmW6yX0lHsRmWJugkeb92sA0hZdkXJhuz+g==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.6.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-brands-svg-icons": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz", - "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.1.tgz", + "integrity": "sha512-nJR76eqPzCnMyhbiGf6X0aclDirZriTPRcFm1YFvuupyJOGwlNF022w3YBqu+yrHRhnKRpzFX+8wJKqiIjWZkA==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.6.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-regular-svg-icons": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz", - "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.1.tgz", + "integrity": "sha512-e13cp+bAx716RZOTQ59DhqikAgETA9u1qTBHO3e3jMQQ+4H/N1NC1ZVeFYt1V0m+Th68BrEL1/X6XplISutbXg==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.6.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", - "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.1.tgz", + "integrity": "sha512-BTKc0b0mgjWZ2UDKVgmwaE0qt0cZs6ITcDgjrti5f/ki7aF5zs+N91V6hitGo3TItCFtnKg6cUVGdTmBFICFRg==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.6.0" + "@fortawesome/fontawesome-common-types": "6.7.1" }, "engines": { "node": ">=6" diff --git a/package.json b/package.json index cb17d35a..3cfb8968 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,10 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/poppins": "^5.1.0", - "@fortawesome/fontawesome-svg-core": "^6.6.0", - "@fortawesome/free-brands-svg-icons": "^6.6.0", - "@fortawesome/free-regular-svg-icons": "^6.6.0", - "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/fontawesome-svg-core": "^6.7.1", + "@fortawesome/free-brands-svg-icons": "^6.7.1", + "@fortawesome/free-regular-svg-icons": "^6.7.1", + "@fortawesome/free-solid-svg-icons": "^6.7.1", "@fortawesome/react-fontawesome": "^0.2.2", "@mui/icons-material": "^6.1.7", "@mui/material": "^6.0.1", From 30526dd10eeda316b1e9a1e74f9d1b68db793604 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:48:37 +0000 Subject: [PATCH 06/10] Bump the mui group with 2 updates Bumps the mui group with 2 updates: [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) and [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material). Updates `@mui/icons-material` from 6.1.7 to 6.1.8 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v6.1.8/packages/mui-icons-material) Updates `@mui/material` from 6.1.7 to 6.1.8 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v6.1.8/packages/mui-material) --- updated-dependencies: - dependency-name: "@mui/icons-material" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: mui - dependency-name: "@mui/material" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: mui ... Signed-off-by: dependabot[bot] --- package-lock.json | 62 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56b24ac9..cb87fb4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@fortawesome/free-regular-svg-icons": "^6.6.0", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "@mui/icons-material": "^6.1.7", + "@mui/icons-material": "^6.1.8", "@mui/material": "^6.0.1", "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", @@ -2031,18 +2031,18 @@ "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.7.tgz", - "integrity": "sha512-POuIBi80BZBogQkG4PQKIGwy4QFwB+kOr+OI4k7Znh7LqMAIhwB9OC00l6M+w1GrZJYj3T8R5WX8G6QAIvoVEw==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.8.tgz", + "integrity": "sha512-TGAvzwUg9hybDacwfIGFjI2bXYXrIqky+vMfaeay8rvT56/PNAlvIDUJ54kpT5KRc9AWAihOvtDI7/LJOThOmQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.7.tgz", - "integrity": "sha512-RGzkeHNArIVy5ZQ12bq/8VYNeICEyngngsFskTJ/2hYKhIeIII3iRGtaZaSvLpXh7h3Fg3VKTulT+QU0w5K4XQ==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.8.tgz", + "integrity": "sha512-6frsXcf1TcJKWevWwRup6V4L8lzI33cbHcAjT83YLgKw0vYRZKY0kjMI9fhrJZdRWXgFFgKKvEv3GjoxbqFF7A==", "dependencies": { "@babel/runtime": "^7.26.0" }, @@ -2054,7 +2054,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.1.7", + "@mui/material": "^6.1.8", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2065,15 +2065,15 @@ } }, "node_modules/@mui/material": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.7.tgz", - "integrity": "sha512-KsjujQL/A2hLd1PV3QboF+W6SSL5QqH6ZlSuQoeYz9r69+TnyBFIevbYLxdjJcJmGBjigL5pfpn7hTGop+vhSg==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.8.tgz", + "integrity": "sha512-QZdQFnXct+7NXIzHgT3qt+sQiO7HYGZU2vymP9Xl9tUMXEOA/S1mZMMb7+WGZrk5TzNlU/kP/85K0da5V1jXoQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.1.7", - "@mui/system": "^6.1.7", + "@mui/core-downloads-tracker": "^6.1.8", + "@mui/system": "^6.1.8", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.7", + "@mui/utils": "^6.1.8", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", @@ -2092,7 +2092,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.1.7", + "@mui/material-pigment-css": "^6.1.8", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2113,12 +2113,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.7.tgz", - "integrity": "sha512-uLbfUSsug5K0LVkv0PI6Flste3le8+6WSL2omdTiYde93P89Qr7pKr8TA6d2yXfr+Bm+SvD8/fGnkaRwFkryuQ==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.8.tgz", + "integrity": "sha512-TuKl7msynCNCVvhX3c0ef1sF0Qb3VHcPs8XOGB/8bdOGBr/ynmIG1yTMjZeiFQXk8yN9fzK/FDEKMFxILNn3wg==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.1.7", + "@mui/utils": "^6.1.8", "prop-types": "^15.8.1" }, "engines": { @@ -2139,9 +2139,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.7.tgz", - "integrity": "sha512-Ou4CxN7MQmwrfG1Pu6EYjPgPChQXxPDJrwgizLXlRPOad5qAq4gYXRuzrGQ2DfGjjwmJhjI8T6A0SeapAZPGig==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.8.tgz", + "integrity": "sha512-ZvEoT0U2nPLSLI+B4by4cVjaZnPT2f20f4JUPkyHdwLv65ZzuoHiTlwyhqX1Ch63p8bcJzKTHQVGisEoMK6PGA==", "dependencies": { "@babel/runtime": "^7.26.0", "@emotion/cache": "^11.13.1", @@ -2172,15 +2172,15 @@ } }, "node_modules/@mui/system": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.7.tgz", - "integrity": "sha512-qbMGgcC/FodpuRSfjXlEDdbNQaW++eATh0vNBcPUv2/YXSpReoOpoT9FhogxEBNks+aQViDXBRZKh6HX2fVmwg==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.8.tgz", + "integrity": "sha512-i1kLfQoWxzFpXTBQIuPoA3xKnAnP3en4I2T8xIolovSolGQX5k8vGjw1JaydQS40td++cFsgCdEU458HDNTGUA==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.1.7", - "@mui/styled-engine": "^6.1.7", + "@mui/private-theming": "^6.1.8", + "@mui/styled-engine": "^6.1.8", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.7", + "@mui/utils": "^6.1.8", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2224,9 +2224,9 @@ } }, "node_modules/@mui/utils": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.7.tgz", - "integrity": "sha512-Gr7cRZxBoZ0BIa3Xqf/2YaUrBLyNPJvXPQH3OsD9WMZukI/TutibbQBVqLYpgqJn8pKSjbD50Yq2auG0wI1xOw==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.8.tgz", + "integrity": "sha512-O2DWb1kz8hiANVcR7Z4gOB3SvPPsSQGUmStpyBDzde6dJIfBzgV9PbEQOBZd3EBsd1pB+Uv1z5LAJAbymmawrA==", "dependencies": { "@babel/runtime": "^7.26.0", "@mui/types": "^7.2.19", diff --git a/package.json b/package.json index cb17d35a..77551e62 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@fortawesome/free-regular-svg-icons": "^6.6.0", "@fortawesome/free-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", - "@mui/icons-material": "^6.1.7", + "@mui/icons-material": "^6.1.8", "@mui/material": "^6.0.1", "@octokit/auth-app": "^7.1.3", "@octokit/core": "^6.1.2", From ae4376ebf454b589f20208c4953e116615bd987c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:49:00 +0000 Subject: [PATCH 07/10] Bump the typescript-eslint group with 2 updates Bumps the typescript-eslint group with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 8.14.0 to 8.15.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.15.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.14.0 to 8.15.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.15.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript-eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript-eslint ... Signed-off-by: dependabot[bot] --- package-lock.json | 110 +++++++++++++++++++++++++++------------------- package.json | 4 +- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56b24ac9..9d36ace9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,8 +54,8 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.0", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.14.0", - "@typescript-eslint/parser": "^8.14.0", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-config-next": "^14.2.14", @@ -4587,16 +4587,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", - "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", + "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/type-utils": "8.14.0", - "@typescript-eslint/utils": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/type-utils": "8.15.0", + "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4620,15 +4620,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", - "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", + "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4" }, "engines": { @@ -4648,13 +4648,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", - "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", + "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0" + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4665,13 +4665,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", - "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", + "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/utils": "8.15.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4682,6 +4682,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -4689,9 +4692,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", - "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", + "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4702,13 +4705,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", - "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", + "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4730,15 +4733,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", - "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", + "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0" + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4749,16 +4752,21 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", - "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", + "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.14.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.15.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4768,6 +4776,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", diff --git a/package.json b/package.json index cb17d35a..ce85e7b5 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "@types/react": "^18.3.12", "@types/react-dom": "^18.3.0", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.14.0", - "@typescript-eslint/parser": "^8.14.0", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-config-next": "^14.2.14", From 9626e30e9f636470be69d3b41452b4cdaa24ac25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=B8vring?= Date: Wed, 4 Dec 2024 15:15:42 +0100 Subject: [PATCH 08/10] Wraps links in Swagger --- src/features/docs/view/Swagger.tsx | 1 + src/features/docs/view/swagger.css | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/features/docs/view/swagger.css diff --git a/src/features/docs/view/Swagger.tsx b/src/features/docs/view/Swagger.tsx index 9aca9125..e821cdcf 100644 --- a/src/features/docs/view/Swagger.tsx +++ b/src/features/docs/view/Swagger.tsx @@ -3,6 +3,7 @@ import SwaggerUI from "swagger-ui-react" import "swagger-ui-react/swagger-ui.css" import { Box } from "@mui/material" import LoadingWrapper from "./LoadingWrapper" +import "./swagger.css" const Swagger = ({ url }: { url: string }) => { const [isLoading, setLoading] = useState(true) diff --git a/src/features/docs/view/swagger.css b/src/features/docs/view/swagger.css new file mode 100644 index 00000000..13551dba --- /dev/null +++ b/src/features/docs/view/swagger.css @@ -0,0 +1,6 @@ +.swagger-ui .info span.url { + display: block; + text-overflow: ellipsis; + overflow: hidden; + max-width: 80%; +} From ec4af52d12bdcc4c5a93b64da4349b396ad24b60 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 5 Dec 2024 13:14:21 +0100 Subject: [PATCH 09/10] Basic auth via config file (#451) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce encryption service * Add page for encrypting with public key * Handle basic auth for remote specifications * Bye bye proxy - use remotes endpoint now * Encapsulate encoding/decoding of RemoteConfig --------- Co-authored-by: Simon B. Støvring --- .env.example | 2 + __test__/encrypt/EncryptionService.test.ts | 80 ++++++++++++ .../projects/GitHubProjectDataSource.test.ts | 115 ++++++++++++++---- __test__/projects/RemoteConfigEncoder.test.ts | 38 ++++++ src/app/(authed)/(home)/encrypt/layout.tsx | 20 +++ src/app/(authed)/(home)/encrypt/page.tsx | 44 +++++++ src/app/api/proxy/route.ts | 115 ------------------ .../remotes/[encodedRemoteConfig]/route.ts | 64 ++++++++++ src/common/utils/fileUtils.ts | 73 +++++++++++ src/composition.ts | 15 ++- src/features/encrypt/EncryptionService.ts | 42 +++++++ src/features/encrypt/view/EncryptionForm.tsx | 101 +++++++++++++++ src/features/encrypt/view/encryptAction.ts | 7 ++ .../projects/data/GitHubProjectDataSource.ts | 24 +++- .../projects/domain/IProjectConfig.ts | 7 +- src/features/projects/domain/RemoteConfig.ts | 11 ++ .../projects/domain/RemoteConfigEncoder.ts | 34 ++++++ .../projects/domain/RemoteSpecAuth.ts | 11 ++ 18 files changed, 657 insertions(+), 146 deletions(-) create mode 100644 __test__/encrypt/EncryptionService.test.ts create mode 100644 __test__/projects/RemoteConfigEncoder.test.ts create mode 100644 src/app/(authed)/(home)/encrypt/layout.tsx create mode 100644 src/app/(authed)/(home)/encrypt/page.tsx delete mode 100644 src/app/api/proxy/route.ts create mode 100644 src/app/api/remotes/[encodedRemoteConfig]/route.ts create mode 100644 src/common/utils/fileUtils.ts create mode 100644 src/features/encrypt/EncryptionService.ts create mode 100644 src/features/encrypt/view/EncryptionForm.tsx create mode 100644 src/features/encrypt/view/encryptAction.ts create mode 100644 src/features/projects/domain/RemoteConfig.ts create mode 100644 src/features/projects/domain/RemoteConfigEncoder.ts create mode 100644 src/features/projects/domain/RemoteSpecAuth.ts diff --git a/.env.example b/.env.example index 1e98a941..239f191a 100644 --- a/.env.example +++ b/.env.example @@ -22,3 +22,5 @@ GITHUB_CLIENT_ID=GitHub App client ID GITHUB_CLIENT_SECRET=GitHub App client secret GITHUB_APP_ID=123456 GITHUB_PRIVATE_KEY_BASE_64=base 64 encoded version of the private key - see README.md for more info +ENCRYPTION_PUBLIC_KEY_BASE_64=base 64 encoded version of the public key +ENCRYPTION_PRIVATE_KEY_BASE_64=base 64 encoded version of the private key diff --git a/__test__/encrypt/EncryptionService.test.ts b/__test__/encrypt/EncryptionService.test.ts new file mode 100644 index 00000000..3b378088 --- /dev/null +++ b/__test__/encrypt/EncryptionService.test.ts @@ -0,0 +1,80 @@ +import RsaEncryptionService from '../../src/features/encrypt/EncryptionService' + +const publicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1k4JT719AUz/wuXb2rt +8933okfM2Iynmc6akSsZWEsW19byzO0UHp8b79xvsmNQKM1wBEBnXb5t+uLjJJZe +rqCiTB7fBL64tExSKIDIRAlMnQtMfHs/rMgR+o/N2Yo2KimQw9G84goCEbBF2kbw +5/MQfe43HeEoVWbNfgmRyP8VudO1UtVr07dGoUEWvFjudtd/h5H9THVdEpp2vH2Z +pSGypn8hRAbOzhIM4ExLOH4ZHb8gPQGiHRGUYXk3Cy95RSf/SpEnRi0p4/63Nx5M +JNXGM2Jk0RgGcYZcwJvLanT5Xdb9LM/IsDxLKXN+utDUgkzddvJbBC12aLaKaJA5 +LwIDAQAB +-----END PUBLIC KEY-----` + +const privateKey = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7WTglPvX0BTP/ +C5dvau3z3feiR8zYjKeZzpqRKxlYSxbX1vLM7RQenxvv3G+yY1AozXAEQGddvm36 +4uMkll6uoKJMHt8Evri0TFIogMhECUydC0x8ez+syBH6j83ZijYqKZDD0bziCgIR +sEXaRvDn8xB97jcd4ShVZs1+CZHI/xW507VS1WvTt0ahQRa8WO5213+Hkf1MdV0S +mna8fZmlIbKmfyFEBs7OEgzgTEs4fhkdvyA9AaIdEZRheTcLL3lFJ/9KkSdGLSnj +/rc3Hkwk1cYzYmTRGAZxhlzAm8tqdPld1v0sz8iwPEspc3660NSCTN128lsELXZo +topokDkvAgMBAAECggEAAWQMl0laQ8OZfiqWY72Ry0oYPgFvFO1PpkQHObm3+S+d +8Q81IgXNLNtWKSA4VpXYQ4zcJUpADmg1ZdxAfszUB4kcshHdpz4Z9Y849i6KW4l4 +qZsP3hbQWtTbgYWG71+M+y2sqJu0hgCkLPmm31AsJDG6zPtEKokKbYH7jWV0Xo5z +0g6IUqepc1ElNzsJAU10hgX5UZUPxvzbWHxhBhFzC51GKpfx/W5ZOQtB+W8+nlmC +OSVlZ9pfr6qxOZbSLWESU1xplywPTPLoYs/38oN5OHIJvB2j8kl+JfcR7v2ezLeV +fx1Z+x9ME0at7AbGCfhjIfJtftPsoCR60nzN3wWoAQKBgQDfOmfzLaWhVkvt49Hn +zeLdLI8pwqWXVYozsPMRlExwuIT1KeNolPzWWKx6dG38UzY4XWSvq+w3WAcQ7m6E +qiRWoRPL3qlWu3pDJYr/EfR2haPMQMwbJM/hg+nC0bhUSVqBEjOZgaQUHStIyugb +SWQFI3jE9fgj71DtbiVNrb1vAQKBgQDW2ljkotAjF81vI+EoN9QmuPYnejo42nK9 +jlSEU4hrDQMLiqxc5yJidQh75vZRfaO9rdUqHxoXK0DEU3Jk16Kb0n4nkM+xqKoc +yHTtAgUyflpenbrr4pRZf783XgI0bn/FhoMFQtAvSblru3NfEFQUtKIY82+Xa5H5 +g+cezSDYLwKBgBeViB39GJ6vC16azzZ6XhmX95gl5HDUrMFBVKzqyhiupf1w64HF +G+FZhP97BZO/Bt91nomg1FgUiMqVJkAF6cjtQ7YqVCHBtO0bLlA8iWNsQx31Spsj +jIL6+NuIZL0i8tjoH2N8euVVH5mVNmiLnHGeicflZM4HHrm3BWHrlTQBAoGBALeW +W98CQFe8Pw542ixDiESOR8fz6UwrXWAb/pwTxL20oKV8GUxJNFhtKJK3CEMZ2JB7 +uWoEqYairvUTWOxSVeBQPPwSAWcNeE6f+0mKMGa1EQNIRDDLq3fOcNYevkOPKB7g +kZQtQzclCAvGYQ8aJL6MmvY3DWOVx2YuD4+COE6BAoGAEGdChfJW5QGXaXEO/PnA +PbQCCzcqbs+0O6LVR1w68H0WQww94tZjfWPqn9kvwjzLd22ZMmdiBJ3bEbDeCjmG +Ybt48kS7y9n22CDgL7JkatszYpybvBSrDQL7ms7x2kKPkTMb7C5zpIIzdtvwH+Jf +6K3kQbqfFCM7VmyR7AmoyOk= +-----END PRIVATE KEY-----` + +const encryptionService = new RsaEncryptionService({ publicKey, privateKey }) + +describe('RsaEncryptionService', () => { + it('should encrypt and decrypt data correctly', () => { + const data = 'Hello, World!' + const encryptedData = encryptionService.encrypt(data) + const decryptedData = encryptionService.decrypt(encryptedData) + + expect(decryptedData).toBe(data) + }) + + it('should throw an error when decrypting with incorrect data', () => { + const incorrectData = 'invalidEncryptedData' + + expect(() => { + encryptionService.decrypt(incorrectData) + }).toThrow() + }) + + it('should throw an error when encrypting with an invalid public key', () => { + const invalidPublicKey = 'invalidPublicKey' + const invalidEncryptionService = new RsaEncryptionService({ publicKey: invalidPublicKey, privateKey }) + + expect(() => { + invalidEncryptionService.encrypt('test') + }).toThrow() + }) + + it('should throw an error when decrypting with an invalid private key', () => { + const data = 'Hello, World!' + const encryptedData = encryptionService.encrypt(data) + const invalidPrivateKey = 'invalidPrivateKey' + const invalidEncryptionService = new RsaEncryptionService({ publicKey, privateKey: invalidPrivateKey }) + + expect(() => { + invalidEncryptionService.decrypt(encryptedData) + }).toThrow() + }) +}) diff --git a/__test__/projects/GitHubProjectDataSource.test.ts b/__test__/projects/GitHubProjectDataSource.test.ts index ac01eaa1..6dcbda37 100644 --- a/__test__/projects/GitHubProjectDataSource.test.ts +++ b/__test__/projects/GitHubProjectDataSource.test.ts @@ -1,4 +1,29 @@ import { GitHubProjectDataSource } from "@/features/projects/data" +import RemoteConfig from "@/features/projects/domain/RemoteConfig" + +/** + * Simple encryption service for testing. Does nothing. + */ +const noopEncryptionService = { + encrypt: function (data: string): string { + return data + }, + decrypt: function (encryptedDataBase64: string): string { + return encryptedDataBase64 + } +} + +/** + * Simple encoder for testing + */ +const base64RemoteConfigEncoder = { + encode: function (remoteConfig: RemoteConfig): string { + return Buffer.from(JSON.stringify(remoteConfig)).toString("base64") + }, + decode: function (encodedString: string): RemoteConfig { + return JSON.parse(Buffer.from(encodedString, "base64").toString()) + } +} test("It loads repositories from data source", async () => { let didLoadRepositories = false @@ -9,7 +34,9 @@ test("It loads repositories from data source", async () => { didLoadRepositories = true return [] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) await sut.getProjects() expect(didLoadRepositories).toBeTruthy() @@ -43,7 +70,9 @@ test("It maps projects including branches and tags", async () => { }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects).toEqual([{ @@ -107,7 +136,9 @@ test("It removes suffix from project name", async () => { }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].id).toEqual("acme-foo") @@ -147,7 +178,9 @@ test("It supports multiple OpenAPI specifications on a branch", async () => { }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects).toEqual([{ @@ -209,7 +242,9 @@ test("It filters away projects with no versions", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects.length).toEqual(0) @@ -243,7 +278,9 @@ test("It filters away branches with no specifications", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions.length).toEqual(1) @@ -283,7 +320,9 @@ test("It filters away tags with no specifications", async () => { }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions.length).toEqual(2) @@ -314,7 +353,9 @@ test("It reads image from configuration file with .yml extension", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].imageURL).toEqual("/api/blob/acme/foo-openapi/icon.png?ref=12345678") @@ -345,7 +386,9 @@ test("It reads display name from configuration file with .yml extension", async tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].id).toEqual("acme-foo") @@ -378,7 +421,9 @@ test("It reads image from configuration file with .yaml extension", async () => tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].imageURL).toEqual("/api/blob/acme/foo-openapi/icon.png?ref=12345678") @@ -409,7 +454,9 @@ test("It reads display name from configuration file with .yaml extension", async tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].id).toEqual("acme-foo") @@ -478,7 +525,9 @@ test("It sorts projects alphabetically", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].name).toEqual("anne") @@ -529,7 +578,9 @@ test("It sorts versions alphabetically", async () => { }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions[0].name).toEqual("1.0") @@ -593,7 +644,9 @@ test("It prioritizes main, master, develop, and development branch names when so }] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions[0].name).toEqual("main") @@ -641,7 +694,9 @@ test("It identifies the default branch in returned versions", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() const defaultVersionNames = projects[0] @@ -682,7 +737,9 @@ test("It adds remote versions from the project configuration", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions).toEqual([{ @@ -692,11 +749,11 @@ test("It adds remote versions from the project configuration", async () => { specifications: [{ id: "huey", name: "Huey", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/huey.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/huey.yml" })}` }, { id: "dewey", name: "Dewey", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/dewey.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/dewey.yml" })}` }] }, { id: "bobby", @@ -705,7 +762,7 @@ test("It adds remote versions from the project configuration", async () => { specifications: [{ id: "louie", name: "Louie", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/louie.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/louie.yml" })}` }] }]) }) @@ -745,7 +802,9 @@ test("It modifies ID of remote version if the ID already exists", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions).toEqual([{ @@ -766,7 +825,7 @@ test("It modifies ID of remote version if the ID already exists", async () => { specifications: [{ id: "baz", name: "Baz", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/baz.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}` }] }, { id: "bar2", @@ -775,7 +834,7 @@ test("It modifies ID of remote version if the ID already exists", async () => { specifications: [{ id: "hello", name: "Hello", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/hello.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/hello.yml" })}` }] }]) }) @@ -806,7 +865,9 @@ test("It lets users specify the ID of a remote version", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions).toEqual([{ @@ -816,7 +877,7 @@ test("It lets users specify the ID of a remote version", async () => { specifications: [{ id: "baz", name: "Baz", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/baz.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}` }] }]) }) @@ -847,7 +908,9 @@ test("It lets users specify the ID of a remote specification", async () => { tags: [] }] } - } + }, + encryptionService: noopEncryptionService, + remoteConfigEncoder: base64RemoteConfigEncoder }) const projects = await sut.getProjects() expect(projects[0].versions).toEqual([{ @@ -857,7 +920,7 @@ test("It lets users specify the ID of a remote specification", async () => { specifications: [{ id: "some-spec", name: "Baz", - url: `/api/proxy?url=${encodeURIComponent("https://example.com/baz.yml")}` + url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}` }] }]) }) diff --git a/__test__/projects/RemoteConfigEncoder.test.ts b/__test__/projects/RemoteConfigEncoder.test.ts new file mode 100644 index 00000000..924f5633 --- /dev/null +++ b/__test__/projects/RemoteConfigEncoder.test.ts @@ -0,0 +1,38 @@ +import RemoteConfigEncoder from "@/features/projects/domain/RemoteConfigEncoder" +import { IEncryptionService } from "@/features/encrypt/EncryptionService" +import RemoteConfig from "@/features/projects/domain/RemoteConfig" +import { ZodError } from "zod" + +describe('RemoteConfigEncoder', () => { + const encryptionService: IEncryptionService = { + encrypt: (data: string) => `encrypted-${data}`, + decrypt: (data: string) => data.replace('encrypted-', '') + } + + const encoder = new RemoteConfigEncoder(encryptionService) + + it('should encode a remote config by first encrypting and then encoding with base64', () => { + const remoteConfig: RemoteConfig = { url: 'https://example.com/spec.yaml' } + const encoded = encoder.encode(remoteConfig) + const expectedEncoded = Buffer.from('encrypted-{"url":"https://example.com/spec.yaml"}').toString('base64') + expect(encoded).toEqual(expectedEncoded) + }) + + it('should decode an encoded string', () => { + const encodedString = Buffer.from('encrypted-{"url":"https://example.com/spec.yaml"}').toString('base64') + const decoded = encoder.decode(encodedString) + const expectedDecoded: RemoteConfig = { url: 'https://example.com/spec.yaml' } + expect(decoded).toEqual(expectedDecoded) + }) + + it('should throw an error if the decrypted string is not valid JSON', () => { + const invalidJson = Buffer.from('encrypted-invalid-json').toString('base64') + expect(() => encoder.decode(invalidJson)).toThrow(/Unexpected token/) + }) + + it('should throw an error if the remote config is not valid', () => { + const remoteConfig: RemoteConfig = { url: '' } + const encoded = encoder.encode(remoteConfig) + expect(() => encoder.decode(encoded)).toThrow(ZodError) + }) +}) diff --git a/src/app/(authed)/(home)/encrypt/layout.tsx b/src/app/(authed)/(home)/encrypt/layout.tsx new file mode 100644 index 00000000..d4114d0c --- /dev/null +++ b/src/app/(authed)/(home)/encrypt/layout.tsx @@ -0,0 +1,20 @@ +import { Box, Stack } from "@mui/material" +import SecondarySplitHeader from "@/features/sidebar/view/SecondarySplitHeader" + +export default function Page({ children }: { children: React.ReactNode }) { + return ( + + + + {children} + + + ) +} \ No newline at end of file diff --git a/src/app/(authed)/(home)/encrypt/page.tsx b/src/app/(authed)/(home)/encrypt/page.tsx new file mode 100644 index 00000000..5e6c28d4 --- /dev/null +++ b/src/app/(authed)/(home)/encrypt/page.tsx @@ -0,0 +1,44 @@ +import { Box, Typography } from '@mui/material' +import MessageLinkFooter from "@/common/ui/MessageLinkFooter" +import { EncryptionForm } from "@/features/encrypt/view/EncryptionForm" +import { env } from '@/common' + +const HELP_URL = env.getOrThrow("FRAMNA_DOCS_HELP_URL") +const SITE_NAME = env.getOrThrow("FRAMNA_DOCS_TITLE") + +export default async function EncryptPage() { + const possessiveName = SITE_NAME + (SITE_NAME.endsWith('s') ? "'" : "'s") + return ( + + + + Encrypt secrets + + + Use the form below to encrypt a secret using {possessiveName} public key. +

+ Authentication in remote specifications must be encrypted using {possessiveName} public key + before it is stored in a repository on GitHub. +
+ + {HELP_URL && + + } +
+
+ ) +} diff --git a/src/app/api/proxy/route.ts b/src/app/api/proxy/route.ts deleted file mode 100644 index 256ee955..00000000 --- a/src/app/api/proxy/route.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { NextRequest, NextResponse } from "next/server" -import { env, makeAPIErrorResponse, makeUnauthenticatedAPIErrorResponse } from "@/common" -import { session } from "@/composition" -import { parse as parseYaml } from "yaml" - -const ErrorName = { - MAX_FILE_SIZE_EXCEEDED: "MaxFileSizeExceededError", - TIMEOUT: "TimeoutError", - NOT_JSON_OR_YAML: "NotJsonOrYamlError", -} - -export async function GET(req: NextRequest) { - const isAuthenticated = await session.getIsAuthenticated() - if (!isAuthenticated) { - return makeUnauthenticatedAPIErrorResponse() - } - const rawURL = req.nextUrl.searchParams.get("url") - if (!rawURL) { - return makeAPIErrorResponse(400, "Missing \"url\" query parameter.") - } - let url: URL - try { - url = new URL(rawURL) - } catch { - return makeAPIErrorResponse(400, "Invalid \"url\" query parameter.") - } - try { - const maxMegabytes = Number(env.getOrThrow("PROXY_API_MAXIMUM_FILE_SIZE_IN_MEGABYTES")) - const timeoutInSeconds = Number(env.getOrThrow("PROXY_API_TIMEOUT_IN_SECONDS")) - const maxBytes = maxMegabytes * 1024 * 1024 - const fileText = await downloadFile({ url, maxBytes, timeoutInSeconds }) - checkIfJsonOrYaml(fileText) - return new NextResponse(fileText, { status: 200, headers: { "Content-Type": "text/plain" } }) - } catch (error) { - if (error instanceof Error == false) { - return makeAPIErrorResponse(500, "An unknown error occurred.") - } - if (error.name === ErrorName.MAX_FILE_SIZE_EXCEEDED) { - return makeAPIErrorResponse(413, "The operation was aborted.") - } else if (error.name === ErrorName.TIMEOUT) { - return makeAPIErrorResponse(408, "The operation timed out.") - } else if (error.name === ErrorName.NOT_JSON_OR_YAML) { - return makeAPIErrorResponse(400, "Url does not point to a JSON or YAML file.") - } else { - return makeAPIErrorResponse(500, error.message) - } - } -} - -async function downloadFile(params: { - url: URL, - maxBytes: number, - timeoutInSeconds: number -}): Promise { - const { url, maxBytes, timeoutInSeconds } = params - const abortController = new AbortController() - const timeoutSignal = AbortSignal.timeout(timeoutInSeconds * 1000) - const headers: {[key: string]: string} = {} - // Extract basic auth from URL and construct an Authorization header instead. - if ((url.username && url.username.length > 0) || (url.password && url.password.length > 0)) { - const username = decodeURIComponent(url.username) - const password = decodeURIComponent(url.password) - headers["Authorization"] = "Basic " + btoa(`${username}:${password}`) - } - // Make sure basic auth is removed from URL. - const urlWithoutAuth = url - urlWithoutAuth.username = "" - urlWithoutAuth.password = "" - const response = await fetch(urlWithoutAuth, { - method: "GET", - headers, - signal: AbortSignal.any([abortController.signal, timeoutSignal]) - }) - if (!response.body) { - throw new Error("Response body unavailable") - } - let totalBytes = 0 - let didExceedMaxBytes = false - const reader = response.body.getReader() - const chunks: Uint8Array[] = [] - // eslint-disable-next-line no-constant-condition - while (true) { - // eslint-disable-next-line no-await-in-loop - const { done, value } = await reader.read() - if (done) { - break - } - totalBytes += value.length - chunks.push(value) - if (totalBytes >= maxBytes) { - didExceedMaxBytes = true - abortController.abort() - break - } - } - if (didExceedMaxBytes) { - const error = new Error("Maximum file size exceeded") - error.name = ErrorName.MAX_FILE_SIZE_EXCEEDED - throw error - } - const blob = new Blob(chunks) - const arrayBuffer = await blob.arrayBuffer() - const decoder = new TextDecoder() - return decoder.decode(arrayBuffer) -} - -function checkIfJsonOrYaml(fileText: string) { - try { - parseYaml(fileText) // will also parse JSON as it is a subset of YAML - } catch { - const error = new Error("File is not JSON or YAML") - error.name = ErrorName.NOT_JSON_OR_YAML - throw error - } -} diff --git a/src/app/api/remotes/[encodedRemoteConfig]/route.ts b/src/app/api/remotes/[encodedRemoteConfig]/route.ts new file mode 100644 index 00000000..61950a87 --- /dev/null +++ b/src/app/api/remotes/[encodedRemoteConfig]/route.ts @@ -0,0 +1,64 @@ +import { NextRequest, NextResponse } from "next/server" +import { remoteConfigEncoder, session } from "@/composition" +import { env, makeAPIErrorResponse, makeUnauthenticatedAPIErrorResponse } from "@/common" +import { downloadFile, checkIfJsonOrYaml, ErrorName } from "@/common/utils/fileUtils"; + +interface RemoteSpecificationParams { + encodedRemoteConfig: string +} + +export async function GET(_req: NextRequest, { params }: { params: RemoteSpecificationParams }) { + const isAuthenticated = await session.getIsAuthenticated() + if (!isAuthenticated) { + return makeUnauthenticatedAPIErrorResponse() + } + + const remoteConfig = remoteConfigEncoder.decode(params.encodedRemoteConfig) + + let url: URL + try { + url = new URL(remoteConfig.url) + } catch { + return makeAPIErrorResponse(400, "Invalid \"url\" query parameter.") + } + try { + const maxMegabytes = Number(env.getOrThrow("PROXY_API_MAXIMUM_FILE_SIZE_IN_MEGABYTES")) + const timeoutInSeconds = Number(env.getOrThrow("PROXY_API_TIMEOUT_IN_SECONDS")) + const maxBytes = maxMegabytes * 1024 * 1024 + + const fileText = await downloadFile({ + url, + maxBytes, + timeoutInSeconds, + basicAuthUsername: remoteConfig.auth?.username, + basicAuthPassword: remoteConfig.auth?.password + }) + + checkIfJsonOrYaml(fileText) + + const fileName = url.pathname.split('/').pop() + + return new NextResponse(fileText, { + status: 200, + headers: { + "Content-Type": "text/plain", + "Content-Disposition": `attachment; filename="${fileName}"` // used for when downloading the file + } + }) + } catch (error) { + if (error instanceof Error == false) { + return makeAPIErrorResponse(500, "An unknown error occurred.") + } + if (error.name === ErrorName.MAX_FILE_SIZE_EXCEEDED) { + return makeAPIErrorResponse(413, "The operation was aborted.") + } else if (error.name === ErrorName.TIMEOUT) { + return makeAPIErrorResponse(408, "The operation timed out.") + } else if (error.name === ErrorName.NOT_JSON_OR_YAML) { + return makeAPIErrorResponse(400, "Url does not point to a JSON or YAML file.") + } else if (error.name === ErrorName.URL_MAY_NOT_INCLUDE_BASIC_AITH) { + return makeAPIErrorResponse(400, "Url may not include basic auth.") + } else { + return makeAPIErrorResponse(500, error.message) + } + } +} diff --git a/src/common/utils/fileUtils.ts b/src/common/utils/fileUtils.ts new file mode 100644 index 00000000..acc3b062 --- /dev/null +++ b/src/common/utils/fileUtils.ts @@ -0,0 +1,73 @@ +import { parse as parseYaml } from "yaml" + +export const ErrorName = { + MAX_FILE_SIZE_EXCEEDED: "MaxFileSizeExceededError", + TIMEOUT: "TimeoutError", + NOT_JSON_OR_YAML: "NotJsonOrYamlError", + URL_MAY_NOT_INCLUDE_BASIC_AITH: "UrlMayNotIncludeBasicAuth" +} + +export async function downloadFile(params: { + url: URL; + maxBytes: number; + timeoutInSeconds: number; + basicAuthUsername?: string; + basicAuthPassword?: string; +}): Promise { + const { url, maxBytes, timeoutInSeconds, basicAuthUsername, basicAuthPassword } = params; + const abortController = new AbortController(); + const timeoutSignal = AbortSignal.timeout(timeoutInSeconds * 1000); + const headers: { [key: string]: string; } = {}; + if (basicAuthUsername && basicAuthPassword) { + headers["Authorization"] = "Basic " + btoa(`${basicAuthUsername}:${basicAuthPassword}`); + } + // Make sure basic auth is removed from URL. + if ((url.username && url.username.length > 0) || (url.password && url.password.length > 0)) { + const error = new Error("URL may not include basic auth"); + error.name = ErrorName.URL_MAY_NOT_INCLUDE_BASIC_AITH; + throw error; + } + const fetchSignal = AbortSignal.any([abortController.signal, timeoutSignal]) + const response = await fetch(url, { method: "GET", headers, signal: fetchSignal }) + if (!response.body) { + throw new Error("Response body unavailable"); + } + let totalBytes = 0; + let didExceedMaxBytes = false; + const reader = response.body.getReader(); + const chunks: Uint8Array[] = []; + // eslint-disable-next-line no-constant-condition + while (true) { + // eslint-disable-next-line no-await-in-loop + const { done, value } = await reader.read(); + if (done) { + break; + } + totalBytes += value.length; + chunks.push(value); + if (totalBytes >= maxBytes) { + didExceedMaxBytes = true; + abortController.abort(); + break; + } + } + if (didExceedMaxBytes) { + const error = new Error("Maximum file size exceeded"); + error.name = ErrorName.MAX_FILE_SIZE_EXCEEDED; + throw error; + } + const blob = new Blob(chunks); + const arrayBuffer = await blob.arrayBuffer(); + const decoder = new TextDecoder(); + return decoder.decode(arrayBuffer); +} + +export function checkIfJsonOrYaml(fileText: string) { + try { + parseYaml(fileText) // will also parse JSON as it is a subset of YAML + } catch { + const error = new Error("File is not JSON or YAML") + error.name = ErrorName.NOT_JSON_OR_YAML + throw error + } +} diff --git a/src/composition.ts b/src/composition.ts index 8514a16b..40a754bc 100644 --- a/src/composition.ts +++ b/src/composition.ts @@ -51,6 +51,8 @@ import { PullRequestCommenter } from "@/features/hooks/domain" import { RepoRestrictedGitHubClient } from "./common/github/RepoRestrictedGitHubClient" +import RsaEncryptionService from "./features/encrypt/EncryptionService" +import RemoteConfigEncoder from "./features/projects/domain/RemoteConfigEncoder" const gitHubAppCredentials = { appId: env.getOrThrow("GITHUB_APP_ID"), @@ -176,6 +178,13 @@ export const projectRepository = new ProjectRepository({ repository: projectUserDataRepository }) +export const encryptionService = new RsaEncryptionService({ + publicKey: Buffer.from(env.getOrThrow("ENCRYPTION_PUBLIC_KEY_BASE_64"), "base64").toString("utf-8"), + privateKey: Buffer.from(env.getOrThrow("ENCRYPTION_PRIVATE_KEY_BASE_64"), "base64").toString("utf-8") +}) + +export const remoteConfigEncoder = new RemoteConfigEncoder(encryptionService) + export const projectDataSource = new CachingProjectDataSource({ dataSource: new GitHubProjectDataSource({ repositoryDataSource: new FilteringGitHubRepositoryDataSource({ @@ -189,7 +198,9 @@ export const projectDataSource = new CachingProjectDataSource({ projectConfigurationFilename: env.getOrThrow("FRAMNA_DOCS_PROJECT_CONFIGURATION_FILENAME") }) }), - repositoryNameSuffix: env.getOrThrow("REPOSITORY_NAME_SUFFIX") + repositoryNameSuffix: env.getOrThrow("REPOSITORY_NAME_SUFFIX"), + encryptionService: encryptionService, + remoteConfigEncoder: remoteConfigEncoder }), repository: projectRepository }) @@ -219,4 +230,4 @@ export const gitHubHookHandler = new GitHubHookHandler({ }) }) }) -}) \ No newline at end of file +}) diff --git a/src/features/encrypt/EncryptionService.ts b/src/features/encrypt/EncryptionService.ts new file mode 100644 index 00000000..67155e5c --- /dev/null +++ b/src/features/encrypt/EncryptionService.ts @@ -0,0 +1,42 @@ +import { publicEncrypt, privateDecrypt, constants } from 'crypto'; + +export interface IEncryptionService { + encrypt(data: string): string; + decrypt(encryptedDataBase64: string): string; +} + +class RsaEncryptionService implements IEncryptionService { + private publicKey: string; + private privateKey: string; + + constructor({ publicKey, privateKey }: { publicKey: string; privateKey: string }) { + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + encrypt(data: string): string { + const buffer = Buffer.from(data, 'utf-8'); + const encrypted = publicEncrypt( + { + key: this.publicKey, + padding: constants.RSA_PKCS1_OAEP_PADDING, + oaepHash: 'sha256' + }, + buffer + ); + return encrypted.toString('base64'); + } + + decrypt(encryptedDataBase64: string): string { + return privateDecrypt( + { + key: this.privateKey, + padding: constants.RSA_PKCS1_OAEP_PADDING, + oaepHash: 'sha256' + }, + Buffer.from(encryptedDataBase64, 'base64') + ).toString('utf-8') + } +} + +export default RsaEncryptionService; diff --git a/src/features/encrypt/view/EncryptionForm.tsx b/src/features/encrypt/view/EncryptionForm.tsx new file mode 100644 index 00000000..1c23f660 --- /dev/null +++ b/src/features/encrypt/view/EncryptionForm.tsx @@ -0,0 +1,101 @@ +'use client' + +import { useState } from 'react' +import { Box, Button, Snackbar, TextField, Tooltip, InputAdornment } from '@mui/material' +import { styled } from '@mui/material/styles' +import { encrypt } from "./encryptAction" +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" +import { faClipboard } from "@fortawesome/free-regular-svg-icons" + +export const EncryptionForm = () => { + const [inputText, setInputText] = useState('') + const [encryptedText, setEncryptedText] = useState('') + const [openSnackbar, setOpenSnackbar] = useState(false) + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault() + if (inputText.length > 0) { + const encrypted = await encrypt(inputText) + setEncryptedText(encrypted) + } else { + setEncryptedText("") + } + } + + const handleCopy = () => { + if (encryptedText.length > 0) { + navigator.clipboard.writeText(encryptedText) + setOpenSnackbar(true) + } + } + + const handleCloseSnackbar = () => { + setOpenSnackbar(false) + } + + const EncryptedValueTextField = styled(TextField)({ + '& .MuiInputBase-root': { + backgroundColor: '#F8F8F8' + } + }) + + return + setInputText(e.target.value)} + multiline + rows={8} + variant="outlined" + placeholder="Enter text to encrypt" + sx={{ width: "300px" }} + /> + + + + + + + + ) + } + }} + placeholder="Encrypted text appears here" + /> + + + + ; +} diff --git a/src/features/encrypt/view/encryptAction.ts b/src/features/encrypt/view/encryptAction.ts new file mode 100644 index 00000000..ed1161c1 --- /dev/null +++ b/src/features/encrypt/view/encryptAction.ts @@ -0,0 +1,7 @@ +'use server' + +import { encryptionService } from '@/composition' + +export async function encrypt(text: string): Promise { + return encryptionService.encrypt(text) +} diff --git a/src/features/projects/data/GitHubProjectDataSource.ts b/src/features/projects/data/GitHubProjectDataSource.ts index bc79fe25..df97c6bb 100644 --- a/src/features/projects/data/GitHubProjectDataSource.ts +++ b/src/features/projects/data/GitHubProjectDataSource.ts @@ -1,3 +1,4 @@ +import { IEncryptionService } from "@/features/encrypt/EncryptionService" import { Project, Version, @@ -9,17 +10,25 @@ import { GitHubRepository, GitHubRepositoryRef } from "../domain" +import RemoteConfig from "../domain/RemoteConfig" +import { IRemoteConfigEncoder } from "../domain/RemoteConfigEncoder" export default class GitHubProjectDataSource implements IProjectDataSource { private readonly repositoryDataSource: IGitHubRepositoryDataSource private readonly repositoryNameSuffix: string + private readonly encryptionService: IEncryptionService + private readonly remoteConfigEncoder: IRemoteConfigEncoder constructor(config: { repositoryDataSource: IGitHubRepositoryDataSource repositoryNameSuffix: string + encryptionService: IEncryptionService + remoteConfigEncoder: IRemoteConfigEncoder }) { this.repositoryDataSource = config.repositoryDataSource this.repositoryNameSuffix = config.repositoryNameSuffix + this.encryptionService = config.encryptionService + this.remoteConfigEncoder = config.remoteConfigEncoder } async getProjects(): Promise { @@ -167,11 +176,22 @@ export default class GitHubProjectDataSource implements IProjectDataSource { const existingVersionIdCount = versionIds.filter(e => e == baseVersionId).length const versionId = baseVersionId + (existingVersionIdCount > 0 ? existingVersionIdCount : "") const specifications = remoteVersion.specifications.map(e => { + const remoteConfig: RemoteConfig = { + url: e.url, + auth: e.auth ? { + type: e.auth.type, + username: this.encryptionService.decrypt(e.auth.encryptedUsername), + password: this.encryptionService.decrypt(e.auth.encryptedPassword) + } : undefined + }; + + const encodedRemoteConfig = this.remoteConfigEncoder.encode(remoteConfig); + return { id: this.makeURLSafeID((e.id || e.name).toLowerCase()), name: e.name, - url: `/api/proxy?url=${encodeURIComponent(e.url)}` - } + url: `/api/remotes/${encodedRemoteConfig}` + }; }) versions.push({ id: versionId, diff --git a/src/features/projects/domain/IProjectConfig.ts b/src/features/projects/domain/IProjectConfig.ts index ef4fd74b..08e27f7c 100644 --- a/src/features/projects/domain/IProjectConfig.ts +++ b/src/features/projects/domain/IProjectConfig.ts @@ -3,7 +3,12 @@ import { z } from "zod" export const ProjectConfigRemoteSpecificationSchema = z.object({ id: z.coerce.string().optional(), name: z.coerce.string(), - url: z.string() + url: z.string(), + auth: z.object({ + type: z.string(), + encryptedUsername: z.string(), + encryptedPassword: z.string() + }).optional(), }) export const ProjectConfigRemoteVersionSchema = z.object({ diff --git a/src/features/projects/domain/RemoteConfig.ts b/src/features/projects/domain/RemoteConfig.ts new file mode 100644 index 00000000..5afb559b --- /dev/null +++ b/src/features/projects/domain/RemoteConfig.ts @@ -0,0 +1,11 @@ +import { z } from 'zod' +import { RemoteSpecAuthSchema } from './RemoteSpecAuth' + +export const RemoteConfigSchema = z.object({ + url: z.string().url(), + auth: RemoteSpecAuthSchema.optional(), +}) + +type RemoteConfig = z.infer + +export default RemoteConfig diff --git a/src/features/projects/domain/RemoteConfigEncoder.ts b/src/features/projects/domain/RemoteConfigEncoder.ts new file mode 100644 index 00000000..6336efec --- /dev/null +++ b/src/features/projects/domain/RemoteConfigEncoder.ts @@ -0,0 +1,34 @@ +import { IEncryptionService } from "@/features/encrypt/EncryptionService"; +import RemoteConfig, { RemoteConfigSchema } from "./RemoteConfig"; + +export interface IRemoteConfigEncoder { + encode(remoteConfig: RemoteConfig): string; + decode(encodedString: string): RemoteConfig; +} + +/** + * Encodes and decodes remote configs. + * + * The remote config is first stringified to JSON, then encrypted, and finally encoded in base64. + * + * At the receiving end, the encoded string is first decoded from base64, then decrypted, and finally parsed as JSON. + */ +export default class RemoteConfigEncoder implements IRemoteConfigEncoder { + private readonly encryptionService: IEncryptionService; + + constructor(encryptionService: IEncryptionService) { + this.encryptionService = encryptionService; + } + + encode(remoteConfig: RemoteConfig): string { + const jsonString = JSON.stringify(remoteConfig); + const encryptedString = this.encryptionService.encrypt(jsonString); + return Buffer.from(encryptedString).toString('base64'); + } + + decode(encodedString: string): RemoteConfig { + const decodedString = Buffer.from(encodedString, 'base64').toString('utf-8'); + const decryptedString = this.encryptionService.decrypt(decodedString); + return RemoteConfigSchema.parse(JSON.parse(decryptedString)); + } +} diff --git a/src/features/projects/domain/RemoteSpecAuth.ts b/src/features/projects/domain/RemoteSpecAuth.ts new file mode 100644 index 00000000..5d72a335 --- /dev/null +++ b/src/features/projects/domain/RemoteSpecAuth.ts @@ -0,0 +1,11 @@ +import { z } from 'zod' + +export const RemoteSpecAuthSchema = z.object({ + type: z.string(), + username: z.string(), + password: z.string(), +}) + +type RemoteSpecAuth = z.infer + +export default RemoteSpecAuth From 67c466cb80cf0e1dcb81793caf222701ffac5b6a Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 5 Dec 2024 14:01:51 +0100 Subject: [PATCH 10/10] In case we fail to decrypt auth info is omitted This can happen if a different public key was used for encrypting username and/or password. --- .../projects/data/GitHubProjectDataSource.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/features/projects/data/GitHubProjectDataSource.ts b/src/features/projects/data/GitHubProjectDataSource.ts index df97c6bb..943e99c0 100644 --- a/src/features/projects/data/GitHubProjectDataSource.ts +++ b/src/features/projects/data/GitHubProjectDataSource.ts @@ -8,7 +8,8 @@ import { ProjectConfigRemoteVersion, IGitHubRepositoryDataSource, GitHubRepository, - GitHubRepositoryRef + GitHubRepositoryRef, + ProjectConfigRemoteSpecification } from "../domain" import RemoteConfig from "../domain/RemoteConfig" import { IRemoteConfigEncoder } from "../domain/RemoteConfigEncoder" @@ -178,11 +179,7 @@ export default class GitHubProjectDataSource implements IProjectDataSource { const specifications = remoteVersion.specifications.map(e => { const remoteConfig: RemoteConfig = { url: e.url, - auth: e.auth ? { - type: e.auth.type, - username: this.encryptionService.decrypt(e.auth.encryptedUsername), - password: this.encryptionService.decrypt(e.auth.encryptedPassword) - } : undefined + auth: this.tryDecryptAuth(e) }; const encodedRemoteConfig = this.remoteConfigEncoder.encode(remoteConfig); @@ -232,4 +229,21 @@ export default class GitHubProjectDataSource implements IProjectDataSource { .replace(/ /g, "-") .replace(/[^A-Za-z0-9-]/g, "") } + + private tryDecryptAuth(projectConfigRemoteSpec: ProjectConfigRemoteSpecification): { type: string, username: string, password: string } | undefined { + if (!projectConfigRemoteSpec.auth) { + return undefined + } + + try { + return { + type: projectConfigRemoteSpec.auth.type, + username: this.encryptionService.decrypt(projectConfigRemoteSpec.auth.encryptedUsername), + password: this.encryptionService.decrypt(projectConfigRemoteSpec.auth.encryptedPassword) + } + } catch (error) { + console.error(`Failed to decrypt remote specification auth for ${projectConfigRemoteSpec.url}. Perhaps a different public key was used?:`, error); + return undefined + } + } }