diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 56af1bd3d7..d90777acdf 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -51,6 +51,7 @@ runs: shell: bash - name: "Bootstrap project" + if: ${{ runner.os != 'Windows' }} run: | if [[ ! -z "${{ inputs.bootstrap-packages }}" ]] then @@ -59,3 +60,13 @@ runs: lerna bootstrap fi shell: bash + + - name: "Bootstrap project on windows" + if: ${{ runner.os == 'Windows' }} + run: | + if ( "${{ inputs.bootstrap-packages }}" ) { + lerna bootstrap --scope '{${{ inputs.bootstrap-packages }},}' + } else { + lerna bootstrap + } + shell: powershell diff --git a/.github/secrets/match_AppStore_comquietmobile.mobileprovision.gpg b/.github/secrets/match_AppStore_comquietmobile.mobileprovision.gpg index 4f35bf8199..27f3a9a038 100644 Binary files a/.github/secrets/match_AppStore_comquietmobile.mobileprovision.gpg and b/.github/secrets/match_AppStore_comquietmobile.mobileprovision.gpg differ diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 6bae30f594..1f41fdd237 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -17,7 +17,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env @@ -38,7 +38,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env @@ -59,7 +59,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env diff --git a/.github/workflows/check-desktop-visual-regression.yml b/.github/workflows/check-desktop-visual-regression.yml index d29e0efb8d..f86cfc14fd 100644 --- a/.github/workflows/check-desktop-visual-regression.yml +++ b/.github/workflows/check-desktop-visual-regression.yml @@ -17,7 +17,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Required to retrieve git history @@ -31,4 +31,4 @@ jobs: with: workingDir: ./packages/desktop token: ${{ secrets.GH_TOKEN }} - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + projectToken: 3218757eee04 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 4b951fd4e0..7a05a53f69 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -16,7 +16,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Remove test files workaround (jest types conflicting with cypress types)" if: ${{ runner.os == 'Windows' }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 090aaa8b24..07ee9e671c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,11 +41,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 + uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -55,7 +55,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 + uses: github/codeql-action/autobuild@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -68,6 +68,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@a09933a12a80f87b87005513f0abb1494c27a716 # v2.21.4 + uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: category: "/language:${{matrix.language}}" \ No newline at end of file diff --git a/.github/workflows/depencency-review.yml b/.github/workflows/depencency-review.yml index 23044f791b..7989380270 100644 --- a/.github/workflows/depencency-review.yml +++ b/.github/workflows/depencency-review.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@0efb1d1d84fc9633afcdaad14c485cbbc90ef46c # v2.5.1 \ No newline at end of file + uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0 diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index c3e0fcf512..44822900ff 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -34,7 +34,7 @@ jobs: CHECKSUM_PATH: ${{ github.event.action == 'released' && 'packages/desktop/dist/latest-linux.yml' || 'packages/desktop/dist/alpha-linux.yml' }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup environment uses: ./.github/actions/setup-env @@ -105,7 +105,7 @@ jobs: S3_BUCKET: ${{ github.event.action == 'released' && 'quiet' || 'test.quiet' }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: actions-rs/components-nightly@v1 with: @@ -153,7 +153,7 @@ jobs: - name: Extract version id: extract_version - uses: Saionaro/extract-package-version@v1.1.1 + uses: Saionaro/extract-package-version@v1.2.1 with: path: packages/desktop @@ -178,7 +178,7 @@ jobs: S3_BUCKET: ${{ github.event.action == 'released' && 'quiet' || 'test.quiet' }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Fetch jsign" shell: bash @@ -217,7 +217,7 @@ jobs: # - name: E2E - Extract version # id: extract_version - # uses: Saionaro/extract-package-version@v1.1.1 + # uses: Saionaro/extract-package-version@v1.2.1 # with: # path: packages/desktop @@ -274,7 +274,7 @@ jobs: - name: Extract version id: extract_version - uses: Saionaro/extract-package-version@v1.1.1 + uses: Saionaro/extract-package-version@v1.2.1 with: path: packages/desktop diff --git a/.github/workflows/desktop-test-scroll.yml b/.github/workflows/desktop-test-scroll.yml index 6e59c8e3f7..bb9a6c6a7c 100644 --- a/.github/workflows/desktop-test-scroll.yml +++ b/.github/workflows/desktop-test-scroll.yml @@ -18,7 +18,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup environment uses: ./.github/actions/setup-env @@ -31,14 +31,14 @@ jobs: - name: "Remove test files workaround" run: find packages/desktop/src -name '*.test.*' -delete && find packages/backend/src -name '*.test.*' -delete - - uses: cypress-io/github-action@v2 + - uses: cypress-io/github-action@v6 with: install: false command: npm run regression-test:ci working-directory: packages/desktop - name: Archive test screenshots - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: test-screenshots-linux diff --git a/.github/workflows/desktop-tests.yml b/.github/workflows/desktop-tests.yml index e5b21cfe10..bba3708c19 100644 --- a/.github/workflows/desktop-tests.yml +++ b/.github/workflows/desktop-tests.yml @@ -18,7 +18,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env diff --git a/.github/workflows/e2e-linux.yml b/.github/workflows/e2e-linux.yml index adca0030d3..3e957e1fe7 100644 --- a/.github/workflows/e2e-linux.yml +++ b/.github/workflows/e2e-linux.yml @@ -18,7 +18,7 @@ jobs: TEST_MODE: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install WM run: sudo apt install fluxbox @@ -53,12 +53,12 @@ jobs: max_attempts: 3 command: cd packages/e2e-tests && npm run test oneClient.test.ts - - name: Run two clients test + - name: Run multiple clients test uses: nick-fields/retry@v2 with: timeout_minutes: 25 max_attempts: 3 - command: cd packages/e2e-tests && npm run test twoClients.test.ts + command: cd packages/e2e-tests && npm run test multipleClients.test.ts - name: Run invitation link test - Includes 2 separate application clients uses: nick-fields/retry@v2 diff --git a/.github/workflows/e2e-mac.yml b/.github/workflows/e2e-mac.yml index 0bf9718477..52154c22dd 100644 --- a/.github/workflows/e2e-mac.yml +++ b/.github/workflows/e2e-mac.yml @@ -11,7 +11,7 @@ jobs: IS_E2E: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env @@ -61,11 +61,11 @@ jobs: max_attempts: 3 command: cd packages/e2e-tests && npm run test oneClient.test.ts - - name: Run two clients test + - name: Run multiple clients test uses: nick-fields/retry@v2 with: timeout_minutes: 25 max_attempts: 3 - command: cd packages/e2e-tests && npm run test twoClients.test.ts + command: cd packages/e2e-tests && npm run test multipleClients.test.ts diff --git a/.github/workflows/e2e-win.yml b/.github/workflows/e2e-win.yml index 9f06c84c28..490ae7d32a 100644 --- a/.github/workflows/e2e-win.yml +++ b/.github/workflows/e2e-win.yml @@ -13,7 +13,7 @@ jobs: E2E: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env @@ -41,7 +41,7 @@ jobs: - name: Extract version id: extract_version - uses: Saionaro/extract-package-version@v1.1.1 + uses: Saionaro/extract-package-version@v1.2.1 with: path: packages/desktop @@ -56,7 +56,7 @@ jobs: shell: bash - name: "Upload built app" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: quiet-windows path: ./packages/desktop/dist/Quiet Setup ${{ steps.extract_version.outputs.version }}.exe @@ -68,11 +68,11 @@ jobs: shell: powershell - name: Kill Quiet - run: Stop-Process -Name "Quiet" -Force + run: Get-Process -Name "Quiet" -ErrorAction SilentlyContinue | Stop-Process -Force shell: powershell - name: Kill tor - run: Stop-Process -Name "tor" -Force + run: Get-Process -Name "tor" -ErrorAction SilentlyContinue | Stop-Process -Force shell: powershell - name: Delay @@ -87,13 +87,13 @@ jobs: shell: bash command: cd packages/e2e-tests && npm run test oneClient.test.ts - - name: Run two clients test + - name: Run multiple clients test uses: nick-fields/retry@v2 with: timeout_minutes: 30 max_attempts: 3 shell: bash - command: cd packages/e2e-tests && npm run test twoClients.test.ts + command: cd packages/e2e-tests && npm run test multipleClients.test.ts - name: Run invitation link test - Includes 2 separate application clients uses: nick-fields/retry@v2 diff --git a/.github/workflows/identity-tests.yml b/.github/workflows/identity-tests.yml index 6a83d07a21..033308b099 100644 --- a/.github/workflows/identity-tests.yml +++ b/.github/workflows/identity-tests.yml @@ -18,7 +18,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 48bc41d289..18680ddb4f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -20,7 +20,7 @@ jobs: - name: 'Print OS' run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env diff --git a/.github/workflows/mobile-deploy-android.yaml b/.github/workflows/mobile-deploy-android.yaml index dd8cbd5878..7326b8ac49 100644 --- a/.github/workflows/mobile-deploy-android.yaml +++ b/.github/workflows/mobile-deploy-android.yaml @@ -19,7 +19,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Set up JDK" uses: actions/setup-java@v3 @@ -65,7 +65,7 @@ jobs: - name: "Upload Artifact" continue-on-error: true - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: app-standard-release.aab path: ./packages/mobile/android/app/build/outputs/bundle/standardRelease/app-standard-release.aab diff --git a/.github/workflows/mobile-deploy-ios.yml b/.github/workflows/mobile-deploy-ios.yml index e86ae241dc..98bd9caee7 100644 --- a/.github/workflows/mobile-deploy-ios.yml +++ b/.github/workflows/mobile-deploy-ios.yml @@ -19,7 +19,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: lfs: true @@ -70,7 +70,7 @@ jobs: -exportPath build/ - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Quiet.ipa path: ./packages/mobile/ios/build/Quiet.ipa diff --git a/.github/workflows/mobile-tests.yml b/.github/workflows/mobile-tests.yml index ad9e047059..46f8ba291c 100644 --- a/.github/workflows/mobile-tests.yml +++ b/.github/workflows/mobile-tests.yml @@ -18,7 +18,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup environment uses: ./.github/actions/setup-env diff --git a/.github/workflows/state-manager-tests.yml b/.github/workflows/state-manager-tests.yml index 389f2746e6..2ecad2b0b1 100644 --- a/.github/workflows/state-manager-tests.yml +++ b/.github/workflows/state-manager-tests.yml @@ -18,7 +18,7 @@ jobs: - name: "Print OS" run: echo ${{ matrix.os }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup environment" uses: ./.github/actions/setup-env diff --git a/CHANGELOG.md b/CHANGELOG.md index 5be4da8d35..f8e3014843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,37 @@ -[quiet@2.0.0-alpha.10] + +[2.0.1-alpha.2] + +* UI layer for taken usernames for desktop and mobile + +* Change nickname for taken username + +* Map messages sent before changing username + +* Update registrar service to match new registration flow. + +* Add possible impersonation attack UI for desktop and mobile + +* Fix truncated long messages in channelInput component + +* Unblock mobile e2e tests + +* Prettify loading component on Chat screen (mobile) + +* Running Chromatic tests for forked PRs + +* Added e2e test for user joining community when owner is offline. Improved e2e tests + +* Bump github actions/* to versions using node16 + +* Project can now be bootstraped on Windows (powershell) + +* Placeholder(...) for community name + +* No unregistered/duplicated label for system messages + +[2.0.0-alpha.11] + +* Customize Launch Screen on iOS * Suspends certain websocket events until backend becomes fully operative (faster and dumber frontend). diff --git a/lerna.json b/lerna.json index 8a24301f53..aca35a8710 100644 --- a/lerna.json +++ b/lerna.json @@ -5,7 +5,7 @@ "version": "independent", "command": { "version": { - "allowBranch": ["master", "develop", "mobile/releasable"], + "allowBranch": ["master", "develop"], "conventionalCommits": true, "createRelease": "github" }, diff --git a/packages/backend-bundle/CHANGELOG.md b/packages/backend-bundle/CHANGELOG.md index 87d88e889b..4291ace9ec 100644 --- a/packages/backend-bundle/CHANGELOG.md +++ b/packages/backend-bundle/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.1-alpha.2](https://github.com/TryQuiet/quiet/compare/backend-bundle@1.6.1...backend-bundle@2.0.1-alpha.2) (2023-10-09) + +**Note:** Version bump only for package backend-bundle + + + + + +## [2.0.1-alpha.1](https://github.com/ZbayApp/monorepo/compare/backend-bundle@2.0.1-alpha.0...backend-bundle@2.0.1-alpha.1) (2023-09-25) + +**Note:** Version bump only for package backend-bundle + + + + + +## [2.0.1-alpha.0](https://github.com/ZbayApp/monorepo/compare/backend-bundle@1.7.0-alpha.0...backend-bundle@2.0.1-alpha.0) (2023-09-25) + +**Note:** Version bump only for package backend-bundle + + + + + # [2.0.0-alpha.18](https://github.com/ZbayApp/monorepo/compare/backend-bundle@1.6.1...backend-bundle@2.0.0-alpha.18) (2023-10-04) **Note:** Version bump only for package backend-bundle diff --git a/packages/backend-bundle/package-lock.json b/packages/backend-bundle/package-lock.json index d7cafddce4..fc0f6ab4ee 100644 --- a/packages/backend-bundle/package-lock.json +++ b/packages/backend-bundle/package-lock.json @@ -1,12 +1,12 @@ { "name": "backend-bundle", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "backend-bundle", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "license": "ISC" } } diff --git a/packages/backend-bundle/package.json b/packages/backend-bundle/package.json index c05b9449de..60f847aa8a 100644 --- a/packages/backend-bundle/package.json +++ b/packages/backend-bundle/package.json @@ -1,6 +1,6 @@ { "name": "backend-bundle", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "description": "", "main": "bundle.cjs", "scripts": {}, diff --git a/packages/backend/.gitattributes b/packages/backend/.gitattributes new file mode 100644 index 0000000000..2271e38305 --- /dev/null +++ b/packages/backend/.gitattributes @@ -0,0 +1,5 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Declare files that will always have CRLF line endings on checkout. +electron-fetch-git.patch text eol=crlf \ No newline at end of file diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 0ed5fe4960..0e5a476501 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.1-alpha.2](https://github.com/TryQuiet/backend/compare/@quiet/backend@1.9.4...@quiet/backend@2.0.1-alpha.2) (2023-10-09) + +**Note:** Version bump only for package @quiet/backend + + + + + +## [2.0.1-alpha.1](https://github.com/TryQuiet/backend/compare/@quiet/backend@2.0.1-alpha.0...@quiet/backend@2.0.1-alpha.1) (2023-09-25) + +**Note:** Version bump only for package @quiet/backend + + + + + +## [2.0.1-alpha.0](https://github.com/TryQuiet/backend/compare/@quiet/backend@2.0.0-alpha.5...@quiet/backend@2.0.1-alpha.0) (2023-09-25) + +**Note:** Version bump only for package @quiet/backend + + + + + # [2.0.0-alpha.20](https://github.com/TryQuiet/backend/compare/@quiet/backend@2.0.0-alpha.19...@quiet/backend@2.0.0-alpha.20) (2023-10-09) **Note:** Version bump only for package @quiet/backend @@ -74,7 +98,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline - # [1.10.0-alpha.0](https://github.com/TryQuiet/backend/compare/@quiet/backend@1.9.0...@quiet/backend@1.10.0-alpha.0) (2023-08-29) **Note:** Version bump only for package @quiet/backend diff --git a/packages/backend/electron-fetch-git.patch b/packages/backend/electron-fetch-git.patch new file mode 100644 index 0000000000..68534bfed9 --- /dev/null +++ b/packages/backend/electron-fetch-git.patch @@ -0,0 +1,18 @@ +diff --git a/packages/backend/node_modules/electron-fetch/lib/index.js b/packages/backend/node_modules/electron-fetch/lib/index.js +index c9ea590d9..74c0757a8 100644 +--- a/packages/backend/node_modules/electron-fetch/lib/index.js ++++ b/packages/backend/node_modules/electron-fetch/lib/index.js +@@ -1283,12 +1283,7 @@ function getNodeRequestOptions(request) { + + let electron; // istanbul ignore else + +-if (process.versions.electron) { +- electron = require('electron'); +-} +- +-const isReady = electron && electron.app && !electron.app.isReady() ? new Promise(resolve => electron.app.once('ready', resolve)) : Promise.resolve(); +- ++const isReady = Promise.resolve(); + /** + * Fetch function + * diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json index f31f587e56..ae6e0430d6 100644 --- a/packages/backend/package-lock.json +++ b/packages/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "@quiet/backend", - "version": "2.0.0-alpha.20", + "version": "2.0.1-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@quiet/backend", - "version": "2.0.0-alpha.20", + "version": "2.0.1-alpha.2", "license": "MIT", "dependencies": { "@chainsafe/libp2p-gossipsub": "6.1.0", @@ -79,6 +79,7 @@ "fetch-mock-jest": "^1.5.1", "jest": "^29.4.2", "mock-fs": "^5.1.2", + "run-script-os": "1.1.6", "tmp": "^0.2.1", "ts-jest": "^29.0.3", "ts-loader": "9.4.2", @@ -20049,6 +20050,16 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==", + "dev": true, + "bin": { + "run-os": "index.js", + "run-script-os": "index.js" + } + }, "node_modules/rxjs": { "version": "7.8.1", "license": "Apache-2.0", @@ -35445,6 +35456,12 @@ "queue-microtask": "^1.2.2" } }, + "run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==", + "dev": true + }, "rxjs": { "version": "7.8.1", "requires": { diff --git a/packages/backend/package.json b/packages/backend/package.json index 91c069b28f..294568124b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "@quiet/backend", - "version": "2.0.0-alpha.20", + "version": "2.0.1-alpha.2", "description": "tlg-manager", "types": "lib/index.d.ts", "type": "module", @@ -10,14 +10,18 @@ "private": true, "scripts": { "build": "tsc -p tsconfig.build.json", - "webpack": "webpack --env mode=development && cp ./lib/bundle.cjs ../backend-bundle/bundle.cjs", + "webpack": "run-script-os", + "webpack:default": "webpack --env mode=development && cp ./lib/bundle.cjs ../backend-bundle/bundle.cjs", "webpack:prod": "webpack --env mode=production && cp ./lib/bundle.cjs ../backend-bundle/bundle.cjs", - "applyPatches": "patch -f -p0 < ./electron-fetch.patch || true && patch -f -p0 --forward --binary < ./parse-duration.patch || true && patch -f -p0 --forward --binary < ./parse-duration-esm.patch || true", + "webpack:windows": "webpack --env mode=development && xcopy .\\lib\\bundle.cjs ..\\backend-bundle\\ /Y", + "webpack:prod:windows": "webpack --env mode=production && xcopy .\\lib\\bundle.cjs ..\\backend-bundle\\ /Y", + "applyPatches": "run-script-os", + "applyPatches:default": "patch -f -p0 < ./electron-fetch.patch || true && patch -f -p0 --forward --binary < ./parse-duration.patch || true && patch -f -p0 --forward --binary < ./parse-duration-esm.patch || true", + "applyPatches:windows": "git apply ./electron-fetch-git.patch --whitespace=fix --reject --verbose --no-index --ignore-space-change --inaccurate-eof || cd .", "prepare": "npm run applyPatches && npm run webpack", "version": "git add -A src", "lint": "eslint --ext .jsx,.js,.ts,.tsx ./src/ --fix", "lint-ci": "eslint --ext .jsx,.js,.ts,.tsx ./src/", - "test2": "cross-env NODE_OPTIONS=--experimental-vm-modules DEBUG=ipfs:*,backend:* node_modules/jest/bin/jest.js", "test-nest": "cross-env NODE_OPTIONS=--experimental-vm-modules DEBUG=ipfs:*,backend:* node_modules/jest/bin/jest.js --detectOpenHandles --forceExit ./src/nest/**/*.spec.ts", "test": "cross-env NODE_OPTIONS=--experimental-vm-modules DEBUG=ipfs:*,backend:* node_modules/jest/bin/jest.js ./src/**/* --runInBand --verbose --testPathIgnorePatterns=\".src/(!?nodeTest*)|(.node_modules*)\"", "test-ci": "cross-env NODE_OPTIONS=--experimental-vm-modules jest ./src/**/* --runInBand --colors --ci --silent --verbose --testPathIgnorePatterns=\".src/nest/(!?nodeTest*)|(.node_modules*)|src/nest/.*\\.tor.spec\\.(t|j)s|src/nest/ipfs-file-manager/big-files.long.spec.ts$\"", @@ -54,8 +58,8 @@ "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", - "@quiet/eslint-config": "^2.0.0-alpha.18", - "@quiet/state-manager": "^2.0.0-alpha.18", + "@quiet/eslint-config": "^2.0.1-alpha.2", + "@quiet/state-manager": "^2.0.1-alpha.2", "@types/crypto-js": "^4.0.2", "@types/express": "^4.17.9", "@types/jest": "28.1.8", @@ -73,6 +77,7 @@ "fetch-mock-jest": "^1.5.1", "jest": "^29.4.2", "mock-fs": "^5.1.2", + "run-script-os": "1.1.6", "tmp": "^0.2.1", "ts-jest": "^29.0.3", "ts-loader": "9.4.2", @@ -90,10 +95,10 @@ "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "@peculiar/webcrypto": "1.4.3", - "@quiet/common": "^2.0.0-alpha.18", - "@quiet/identity": "^2.0.0-alpha.18", - "@quiet/logger": "^2.0.0-alpha.18", - "@quiet/types": "^2.0.0-alpha.18", + "@quiet/common": "^2.0.1-alpha.2", + "@quiet/identity": "^2.0.1-alpha.2", + "@quiet/logger": "^2.0.1-alpha.2", + "@quiet/types": "^2.0.1-alpha.2", "abortable-iterator": "^3.0.0", "class-transformer": "^0.5.1", "class-validator": "^0.13.1", diff --git a/packages/backend/src/backendManager.ts b/packages/backend/src/backendManager.ts index 9f3e9e21c6..f7e80b5e4e 100644 --- a/packages/backend/src/backendManager.ts +++ b/packages/backend/src/backendManager.ts @@ -72,7 +72,7 @@ export const runBackendDesktop = async () => { try { await connectionsManager.closeAllServices() } catch (e) { - log.error('Error occured while closing backend services', e) + log.error('Error occurred while closing backend services', e) } if (process.send) process.send('closed-services') } @@ -80,7 +80,7 @@ export const runBackendDesktop = async () => { try { await connectionsManager.leaveCommunity() } catch (e) { - log.error('Error occured while leaving community', e) + log.error('Error occurred while leaving community', e) } if (process.send) process.send('leftCommunity') } diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts index abc3ad923e..4952b669a6 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.spec.ts @@ -2,7 +2,7 @@ import { jest } from '@jest/globals' import { LazyModuleLoader } from '@nestjs/core' import { Test, TestingModule } from '@nestjs/testing' import { getFactory, prepareStore, type Store, type communities, type identity } from '@quiet/state-manager' -import { type Community, type Identity, type InitCommunityPayload, type LaunchRegistrarPayload } from '@quiet/types' +import { type Community, type Identity, type InitCommunityPayload } from '@quiet/types' import { type FactoryGirl } from 'factory-girl' import PeerId from 'peer-id' import { TestModule } from '../common/test.module' @@ -108,10 +108,8 @@ describe('ConnectionsManagerService', () => { await connectionsManagerService.closeAllServices() const launchCommunitySpy = jest.spyOn(connectionsManagerService, 'launchCommunity').mockResolvedValue() - const launchRegistrarSpy = jest.spyOn(registrationService, 'launchRegistrar').mockResolvedValue() await connectionsManagerService.init() - expect(launchRegistrarSpy).not.toHaveBeenCalled() expect(launchCommunitySpy).toHaveBeenCalledWith(launchCommunityPayload) }) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index d3ca9704aa..c733bb55c1 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -30,11 +30,8 @@ import { NetworkStats, PushNotificationPayload, RegisterOwnerCertificatePayload, - RegisterUserCertificatePayload, RemoveDownloadStatus, ResponseCreateNetworkPayload, - SaveCertificatePayload, - SaveOwnerCertificatePayload, SendCertificatesResponse, SendMessagePayload, SetChannelSubscribedPayload, @@ -43,7 +40,6 @@ import { UploadFilePayload, PeerId as PeerIdType, SaveCSRPayload, - SendUserCertificatePayload, CommunityMetadata, CommunityMetadataPayload, } from '@quiet/types' @@ -178,10 +174,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI if (this.tor && !options.saveTor) { await this.tor.kill() } - if (this.registrationService) { - this.logger('Stopping registration service') - await this.registrationService.stop() - } if (this.storageService) { this.logger('Stopping orbitdb') await this.storageService?.stopOrbitDb() @@ -362,7 +354,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI targetPort: this.ports.libp2pHiddenService, peers, } - this.logger('libp2p params', params) await this.libp2pService.createInstance(params) // KACPER @@ -396,26 +387,11 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI this.socketService.on(SocketActionTypes.CONNECTION_PROCESS_INFO, data => { this.serverIoProvider.io.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, data) }) - - this.registrationService.on(SocketActionTypes.CONNECTION_PROCESS_INFO, data => { - this.serverIoProvider.io.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, data) - }) } private attachRegistrationListeners() { - this.registrationService.on(RegistrationEvents.REGISTRAR_STATE, (payload: ServiceState) => { - this.registrarState = payload - }) this.registrationService.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload => { this.serverIoProvider.io.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, payload) }) - this.registrationService.on(RegistrationEvents.SPAWN_HS_FOR_REGISTRAR, async payload => { - const onionAddress = await this.tor.spawnHiddenService({ - targetPort: payload.port, - privKey: payload.privateKey, - virtPort: payload.targetPort, - }) - this.registrationService.onionAddress = onionAddress - }) this.registrationService.on(RegistrationEvents.ERROR, payload => { emitError(this.serverIoProvider.io, payload) }) @@ -529,7 +505,6 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI }) this.storageService.on(StorageEvents.LOAD_CERTIFICATES, (payload: SendCertificatesResponse) => { this.serverIoProvider.io.emit(SocketActionTypes.RESPONSE_GET_CERTIFICATES, payload) - this.registrationService.emit(RegistrationEvents.SET_CERTIFICATES, payload.certificates) }) this.storageService.on(StorageEvents.LOAD_PUBLIC_CHANNELS, (payload: ChannelsReplicatedPayload) => { this.serverIoProvider.io.emit(SocketActionTypes.CHANNELS_REPLICATED, payload) @@ -584,11 +559,14 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI console.log('emitting deleted channel event back to state manager') this.serverIoProvider.io.emit(SocketActionTypes.CHANNEL_DELETION_RESPONSE, payload) }) - this.storageService.on(StorageEvents.REPLICATED_CSR, async (payload: string[]) => { - console.log(`On ${StorageEvents.REPLICATED_CSR}`) - this.serverIoProvider.io.emit(SocketActionTypes.RESPONSE_GET_CSRS, { csrs: payload }) - payload.forEach(csr => this.registrationService.emit(RegistrationEvents.REGISTER_USER_CERTIFICATE, csr)) - }) + this.storageService.on( + StorageEvents.REPLICATED_CSR, + async (payload: { csrs: string[]; certificates: string[] }) => { + console.log(`On ${StorageEvents.REPLICATED_CSR}`) + this.serverIoProvider.io.emit(SocketActionTypes.RESPONSE_GET_CSRS, { csrs: payload.csrs }) + this.registrationService.emit(RegistrationEvents.REGISTER_USER_CERTIFICATE, payload) + } + ) this.storageService.on(StorageEvents.REPLICATED_COMMUNITY_METADATA, (payload: CommunityMetadata) => { console.log(`On ${StorageEvents.REPLICATED_COMMUNITY_METADATA}: ${payload}`) const communityMetadataPayload: CommunityMetadataPayload = { diff --git a/packages/backend/src/nest/registration/registration.functions.ts b/packages/backend/src/nest/registration/registration.functions.ts index 43bde69f62..1363eae65e 100644 --- a/packages/backend/src/nest/registration/registration.functions.ts +++ b/packages/backend/src/nest/registration/registration.functions.ts @@ -1,31 +1,12 @@ -import { - createUserCert, - loadCSR, - CertFieldsTypes, - getReqFieldValue, - keyFromCertificate, - parseCertificate, - getCertFieldValue, -} from '@quiet/identity' +import { createUserCert, keyFromCertificate } from '@quiet/identity' import { IsBase64, IsNotEmpty, validate } from 'class-validator' -import { CertificationRequest } from 'pkijs' -import { Agent } from 'http' -import AbortController from 'abort-controller' -import fetch, { Response } from 'node-fetch' -import { getUsersAddresses } from '../common/utils' -import { - ErrorCodes, - ErrorMessages, - ErrorPayload, - PermsData, - SocketActionTypes, - SuccessfullRegistrarionResponse, - UserCertificatePayload, - UserData, -} from '@quiet/types' +import { ErrorPayload, PermsData, SocketActionTypes, SuccessfullRegistrarionResponse } from '@quiet/types' import { CsrContainsFields, IsCsr } from './registration.validators' import { RegistrationEvents } from './registration.types' +import { loadCSR, CertFieldsTypes, getCertFieldValue, getReqFieldValue, parseCertificate } from '@quiet/identity' +import { CertificationRequest } from 'pkijs' import Logger from '../common/logger' +import { load } from 'mock-fs' const logger = Logger('registration.functions') class UserCsrData { @@ -37,51 +18,8 @@ class UserCsrData { } export interface RegistrarResponse { - status: number - body: any -} - -// REFACTORING: Move this method to identity package -export const pubKeyMatch = (cert: string, parsedCsr: CertificationRequest): boolean => { - const parsedCertificate = parseCertificate(cert) - const pubKey = keyFromCertificate(parsedCertificate) - const pubKeyCsr = keyFromCertificate(parsedCsr) - - if (pubKey === pubKeyCsr) { - return true - } - return false -} - -export const registerOwner = async (userCsr: string, permsData: PermsData): Promise => { - const userData = new UserCsrData() - userData.csr = userCsr - const validationErrors = await validate(userData) - if (validationErrors.length > 0) { - throw new Error(`Validation errors: ${validationErrors}`) - } - const userCert = await createUserCert( - permsData.certificate, - permsData.privKey, - userCsr, - new Date(), - new Date(2030, 1, 1) - ) - return userCert.userCertString -} - -const certificateByUsername = (username: string, certificates: string[]): string | null => { - /** - * Check if given username is already in use - */ - for (const cert of certificates) { - const parsedCert = parseCertificate(cert) - const certUsername = getCertFieldValue(parsedCert, CertFieldsTypes.nickName) - if (certUsername?.localeCompare(username, undefined, { sensitivity: 'base' }) === 0) { - return cert - } - } - return null + cert: string | null + error: any } export interface RegistrationResponse { @@ -89,194 +27,59 @@ export interface RegistrationResponse { data: ErrorPayload | SuccessfullRegistrarionResponse } -export const sendCertificateRegistrationRequest = async ( - serviceAddress: string, - userCsr: string, - communityId: string, - requestTimeout = 120000, - socksProxyAgent: Agent -): Promise => { - const controller = new AbortController() - const timeout = setTimeout(() => { - controller.abort() - }, requestTimeout) - - let options = { - method: 'POST', - body: JSON.stringify({ data: userCsr }), - headers: { 'Content-Type': 'application/json' }, - signal: controller.signal, - } - - options = Object.assign( - { - agent: socksProxyAgent, - }, - options - ) - - let response: Response | null = null +export const extractPendingCsrs = async (payload: { csrs: string[]; certificates: string[] }) => { + const certNames = new Set() + const pendingNames = new Set() + const parsedUniqueCsrs = new Map() + const pendingCsrs: string[] = [] - try { - const start = new Date() - response = await fetch(`${serviceAddress}/register`, options) - const end = new Date() - const fetchTime = (end.getTime() - start.getTime()) / 1000 - logger(`Fetched ${serviceAddress}, time: ${fetchTime}`) - } catch (e) { - logger.error(e) - return { - eventType: RegistrationEvents.ERROR, - data: { - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.NOT_FOUND, - message: ErrorMessages.REGISTRAR_NOT_FOUND, - community: communityId, - }, + payload.certificates.forEach(cert => { + const parsedCert = parseCertificate(cert) + const username = getCertFieldValue(parsedCert, CertFieldsTypes.nickName) + if (username) { + certNames.add(username) } - } finally { - clearTimeout(timeout) - } + }) - switch (response?.status) { - case 200: - break - case 400: - return { - eventType: RegistrationEvents.ERROR, - data: { - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.BAD_REQUEST, - message: ErrorMessages.INVALID_USERNAME, - community: communityId, - }, - } - case 403: - return { - eventType: RegistrationEvents.ERROR, - data: { - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.FORBIDDEN, - message: ErrorMessages.USERNAME_TAKEN, - community: communityId, - }, - } - case 404: - return { - eventType: RegistrationEvents.ERROR, - data: { - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.NOT_FOUND, - message: ErrorMessages.REGISTRAR_NOT_FOUND, - community: communityId, - }, - } - default: - logger.error(`Registrar responded with ${response?.status} "${response?.statusText}" (${communityId})`) - return { - eventType: RegistrationEvents.ERROR, - data: { - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.SERVER_ERROR, - message: ErrorMessages.REGISTRATION_FAILED, - community: communityId, - }, - } + for (const csr of payload.csrs.reverse()) { + const parsedCsr = await loadCSR(csr) + const pubKey = keyFromCertificate(parsedCsr) + if (!parsedUniqueCsrs.has(pubKey)) { + parsedUniqueCsrs.set(pubKey, csr) + } } - const registrarResponse: UserCertificatePayload = await response.json() + const uniqueCsrsArray = Array.from(parsedUniqueCsrs.values()).reverse() - logger(`Sending user certificate (${communityId})`) - return { - eventType: SocketActionTypes.SEND_USER_CERTIFICATE, - data: { - communityId: communityId, - payload: registrarResponse, - }, + for (const csr of uniqueCsrsArray) { + const parsedCsr = await loadCSR(csr) + const username = getReqFieldValue(parsedCsr, CertFieldsTypes.nickName) + if (username && !certNames.has(username) && !pendingNames.has(username)) { + pendingNames.add(username) + pendingCsrs.push(csr) + } } + return pendingCsrs } -export const registerUser = async ( - csr: string, - permsData: PermsData, - certificates: string[], - ownerCertificate: string -): Promise => { - let cert: string +export const validateCsr = async (csr: string) => { const userData = new UserCsrData() userData.csr = csr const validationErrors = await validate(userData) - if (validationErrors.length > 0) { - logger.error(`Received data is not valid: ${validationErrors.toString()}`) - return { - status: 400, - body: JSON.stringify(validationErrors), - } - } + return validationErrors +} - const parsedCsr = await loadCSR(userData.csr) - const username = getReqFieldValue(parsedCsr, CertFieldsTypes.nickName) - if (!username) { - logger.error(`Could not parse certificate for field type ${CertFieldsTypes.nickName}`) +/** + * This function should only be called with pending CSRs (by calling extractPendingCsrs first which prevents signing CSRs for duplicate usernames). + */ +export const issueCertificate = async (userCsr: string, permsData: PermsData): Promise => { + const validationErrors = await validateCsr(userCsr) + if (validationErrors.length > 0) { return { - // Should be internal server error code 500 - status: 400, - body: null, - } - } - // Use map here - const usernameCert = certificateByUsername(username, certificates) - if (usernameCert) { - if (!pubKeyMatch(usernameCert, parsedCsr)) { - logger(`Username ${username} is taken`) - return { - // Should be conflict code 409 - status: 403, - body: null, - } - } else { - logger('Requesting same CSR again') - cert = usernameCert - } - } else { - logger('username doesnt have existing cert, creating new') - try { - cert = await registerCertificate(userData.csr, permsData) - } catch (e) { - logger.error(`Something went wrong with registering user: ${e.message as string}`) - return { - // Should be internal server error code 500 - status: 400, - body: null, - } + cert: null, + error: [validationErrors], } } - - const allUsers: UserData[] = [] - for (const cert of certificates) { - const parsedCert = parseCertificate(cert) - const onionAddress = getCertFieldValue(parsedCert, CertFieldsTypes.commonName) - const peerId = getCertFieldValue(parsedCert, CertFieldsTypes.peerId) - const username = getCertFieldValue(parsedCert, CertFieldsTypes.nickName) - const dmPublicKey = getCertFieldValue(parsedCert, CertFieldsTypes.dmPublicKey) - if (!onionAddress || !peerId || !username || !dmPublicKey) continue - allUsers.push({ onionAddress, peerId, username, dmPublicKey }) - } - - const peerList = await getUsersAddresses(allUsers) - - return { - status: 200, - body: { - certificate: cert, - peers: peerList, - rootCa: permsData.certificate, - ownerCert: ownerCertificate, - }, - } -} - -export const registerCertificate = async (userCsr: string, permsData: PermsData): Promise => { const userCert = await createUserCert( permsData.certificate, permsData.privKey, @@ -284,5 +87,8 @@ export const registerCertificate = async (userCsr: string, permsData: PermsData) new Date(), new Date(2030, 1, 1) ) - return userCert.userCertString + return { + cert: userCert.userCertString, + error: null, + } } diff --git a/packages/backend/src/nest/registration/registration.service.spec.ts b/packages/backend/src/nest/registration/registration.service.spec.ts index 38719e3ec0..6355013592 100644 --- a/packages/backend/src/nest/registration/registration.service.spec.ts +++ b/packages/backend/src/nest/registration/registration.service.spec.ts @@ -2,29 +2,14 @@ import { Test, TestingModule } from '@nestjs/testing' import { TestModule } from '../common/test.module' import { RegistrationModule } from './registration.module' import { RegistrationService } from './registration.service' -import { - configCrypto, - createRootCA, - createUserCert, - createUserCsr, - type RootCA, - verifyUserCert, - type UserCsr, -} from '@quiet/identity' +import { configCrypto, createRootCA, createUserCsr, type RootCA, verifyUserCert, type UserCsr } from '@quiet/identity' import { type DirResult } from 'tmp' -import { ErrorCodes, ErrorMessages, type PermsData, SocketActionTypes } from '@quiet/types' +import { type PermsData } from '@quiet/types' import { Time } from 'pkijs' -import { registerOwner, registerUser, sendCertificateRegistrationRequest } from './registration.functions' -import createHttpsProxyAgent from 'https-proxy-agent' -import { RegistrationEvents } from './registration.types' +import { issueCertificate, extractPendingCsrs } from './registration.functions' import { jest } from '@jest/globals' import { createTmpDir } from '../common/utils' -// @ts-ignore -const { Response } = jest.requireActual('node-fetch') - -jest.mock('node-fetch', () => jest.fn()) - describe('RegistrationService', () => { let module: TestingModule let registrationService: RegistrationService @@ -34,7 +19,6 @@ describe('RegistrationService', () => { let permsData: PermsData let userCsr: UserCsr let invalidUserCsr: any - let fetch: any beforeEach(async () => { module = await Test.createTestingModule({ @@ -60,7 +44,6 @@ describe('RegistrationService', () => { hashAlg: configCrypto.hashAlg, }) invalidUserCsr = 'invalidUserCsr' - fetch = await import('node-fetch') }) afterEach(async () => { @@ -68,104 +51,99 @@ describe('RegistrationService', () => { await module.close() }) - it('registerOwner should return certificate if csr is valid', async () => { - const result = await registerOwner(userCsr.userCsr, permsData) - expect(result).toBeTruthy() + it('registerUser should return cert if csr is valid and cert should pass the verification', async () => { + const responseData = await issueCertificate(userCsr.userCsr, permsData) + expect(responseData.cert).toBeTruthy() + if (!responseData.cert) return null + const isProperUserCert = await verifyUserCert(certRoot.rootCertString, responseData.cert) + expect(isProperUserCert.result).toBe(true) }) - it('registerOwner should throw error if csr is invalid', async () => { - await expect(registerOwner(invalidUserCsr, permsData)).rejects.toThrow() + it('registrar should return errors array if csr is not valid and should not return any cert', async () => { + const responseData = await issueCertificate(invalidUserCsr, permsData) + expect(responseData.cert).toBeFalsy() + expect(responseData.error.length).toBeTruthy() }) - it('registerUser should return 200 status code', async () => { - const responseData = await registerUser(userCsr.userCsr, permsData, [], 'ownerCert') - const isProperUserCert = await verifyUserCert(certRoot.rootCertString, responseData.body.certificate) - expect(isProperUserCert.result).toBe(true) + it('extractPendingCsrs should return all csrs if there are no certificates and csrs do not contain duplicate usernames', async () => { + const certificates: string[] = [] + const csrs: string[] = [userCsr.userCsr] + const payload: { certificates: string[]; csrs: string[] } = { + certificates: certificates, + csrs: csrs, + } + const pendingCsrs = await extractPendingCsrs(payload) + expect(pendingCsrs).toEqual(csrs) }) - it('returns existing certificate if username is taken but csr and cert public keys match', async () => { - const user = await createUserCsr({ - nickname: 'userName', + it('extractPendingCsrs should return all csrs if there are certificates, and csrs do not contain any name that is in certificates already', async () => { + const aliceCsr = await createUserCsr({ + nickname: 'alice', commonName: 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', peerId: 'Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', - dmPublicKey: 'testdmPublicKey1', + dmPublicKey: 'testdmPublicKey', signAlg: configCrypto.signAlg, hashAlg: configCrypto.hashAlg, }) - const userCert = await createUserCert( - certRoot.rootCertString, - certRoot.rootKeyString, - user.userCsr, - new Date(), - new Date(2030, 1, 1) - ) - const responseData = await registerUser(user.userCsr, permsData, [userCert.userCertString], 'ownerCert') - expect(responseData.status).toEqual(200) - const isProperUserCert = await verifyUserCert(certRoot.rootCertString, responseData.body.certificate) - expect(isProperUserCert.result).toBe(true) - expect(responseData.body.peers.length).toBe(1) - expect(responseData.body.rootCa).toBe(certRoot.rootCertString) + const aliceCert = await issueCertificate(aliceCsr.userCsr, permsData) + if (!aliceCert.cert) return + const certificates: string[] = [aliceCert.cert] + const csrs: string[] = [userCsr.userCsr] + const payload: { certificates: string[]; csrs: string[] } = { + certificates: certificates, + csrs: csrs, + } + const pendingCsrs = await extractPendingCsrs(payload) + expect(pendingCsrs).toEqual(csrs) }) - it('returns 403 if username already exists and csr and cert public keys dont match', async () => { - const user = await createUserCsr({ - nickname: 'userName', + it('extractPendingCsrs should return filtered csrs, excluding those that tries to claim username already present in certificate', async () => { + const userCert = await issueCertificate(userCsr.userCsr, permsData) + if (!userCert.cert) return + const certificates: string[] = [userCert.cert] + const csrs: string[] = [userCsr.userCsr] + const payload: { certificates: string[]; csrs: string[] } = { + certificates: certificates, + csrs: csrs, + } + const pendingCsrs = await extractPendingCsrs(payload) + expect(pendingCsrs.length).toEqual(0) + }) + + it('extractPendingCsrs should return all csrs if there are no duplicates in requested usernames', async () => { + const userCsr2 = await createUserCsr({ + nickname: 'userName2', commonName: 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', peerId: 'Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', - dmPublicKey: 'testdmPublicKey1', + dmPublicKey: 'testdmPublicKey', signAlg: configCrypto.signAlg, hashAlg: configCrypto.hashAlg, }) - const userCert = await createUserCert( - certRoot.rootCertString, - certRoot.rootKeyString, - user.userCsr, - new Date(), - new Date(2030, 1, 1) - ) - const userNew = await createUserCsr({ - nickname: 'username', - commonName: 'abcd.onion', - peerId: 'QmS9vJkgbea9EgzHvVPqhj1u4tH7YKq7eteDN7gnG5zUmc', - dmPublicKey: 'testdmPublicKey2', + const csrs: string[] = [userCsr.userCsr, userCsr2.userCsr] + const pendingCsrs = await extractPendingCsrs({ certificates: [], csrs: csrs }) + expect(pendingCsrs.length).toEqual(csrs.length) + }) + + it('Extract pending csrs should return only csrs that have unique usernames', async () => { + const userCsr = await createUserCsr({ + nickname: 'karol', + commonName: 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', + peerId: 'Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', + dmPublicKey: 'testdmPublicKey', signAlg: configCrypto.signAlg, hashAlg: configCrypto.hashAlg, }) - const response = await registerUser(userNew.userCsr, permsData, [userCert.userCertString], 'ownerCert') - expect(response.status).toEqual(403) - }) - - it('returns 400 if no csr in data or csr has wrong format', async () => { - for (const invalidCsr of ['', 'abcd']) { - const response = await registerUser(invalidCsr, permsData, [], 'ownerCert') - expect(response.status).toEqual(400) - } - }) - - it('returns 400 if csr is lacking a field', async () => { - const csr = - 'MIIBFTCBvAIBADAqMSgwFgYKKwYBBAGDjBsCARMIdGVzdE5hbWUwDgYDVQQDEwdaYmF5IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGPGHpJzE/CvL7l/OmTSfYQrhhnWQrYw3GgWB1raCTSeFI/MDVztkBOlxwdUWSm10+1OtKVUWeMKaMtyIYFcPPqAwMC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0OBBYEFLjaEh+cnNhsi5qDsiMB/ZTzZFfqMAoGCCqGSM49BAMCA0gAMEUCIFwlob/Igab05EozU0e/lsG7c9BxEy4M4c4Jzru2vasGAiEAqFTQuQr/mVqTHO5vybWm/iNDk8vh88K6aBCCGYqIfdw=' - const response = await registerUser(csr, permsData, [], 'ownerCert') - expect(response.status).toEqual(400) - }) - - it('returns 404 if fetching registrar address throws error', async () => { - console.log(fetch) - fetch.default.mockRejectedValue('User aborted request') - const communityId = 'communityID' - const response = await sendCertificateRegistrationRequest( - 'QmS9vJkgbea9EgzHvVPqhj1u4tH7YKq7eteDN7gnG5zUmc', - userCsr.userCsr, - communityId, - 1000, - createHttpsProxyAgent({ port: '12311', host: 'localhost' }) - ) - expect(response.eventType).toBe(RegistrationEvents.ERROR) - expect(response.data).toEqual({ - type: SocketActionTypes.REGISTRAR, - code: ErrorCodes.NOT_FOUND, - message: ErrorMessages.REGISTRAR_NOT_FOUND, - community: communityId, + const userCsr2 = await createUserCsr({ + nickname: 'karol', + commonName: 'nnnnnnc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', + peerId: 'QmffffffqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', + dmPublicKey: 'testdmPublicKey', + signAlg: configCrypto.signAlg, + hashAlg: configCrypto.hashAlg, }) + const csrs: string[] = [userCsr.userCsr, userCsr2.userCsr] + const pendingCsrs = await extractPendingCsrs({ certificates: [], csrs: csrs }) + expect(pendingCsrs.length).toEqual(1) + expect(pendingCsrs[0]).toBe(userCsr.userCsr) }) }) diff --git a/packages/backend/src/nest/registration/registration.service.ts b/packages/backend/src/nest/registration/registration.service.ts index 2640e14cea..c788d1cb7c 100644 --- a/packages/backend/src/nest/registration/registration.service.ts +++ b/packages/backend/src/nest/registration/registration.service.ts @@ -1,110 +1,39 @@ -import { Inject, Injectable, OnModuleInit } from '@nestjs/common' -import express from 'express' -import getPort from 'get-port' -import { Agent, Server } from 'http' +import { Injectable, OnModuleInit } from '@nestjs/common' import { EventEmitter } from 'events' -import { - registerOwner, - registerUser, - RegistrarResponse, - RegistrationResponse, - sendCertificateRegistrationRequest, -} from './registration.functions' -import { - ConnectionProcessInfo, - ErrorCodes, - ErrorMessages, - LaunchRegistrarPayload, - PermsData, - RegisterOwnerCertificatePayload, - SocketActionTypes, -} from '@quiet/types' -import { EXPRESS_PROVIDER } from '../const' +import { extractPendingCsrs, issueCertificate } from './registration.functions' +import { ErrorCodes, ErrorMessages, PermsData, RegisterOwnerCertificatePayload, SocketActionTypes } from '@quiet/types' import { RegistrationEvents } from './registration.types' -import { ServiceState } from '../connections-manager/connections-manager.types' import Logger from '../common/logger' @Injectable() export class RegistrationService extends EventEmitter implements OnModuleInit { private readonly logger = Logger(RegistrationService.name) - public onionAddress: string - private _server: Server - private _port: number - public registrationService: any public certificates: string[] = [] private _permsData: PermsData - private _ownerCertificate: string - constructor(@Inject(EXPRESS_PROVIDER) public readonly _app: express.Application) { + constructor() { super() } onModuleInit() { - this.on(RegistrationEvents.SET_CERTIFICATES, certs => { - this.setCertificates(certs) - }) - this.on(RegistrationEvents.REGISTER_USER_CERTIFICATE, async (csr: string) => { - if (!this._permsData) { - console.log('NO PERMS DATA') - return - } - await this.registerUser(csr) - }) - // eslint-disable-next-line - const self = this - this.setRouting(self) - } - - public setCertificates(certs: string[]) { - this.certificates = certs - } - - private pendingPromise: Promise | null = null - - private setRouting(self: any) { - // @ts-ignore - const middleware = function (req, res, next) { - const host = req.headers['host'] - if (host !== self.onionAddress) { - return res.status(403).send('Access denied') + this.on( + RegistrationEvents.REGISTER_USER_CERTIFICATE, + async (payload: { csrs: string[]; certificates: string[] }) => { + // Lack of permsData means that we are not the owner of the community in the official model of the app, however anyone can modify the source code, put malicious permsData here, issue false certificates and try to trick other users. + await this.issueCertificates(payload) } - next() - } - - this._app.use(middleware) - this._app.use(express.json()) - this._app.post('/register', async (req, res): Promise => { - if (this.pendingPromise) return - this.pendingPromise = this.registerUser(req.body.data) - const result = await this.pendingPromise - if (result) { - res.status(result.status).send(result.body) - } - this.pendingPromise = null - }) - } - - public async listen(): Promise { - return await new Promise(resolve => { - this._server = this._app.listen(this._port, () => { - this.logger(`Certificate registration service listening on port: ${this._port}`) - resolve() - }) - }) + ) } - public async stop(): Promise { - return await new Promise(resolve => { - if (!this._server) resolve() - this._server.close(() => { - this.logger('Certificate registration service closed') - resolve() - }) + private async issueCertificates(payload: { csrs: string[]; certificates: string[] }) { + if (!this._permsData) return + const pendingCsrs = await extractPendingCsrs(payload) + pendingCsrs.forEach(async csr => { + await this.registerUserCertificate(csr) }) } public set permsData(perms: PermsData) { - console.log('Setting owner perms data') this._permsData = { certificate: perms.certificate, privKey: perms.privKey, @@ -112,79 +41,28 @@ export class RegistrationService extends EventEmitter implements OnModuleInit { } public async registerOwnerCertificate(payload: RegisterOwnerCertificatePayload): Promise { - let cert: string - try { - cert = await registerOwner(payload.userCsr.userCsr, payload.permsData) - } catch (e) { - this.logger.error(`Registering owner failed: ${e.message}`) + // FIXME: We should resolve problems with events order and we should set permsData only on LAUNCH_REGISTRART socket event in connectionsManager. + this._permsData = payload.permsData + const result = await issueCertificate(payload.userCsr.userCsr, this._permsData) + if (result?.cert) { + this.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, { + communityId: payload.communityId, + network: { certificate: result.cert }, + }) + } else { this.emit(SocketActionTypes.ERROR, { type: SocketActionTypes.REGISTRAR, code: ErrorCodes.SERVER_ERROR, message: ErrorMessages.REGISTRATION_FAILED, community: payload.communityId, }) - return - } - this.emit(SocketActionTypes.SAVED_OWNER_CERTIFICATE, { - communityId: payload.communityId, - network: { certificate: cert, peers: [] }, - }) - this._ownerCertificate = cert - } - - public async sendCertificateRegistrationRequest( - serviceAddress: string, - userCsr: string, - communityId: string, - requestTimeout = 120000, - socksProxyAgent: Agent - ): Promise { - const response: RegistrationResponse = await sendCertificateRegistrationRequest( - serviceAddress, - userCsr, - communityId, - requestTimeout, - socksProxyAgent - ) - this.emit(SocketActionTypes.CONNECTION_PROCESS_INFO, ConnectionProcessInfo.CONNECTING_TO_COMMUNITY) - this.emit(response.eventType, response.data) - } - - public async registerUser(csr: string): Promise<{ status: number; body: any }> { - const result = await registerUser(csr, this._permsData, this.certificates, this._ownerCertificate) - if (result?.status === 200) { - this.emit(RegistrationEvents.NEW_USER, { certificate: result.body.certificate, rootPermsData: this._permsData }) } - return result } - public async launchRegistrar(payload: LaunchRegistrarPayload): Promise { - this.emit(RegistrationEvents.REGISTRAR_STATE, ServiceState.LAUNCHING) - this._permsData = { - certificate: payload.rootCertString, - privKey: payload.rootKeyString, - } - this.logger(`Initializing registration service for peer ${payload.peerId}...`) - try { - await this.init(payload.privateKey) - } catch (err) { - this.logger.error(`Couldn't initialize certificate registration service: ${err as string}`) - return + public async registerUserCertificate(csr: string): Promise { + const result = await issueCertificate(csr, this._permsData) + if (result?.cert) { + this.emit(RegistrationEvents.NEW_USER, { certificate: result.cert }) } - try { - await this.listen() - } catch (err) { - this.logger.error(`Certificate registration service couldn't start listening: ${err as string}`) - } - this.emit(RegistrationEvents.REGISTRAR_STATE, ServiceState.LAUNCHED) - } - - public async init(privKey: string): Promise { - this._port = await getPort() - this.emit(RegistrationEvents.SPAWN_HS_FOR_REGISTRAR, { - port: this._port, - privateKey: privKey, - targetPort: 80, - }) } } diff --git a/packages/backend/src/nest/registration/registration.types.ts b/packages/backend/src/nest/registration/registration.types.ts index dcffe9d7f9..02da49c0d6 100644 --- a/packages/backend/src/nest/registration/registration.types.ts +++ b/packages/backend/src/nest/registration/registration.types.ts @@ -1,8 +1,5 @@ export enum RegistrationEvents { ERROR = 'error', - SPAWN_HS_FOR_REGISTRAR = 'spawnHsForRegistrar', NEW_USER = 'newUser', - SET_CERTIFICATES = 'setCertificates', - REGISTRAR_STATE = 'registrarState', REGISTER_USER_CERTIFICATE = 'registerUserCertificate', } diff --git a/packages/backend/src/nest/socket/socket.service.ts b/packages/backend/src/nest/socket/socket.service.ts index 073636a08b..5d687fe2a2 100644 --- a/packages/backend/src/nest/socket/socket.service.ts +++ b/packages/backend/src/nest/socket/socket.service.ts @@ -174,9 +174,6 @@ export class SocketService extends EventEmitter implements OnModuleInit { ownerCertificate: payload.certificate, rootCa: payload.permsData.certificate, } - - console.log('Metadata from state-manager', communityMetadataPayload) - this.emit(SocketActionTypes.SEND_COMMUNITY_METADATA, communityMetadataPayload) }) diff --git a/packages/backend/src/nest/storage/storage.service.spec.ts b/packages/backend/src/nest/storage/storage.service.spec.ts index 9012cf0785..a4e0fb0ada 100644 --- a/packages/backend/src/nest/storage/storage.service.spec.ts +++ b/packages/backend/src/nest/storage/storage.service.spec.ts @@ -295,26 +295,6 @@ describe('StorageService', () => { expect(result).toBe(true) }) - it('is not saved to db if did not pass verification', async () => { - const oldUserCertificate = await createUserCert( - rootPermsData.certificate, - rootPermsData.privKey, - // @ts-expect-error userCsr can be undefined - alice.userCsr?.userCsr, - new Date(2021, 1, 1), - new Date(2021, 1, 2) - ) - - await storageService.init(peerId) - - const result = await storageService.saveCertificate({ - certificate: oldUserCertificate.userCertString, - rootPermsData, - }) - - expect(result).toBe(false) - }) - it('is not saved to db if empty', async () => { await storageService.init(peerId) diff --git a/packages/backend/src/nest/storage/storage.service.ts b/packages/backend/src/nest/storage/storage.service.ts index dbe0a8622b..62f1d6ba88 100644 --- a/packages/backend/src/nest/storage/storage.service.ts +++ b/packages/backend/src/nest/storage/storage.service.ts @@ -397,36 +397,18 @@ export class StorageService extends EventEmitter { write: ['*'], }, }) - this.certificatesRequests.events.on('replicate.progress', async (_address, _hash, entry, _progress, _total) => { - const csr: string = entry.payload.value - this.logger('Replicated csr') - let parsedCSR: CertificationRequest - try { - parsedCSR = parseCertificationRequest(csr) - } catch (e) { - this.logger.error(`csrs replicate.progress: could not parse certificate request`) - return - } - - const username = getReqFieldValue(parsedCSR, CertFieldsTypes.nickName) - if (!username) { - this.logger.error( - `csrs replicate.progress: could not parse certificate request for field type ${CertFieldsTypes.nickName}` - ) - return - } - this.emit(StorageEvents.REPLICATED_CSR, [csr]) - }) this.certificatesRequests.events.on('replicated', async () => { this.logger('REPLICATED: CSRs') const allCsrs = this.getAllEventLogEntries(this.certificatesRequests) - this.emit(StorageEvents.REPLICATED_CSR, allCsrs) + const allCertificates = this.getAllEventLogEntries(this.certificates) + this.emit(StorageEvents.REPLICATED_CSR, { csrs: allCsrs, certificates: allCertificates }) await this.updatePeersList() }) this.certificatesRequests.events.on('write', async (_address, entry) => { const csr: string = entry.payload.value this.logger('Saved CSR locally') - this.emit(StorageEvents.REPLICATED_CSR, [csr]) + const allCertificates = this.getAllEventLogEntries(this.certificates) + this.emit(StorageEvents.REPLICATED_CSR, { csrs: [csr], certificates: allCertificates }) await this.updatePeersList() }) @@ -849,12 +831,6 @@ export class StorageService extends EventEmitter { this.logger('Certificate is either null or undefined, not saving to db') return false } - const verification = await verifyUserCert(payload.rootPermsData.certificate, payload.certificate) - if (verification.resultCode !== 0) { - this.logger.error('Certificate is not valid') - this.logger.error(verification.resultMessage) - return false - } this.logger('Saving certificate...') await this.certificates.add(payload.certificate) return true diff --git a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts index 1ffde5daa4..f8fc150f63 100644 --- a/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts +++ b/packages/backend/src/nest/websocketOverTor/websocketOverTor.tor.spec.ts @@ -118,7 +118,8 @@ describe('websocketOverTor', () => { await listener?.close() }) - it.each([ + // Those are randomly failing and we do not use wss atm anyway. + it.skip.each([ ['string', String], ['array', Array], ])('connects successfully with CA passed as %s', async (_name: string, caType: (ca: string) => any) => { diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md index 927083dec1..dddc4388af 100644 --- a/packages/common/CHANGELOG.md +++ b/packages/common/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.1-alpha.2](https://github.com/TryQuiet/quiet/compare/@quiet/common@2.0.1-alpha.1...@quiet/common@2.0.1-alpha.2) (2023-10-09) + +**Note:** Version bump only for package @quiet/common + + + + + +## [2.0.1-alpha.1](https://github.com/ZbayApp/monorepo/compare/@quiet/common@2.0.1-alpha.0...@quiet/common@2.0.1-alpha.1) (2023-09-25) + +**Note:** Version bump only for package @quiet/common + + + + + +## [2.0.1-alpha.0](https://github.com/ZbayApp/monorepo/compare/@quiet/common@2.0.0-alpha.3...@quiet/common@2.0.1-alpha.0) (2023-09-25) + +**Note:** Version bump only for package @quiet/common + + + + + # [2.0.0-alpha.18](https://github.com/ZbayApp/monorepo/compare/@quiet/common@2.0.0-alpha.3...@quiet/common@2.0.0-alpha.18) (2023-10-04) **Note:** Version bump only for package @quiet/common diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json index 998dc70725..1c7d1069b5 100644 --- a/packages/common/package-lock.json +++ b/packages/common/package-lock.json @@ -1,12 +1,12 @@ { "name": "@quiet/common", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@quiet/common", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "license": "ISC", "dependencies": { "cross-env": "^5.2.0", diff --git a/packages/common/package.json b/packages/common/package.json index 309fa44c15..ac7b81004b 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@quiet/common", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "description": "Common monorepo utils", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -18,7 +18,7 @@ "rmDist": "rimraf lib/" }, "devDependencies": { - "@quiet/eslint-config": "^2.0.0-alpha.18", + "@quiet/eslint-config": "^2.0.1-alpha.2", "@types/jest": "^26.0.23", "@types/node": "^17.0.21", "jest": "^26.6.3", @@ -26,7 +26,7 @@ "typescript": "^4.9.3" }, "dependencies": { - "@quiet/types": "^2.0.0-alpha.18", + "@quiet/types": "^2.0.1-alpha.2", "cross-env": "^5.2.0", "debug": "^4.3.1" }, diff --git a/packages/desktop/CHANGELOG.md b/packages/desktop/CHANGELOG.md index c63622b9fe..9df9924507 100644 --- a/packages/desktop/CHANGELOG.md +++ b/packages/desktop/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -# 2.0.0-alpha.18 (2023-10-04) +## 2.0.1-alpha.2 (2023-10-09) ### Bug Fixes @@ -19,6 +19,38 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline +## [2.0.1-alpha.1](https://github.com/ZbayApp/monorepo/compare/quiet@2.0.1-alpha.0...quiet@2.0.1-alpha.1) (2023-09-25) + +**Note:** Version bump only for package quiet + + + + + +## [2.0.1-alpha.0](https://github.com/ZbayApp/monorepo/compare/quiet@2.0.0-alpha.12...quiet@2.0.1-alpha.0) (2023-09-25) + +**Note:** Version bump only for package quiet + + + + + +# [2.0.0-alpha.12](https://github.com/TryQuiet/quiet/compare/quiet@2.0.0-alpha.11...quiet@2.0.0-alpha.12) (2023-09-20) + +**Note:** Version bump only for package quiet + + + + + +# [2.0.0-alpha.11](https://github.com/TryQuiet/quiet/compare/quiet@2.0.0-alpha.10...quiet@2.0.0-alpha.11) (2023-09-19) + +**Note:** Version bump only for package quiet + + + + + # [2.0.0-alpha.10](https://github.com/TryQuiet/quiet/compare/quiet@2.0.0-alpha.9...quiet@2.0.0-alpha.10) (2023-09-19) **Note:** Version bump only for package quiet diff --git a/packages/desktop/README.md b/packages/desktop/README.md index c58c4b3d5c..ca80365377 100644 --- a/packages/desktop/README.md +++ b/packages/desktop/README.md @@ -20,6 +20,20 @@ npm run start ``` ---- +## Running dev desktop on Windows + +Bootstrap scripts has been adjusted to work on Windows (powershell or cmd) hovewer there still may be a problem with patching. +Getting error: + +``` +webpack://@quiet/backend/./node_modules/electron/index.js?:9 + throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again') +``` + +while running desktop may mean that applying patch in packages/backend (`npm run applyPatches`) did not work correctly. +If that's the case file must be patched manually according to `electron-fetch-git.patch` and backend must be rebuilt by running `npm run webpack` in packages/backend. + + ## Versioning packages Before trying to release a new version, make sure you have `GH_TOKEN` env set. diff --git a/packages/desktop/package-lock.json b/packages/desktop/package-lock.json index f4445149aa..12370c6f59 100644 --- a/packages/desktop/package-lock.json +++ b/packages/desktop/package-lock.json @@ -1,12 +1,12 @@ { "name": "@quiet/desktop", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@quiet/desktop", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "license": "ISC", "dependencies": { "@electron/remote": "^2.0.8", @@ -134,6 +134,7 @@ "redux-saga-test-plan": "^4.0.3", "redux-thunk": "^2.3.0", "reselect": "^4.1.5", + "run-script-os": "1.1.6", "socket.io-mock": "^1.3.2", "source-map-loader": "^4.0.1", "standard": "^12.0.1", @@ -40258,6 +40259,16 @@ "aproba": "^1.1.1" } }, + "node_modules/run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==", + "dev": true, + "bin": { + "run-os": "index.js", + "run-script-os": "index.js" + } + }, "node_modules/rxjs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", @@ -76824,6 +76835,12 @@ "aproba": "^1.1.1" } }, + "run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==", + "dev": true + }, "rxjs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index ef1982c0ac..57d050383c 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -80,7 +80,7 @@ }, "homepage": "https://github.com/TryQuiet", "@comment version": "To build new version for specific platform, just replace platform in version tag to one of following linux, mac, windows", - "version": "2.0.0-alpha.18", + "version": "2.0.1-alpha.2", "description": "Decentralized team chat", "main": "dist/main/main.js", "scripts": { @@ -120,16 +120,18 @@ "rmDist": "rimraf dist/", "setMainEnvs": "node scripts/setMainEnvs.js", "copyMainEnvs": "cp mainEnvs.json dist/main", - "copyFonts": "cp src/renderer/fonts/* dist/main" + "copyFonts": "run-script-os", + "copyFonts:windows": "xcopy src\\renderer\\fonts\\* dist\\main /Y", + "copyFonts:default": "cp src/renderer/fonts/* dist/main" }, "dependencies": { "@electron/remote": "^2.0.8", "@peculiar/webcrypto": "1.4.3", - "@quiet/common": "^2.0.0-alpha.18", - "@quiet/logger": "^2.0.0-alpha.18", - "@quiet/types": "^2.0.0-alpha.18", + "@quiet/common": "^2.0.1-alpha.2", + "@quiet/logger": "^2.0.1-alpha.2", + "@quiet/types": "^2.0.1-alpha.2", "@sentry/electron": "^2.5.4", - "backend-bundle": "^2.0.0-alpha.18", + "backend-bundle": "^2.0.1-alpha.2", "electron-debug": "^3.0.1", "electron-localshortcut": "^3.2.1", "electron-store": "^8.0.1", @@ -155,9 +157,9 @@ "@mui/icons-material": "^5.10.15", "@mui/lab": "^5.0.0-alpha.109", "@mui/material": "~5.10.15", - "@quiet/eslint-config": "^2.0.0-alpha.18", - "@quiet/identity": "^2.0.0-alpha.18", - "@quiet/state-manager": "^2.0.0-alpha.18", + "@quiet/eslint-config": "^2.0.1-alpha.2", + "@quiet/identity": "^2.0.1-alpha.2", + "@quiet/state-manager": "^2.0.1-alpha.2", "@redux-saga/types": "^1.1.0", "@reduxjs/toolkit": "^1.9.1", "@sentry/browser": "^6.19.7", @@ -256,6 +258,7 @@ "redux-saga-test-plan": "^4.0.3", "redux-thunk": "^2.3.0", "reselect": "^4.1.5", + "run-script-os": "1.1.6", "socket.io-mock": "^1.3.2", "source-map-loader": "^4.0.1", "standard": "^12.0.1", diff --git a/packages/desktop/src/renderer/Root.tsx b/packages/desktop/src/renderer/Root.tsx index 8717893233..608060d374 100644 --- a/packages/desktop/src/renderer/Root.tsx +++ b/packages/desktop/src/renderer/Root.tsx @@ -31,7 +31,8 @@ import ChannelCreationModal from './components/ChannelCreationModal/ChannelCreat import { SaveStateComponent } from './components/SaveState/SaveStateComponent' import UnregisteredModalContainer from './components/widgets/userLabel/unregistered/UnregisteredModal.container' import DuplicateModalContainer from './components/widgets/userLabel/duplicate/DuplicateModal.container' -// Trigger lerna +import UsernameTakenModalContainer from './components/widgets/usernameTakenModal/UsernameTakenModal.container' +import PossibleImpersonationAttackModalContainer from './components/widgets/possibleImpersonationAttackModal/PossibleImpersonationAttackModal.container' export const persistor = persistStore(store) export default () => { @@ -48,7 +49,9 @@ export default () => { + + diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx index ead282576a..3ec4ac037f 100644 --- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx +++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx @@ -155,7 +155,7 @@ export const PerformCommunityActionComponent: React.FC { const [formSent, setFormSent] = useState(false) - const [communityName, setCommunityName] = useState('') + const [communityName, setCommunityName] = useState('...') const [parsedNameDiffers, setParsedNameDiffers] = useState(false) const waitingForResponse = formSent && !hasReceivedResponse diff --git a/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.test.tsx b/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.test.tsx index 0f8656a6c4..e5b406d690 100644 --- a/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.test.tsx +++ b/packages/desktop/src/renderer/components/CreateUsername/CreateUsername.test.tsx @@ -4,8 +4,10 @@ import userEvent from '@testing-library/user-event' import { screen, waitFor } from '@testing-library/dom' import { renderComponent } from '../../testUtils/renderComponent' -import CreateUsernameComponent from './CreateUsernameComponent' +import CreateUsernameComponent, { UsernameVariant } from './CreateUsernameComponent' import { FieldErrors, UsernameErrors } from '../../forms/fieldsErrors' +import { keyFromCertificate, parseCertificate } from '@quiet/identity' +import { UserData } from '@quiet/types' describe('Create username', () => { it.each([ @@ -48,3 +50,201 @@ describe('Create username', () => { expect(message).toBeVisible() }) }) + +describe('Username taken', () => { + const userCertData = { + username: 'userName', + onionAddress: 'nqnw4kc4c77fb47lk52m5l57h4tcxceo7ymxekfn7yh5m66t4jv2olad.onion', + peerId: 'Qmf3ySkYqLET9xtAtDzvAr5Pp3egK1H3C5iJAZm1SpLEp6', + dmPublicKey: '0bfb475810c0e26c9fab590d47c3d60ec533bb3c451596acc3cd4f21602e9ad9', + } + + const userCertString = + 'MIICaDCCAg6gAwIBAgIGAYBqyuV2MAoGCCqGSM49BAMCMBkxFzAVBgNVBAMTDnF1aWV0Y29tbXVuaXR5MB4XDTEwMTIyODEwMTAxMFoXDTMwMTIyODEwMTAxMFowSTFHMEUGA1UEAxM+bnFudzRrYzRjNzdmYjQ3bGs1Mm01bDU3aDR0Y3hjZW83eW14ZWtmbjd5aDVtNjZ0NGp2Mm9sYWQub25pb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQZBMmiVmRBRvw+QiL5DYg7WGFUVgA7u90KMpJg4qCaCJJNh7wH2tl0EDsN4FeGmR9AkvtCGd+5vYL0nGcX/oLdo4IBEDCCAQwwCQYDVR0TBAIwADALBgNVHQ8EBAMCAIAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMC8GCSqGSIb3DQEJDAQiBCAL+0dYEMDibJ+rWQ1Hw9YOxTO7PEUVlqzDzU8hYC6a2TAYBgorBgEEAYOMGwIBBAoTCHVzZXJOYW1lMD0GCSsGAQIBDwMBAQQwEy5RbWYzeVNrWXFMRVQ5eHRBdER6dkFyNVBwM2VnSzFIM0M1aUpBWm0xU3BMRXA2MEkGA1UdEQRCMECCPm5xbnc0a2M0Yzc3ZmI0N2xrNTJtNWw1N2g0dGN4Y2VvN3lteGVrZm43eWg1bTY2dDRqdjJvbGFkLm9uaW9uMAoGCCqGSM49BAMCA0gAMEUCIF63rnIq8vd86NT9RHSFj7borwwODqyfE7Pw64tGElpIAiEA5ZDSdrDd8OGf+kv7wxByM1Xgmc5m/aydUk+WorbO3Gg=' + const parsedCert = parseCertificate(userCertString) + const userPubKey = keyFromCertificate(parsedCert) + + const registeredUsers: Record = { + [userPubKey]: userCertData, + } + it('renders component ', () => { + const result = renderComponent( + {}} + open={true} + currentUsername={'jack'} + variant={UsernameVariant.TAKEN} + registeredUsers={registeredUsers} + registerUsername={() => {}} + /> + ) + expect(result.baseElement).toMatchInlineSnapshot(` + +