From 294945ccbb2fc74b2fe4bb671102528f23e76c8e Mon Sep 17 00:00:00 2001
From: Emi <emilia.marczyk@rumblefish.pl>
Date: Tue, 24 Oct 2023 14:31:39 +0200
Subject: [PATCH] feat: Check if psk in invitation link is base64 encoded #1897

---
 packages/backend/package-lock.json            | 22 +++++++-----
 packages/backend/package.json                 |  4 +--
 packages/backend/src/nest/common/utils.ts     |  8 +++--
 .../connections-manager.service.ts            | 29 ++++++++++------
 packages/common/package-lock.json             | 29 +++++++++++++++-
 packages/common/package.json                  |  4 ++-
 packages/common/src/invitationCode.test.ts    | 34 ++++++++++++-------
 packages/common/src/invitationCode.ts         | 15 ++++----
 .../PerformCommunityActionComponent.tsx       |  4 +--
 .../components/Settings/Settings.stories.tsx  |  4 +--
 .../Tabs/Invite/Invite.component.test.tsx     |  6 ++--
 .../Settings/Tabs/Invite/Invite.stories.tsx   |  4 +--
 .../Settings/Tabs/QRCode/QRCode.stories.tsx   |  4 +--
 .../invitationCode/invitationCode.test.ts     | 26 +++++++++-----
 14 files changed, 130 insertions(+), 63 deletions(-)

diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json
index e3231dcb13..f31eec94c5 100644
--- a/packages/backend/package-lock.json
+++ b/packages/backend/package-lock.json
@@ -56,7 +56,7 @@
 				"socks-proxy-agent": "^5.0.0",
 				"string-replace-loader": "3.1.0",
 				"ts-jest-resolver": "^2.0.0",
-				"validator": "^13.6.0"
+				"validator": "^13.11.0"
 			},
 			"devDependencies": {
 				"@nestjs/cli": "^10.0.0",
@@ -72,7 +72,7 @@
 				"@types/orbit-db": "git+https://github.com/orbitdb/orbit-db-types.git",
 				"@types/supertest": "^2.0.11",
 				"@types/tmp": "^0.2.3",
-				"@types/validator": "^13.1.4",
+				"@types/validator": "^13.11.5",
 				"@types/ws": "8.5.3",
 				"babel-jest": "^29.3.1",
 				"cross-env": "^5.2.0",
@@ -6580,8 +6580,9 @@
 			"license": "MIT"
 		},
 		"node_modules/@types/validator": {
-			"version": "13.1.4",
-			"license": "MIT"
+			"version": "13.11.5",
+			"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz",
+			"integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q=="
 		},
 		"node_modules/@types/ws": {
 			"version": "8.5.3",
@@ -21995,8 +21996,9 @@
 			}
 		},
 		"node_modules/validator": {
-			"version": "13.7.0",
-			"license": "MIT",
+			"version": "13.11.0",
+			"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
+			"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
 			"engines": {
 				"node": ">= 0.10"
 			}
@@ -26934,7 +26936,9 @@
 			"dev": true
 		},
 		"@types/validator": {
-			"version": "13.1.4"
+			"version": "13.11.5",
+			"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz",
+			"integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q=="
 		},
 		"@types/ws": {
 			"version": "8.5.3",
@@ -36673,7 +36677,9 @@
 			}
 		},
 		"validator": {
-			"version": "13.7.0"
+			"version": "13.11.0",
+			"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
+			"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ=="
 		},
 		"varint": {
 			"version": "6.0.0"
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 43ca6f284b..a1e58e0f34 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -65,7 +65,7 @@
 		"@types/orbit-db": "git+https://github.com/orbitdb/orbit-db-types.git",
 		"@types/supertest": "^2.0.11",
 		"@types/tmp": "^0.2.3",
-		"@types/validator": "^13.1.4",
+		"@types/validator": "^13.11.5",
 		"@types/ws": "8.5.3",
 		"babel-jest": "^29.3.1",
 		"cross-env": "^5.2.0",
@@ -134,7 +134,7 @@
 		"socks-proxy-agent": "^5.0.0",
 		"string-replace-loader": "3.1.0",
 		"ts-jest-resolver": "^2.0.0",
-		"validator": "^13.6.0"
+		"validator": "^13.11.0"
 	},
 	"overrides": {
 		"level": "$level",
diff --git a/packages/backend/src/nest/common/utils.ts b/packages/backend/src/nest/common/utils.ts
index 23d3735631..4d0de9701a 100644
--- a/packages/backend/src/nest/common/utils.ts
+++ b/packages/backend/src/nest/common/utils.ts
@@ -13,7 +13,6 @@ import logger from './logger'
 import { createCertificatesTestHelper } from './client-server'
 import { Libp2pNodeParams } from '../libp2p/libp2p.types'
 import { createLibp2pAddress, createLibp2pListenAddress } from '@quiet/common'
-import { randomBytes } from '@libp2p/crypto'
 import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
 import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
 
@@ -241,8 +240,11 @@ export async function createPeerId(): Promise<PeerId> {
 
 const KEY_LENGTH = 32
 
-export function generateKey(bytes: Uint8Array | NodeJS.WriteStream, key?: Uint8Array) {
-  const psk = key || randomBytes(KEY_LENGTH)
+export function generateLibp2pPSK(bytes: Uint8Array | NodeJS.WriteStream, key?: Uint8Array) {
+  /**
+   * Based on 'libp2p/pnet' generateKey
+   */
+  const psk = key || crypto.randomBytes(KEY_LENGTH)
   const base16StringKey = uint8ArrayToString(psk, 'base16')
   const fullKey = uint8ArrayFromString('/key/swarm/psk/1.0.0/\n/base16/\n' + base16StringKey)
 
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 486e32b573..8ab0b5988d 100644
--- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts
+++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts
@@ -8,7 +8,8 @@ import { setEngine, CryptoEngine } from 'pkijs'
 import { EventEmitter } from 'events'
 import getPort from 'get-port'
 import PeerId from 'peer-id'
-import { generateKey, removeFilesFromDir } from '../common/utils'
+import { generateLibp2pPSK, removeFilesFromDir } from '../common/utils'
+import validator from 'validator'
 import {
   AskForMessagesPayload,
   ChannelMessagesIdsResponse,
@@ -276,10 +277,18 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
       },
       network,
     }
-    const psk = community.psk // Passed in base64
+    const psk = community.psk
     if (psk) {
       console.log('createNetwork got psk', psk)
-      await this.localDbService.put(LocalDBKeys.PSK, psk) // Validate psk before saving?
+      if (!validator.isBase64(psk)) {
+        emitError(this.serverIoProvider.io, {
+          type: SocketActionTypes.NETWORK,
+          message: ErrorMessages.NETWORK_SETUP_FAILED,
+          community: community.id,
+        })
+        return
+      }
+      await this.localDbService.put(LocalDBKeys.PSK, psk)
     }
 
     this.serverIoProvider.io.emit(SocketActionTypes.NETWORK, payload)
@@ -287,11 +296,9 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
 
   private async generatePSK() {
     const libp2pPSK = new Uint8Array(95)
-    const psk = generateKey(libp2pPSK)
-    console.log('Generated new buffer psk', psk)
-    const pskBase64 = uint8ArrayToString(psk, 'base64')
+    const psk = generateLibp2pPSK(libp2pPSK)
+    const pskBase64 = psk.toString('base64')
     await this.localDbService.put(LocalDBKeys.PSK, pskBase64)
-
     console.log('psk base64 SAVED', pskBase64)
     this.serverIoProvider.io.emit(SocketActionTypes.PSK, { psk: pskBase64 })
   }
@@ -367,12 +374,14 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI
     if (!peers || peers.length === 0) {
       peers = [this.libp2pService.createLibp2pAddress(onionAddress, _peerId.toString())]
     }
-    const pskValue = await this.localDbService.get(LocalDBKeys.PSK) // What if there is no psk in db?
+    const pskValue = await this.localDbService.get(LocalDBKeys.PSK)
+    if (!pskValue) {
+      throw new Error('No psk in local db')
+    }
     console.log('psk base64 RETRIEVED', pskValue)
     const psk = uint8ArrayFromString(pskValue, 'base64')
-    console.log('psk buffer retrieved', psk)
     const libp2pPSK = new Uint8Array(95)
-    generateKey(libp2pPSK, psk)
+    generateLibp2pPSK(libp2pPSK, psk)
 
     const params: Libp2pNodeParams = {
       peerId: _peerId,
diff --git a/packages/common/package-lock.json b/packages/common/package-lock.json
index e3ab0a7f16..45a196a5bc 100644
--- a/packages/common/package-lock.json
+++ b/packages/common/package-lock.json
@@ -10,11 +10,13 @@
       "license": "ISC",
       "dependencies": {
         "cross-env": "^5.2.0",
-        "debug": "^4.3.1"
+        "debug": "^4.3.1",
+        "validator": "^13.11.0"
       },
       "devDependencies": {
         "@types/jest": "^26.0.23",
         "@types/node": "^17.0.21",
+        "@types/validator": "^13.11.5",
         "jest": "^26.6.3",
         "ts-jest": "^26.5.2",
         "typescript": "^4.9.3"
@@ -1116,6 +1118,12 @@
       "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
       "dev": true
     },
+    "node_modules/@types/validator": {
+      "version": "13.11.5",
+      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz",
+      "integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q==",
+      "dev": true
+    },
     "node_modules/@types/yargs": {
       "version": "15.0.15",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
@@ -5989,6 +5997,14 @@
         "spdx-expression-parse": "^3.0.0"
       }
     },
+    "node_modules/validator": {
+      "version": "13.11.0",
+      "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
+      "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/w3c-hr-time": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -7098,6 +7114,12 @@
       "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
       "dev": true
     },
+    "@types/validator": {
+      "version": "13.11.5",
+      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz",
+      "integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q==",
+      "dev": true
+    },
     "@types/yargs": {
       "version": "15.0.15",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
@@ -10885,6 +10907,11 @@
         "spdx-expression-parse": "^3.0.0"
       }
     },
+    "validator": {
+      "version": "13.11.0",
+      "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
+      "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ=="
+    },
     "w3c-hr-time": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
diff --git a/packages/common/package.json b/packages/common/package.json
index f9f6eb49f0..b3e8934d16 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -21,6 +21,7 @@
     "@quiet/eslint-config": "^2.0.1-alpha.4",
     "@types/jest": "^26.0.23",
     "@types/node": "^17.0.21",
+    "@types/validator": "^13.11.5",
     "jest": "^26.6.3",
     "ts-jest": "^26.5.2",
     "typescript": "^4.9.3"
@@ -28,7 +29,8 @@
   "dependencies": {
     "@quiet/types": "^2.0.1-alpha.4",
     "cross-env": "^5.2.0",
-    "debug": "^4.3.1"
+    "debug": "^4.3.1",
+    "validator": "^13.11.0"
   },
   "jest": {
     "transform": {
diff --git a/packages/common/src/invitationCode.test.ts b/packages/common/src/invitationCode.test.ts
index 76cb6320f7..f44588fe1f 100644
--- a/packages/common/src/invitationCode.test.ts
+++ b/packages/common/src/invitationCode.test.ts
@@ -13,6 +13,8 @@ describe('Invitation code helper', () => {
   const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad'
   const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE'
   const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd'
+  const psk = 'BNlxfE2WBF7LrlpIX0CvECN5o1oZtA16PkAb7GYiwYw%3D'
+  const pskDecoded = 'BNlxfE2WBF7LrlpIX0CvECN5o1oZtA16PkAb7GYiwYw='
 
   it('retrieves invitation code from argv', () => {
     const expectedCodes: InvitationData = {
@@ -20,7 +22,7 @@ describe('Invitation code helper', () => {
         { peerId: peerId1, onionAddress: address1 },
         { peerId: peerId2, onionAddress: address2 },
       ],
-      psk: '12345',
+      psk: pskDecoded,
     }
     const result = argvInvitationCode([
       'something',
@@ -33,16 +35,27 @@ describe('Invitation code helper', () => {
     expect(result).toEqual(expectedCodes)
   })
 
-  it('builds proper invitation deep url', () => {
+  it('returns null if argv do not contain any valid invitation code', () => {
+    const result = argvInvitationCode([
+      'something',
+      'quiet:/invalid',
+      'zbay://invalid',
+      'quiet://invalid',
+      'quiet://?param=invalid',
+    ])
+    expect(result).toBeNull()
+  })
+
+  it('composes proper invitation deep url', () => {
     expect(
       composeInvitationDeepUrl({
         pairs: [
           { peerId: 'peerID1', onionAddress: 'address1' },
           { peerId: 'peerID2', onionAddress: 'address2' },
         ],
-        psk: '12345',
+        psk: pskDecoded,
       })
-    ).toEqual(`quiet://?peerID1=address1&peerID2=address2&${Site.PSK_PARAM_KEY}=12345`)
+    ).toEqual(`quiet://?peerID1=address1&peerID2=address2&${Site.PSK_PARAM_KEY}=${psk}`)
   })
 
   it('creates invitation share url based on invitation data', () => {
@@ -51,9 +64,9 @@ describe('Invitation code helper', () => {
         { peerId: 'peerID1', onionAddress: 'address1' },
         { peerId: 'peerID2', onionAddress: 'address2' },
       ],
-      psk: '12345',
+      psk: pskDecoded,
     }
-    const expected = `${QUIET_JOIN_PAGE}#peerID1=address1&peerID2=address2&${Site.PSK_PARAM_KEY}=${pairs.psk}`
+    const expected = `${QUIET_JOIN_PAGE}#peerID1=address1&peerID2=address2&${Site.PSK_PARAM_KEY}=${psk}`
     expect(composeInvitationShareUrl(pairs)).toEqual(expected)
   })
 
@@ -63,14 +76,12 @@ describe('Invitation code helper', () => {
       'invalidAddress',
       '/dns4/somethingElse.onion/tcp/443/wss/p2p/QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA',
     ]
-    const psk = 'L2tleS9zd2FybS9wc2svMS'
-    expect(invitationShareUrl(peerList, psk)).toEqual(
+    expect(invitationShareUrl(peerList, pskDecoded)).toEqual(
       `${QUIET_JOIN_PAGE}#QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE=gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad&QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA=somethingElse&${Site.PSK_PARAM_KEY}=${psk}`
     )
   })
 
   it('retrieves invitation codes from deep url', () => {
-    const psk = '12345'
     const codes = parseInvitationCodeDeepUrl(
       `quiet://?${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=${psk}`
     )
@@ -79,17 +90,16 @@ describe('Invitation code helper', () => {
         { peerId: peerId1, onionAddress: address1 },
         { peerId: peerId2, onionAddress: address2 },
       ],
-      psk: psk,
+      psk: pskDecoded,
     })
   })
 
   it('retrieves invitation codes from deep url with partly invalid codes', () => {
-    const psk = '12345'
     const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLs'
     const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd'
     const parsed = parseInvitationCodeDeepUrl(
       `quiet://?${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=${psk}`
     )
-    expect(parsed).toEqual({ pairs: [{ peerId: peerId1, onionAddress: address1 }], psk: psk })
+    expect(parsed).toEqual({ pairs: [{ peerId: peerId1, onionAddress: address1 }], psk: pskDecoded })
   })
 })
diff --git a/packages/common/src/invitationCode.ts b/packages/common/src/invitationCode.ts
index d36a5ddc8e..4cc50616b8 100644
--- a/packages/common/src/invitationCode.ts
+++ b/packages/common/src/invitationCode.ts
@@ -1,12 +1,14 @@
 import { InvitationData, InvitationPair } from '@quiet/types'
 import { ONION_ADDRESS_REGEX, PEER_ID_REGEX, QUIET_JOIN_PAGE, Site } from './static'
 import { createLibp2pAddress } from './libp2p'
+import validator from 'validator'
 
 const parseDeepUrl = ({ url, expectedProtocol = `quiet:` }: { url: string; expectedProtocol?: string }) => {
   let _url = url
   let validUrl: URL | null = null
 
   if (!expectedProtocol) {
+    // Create a full url to be able to use the same URL parsing mechanism
     expectedProtocol = `${Site.DEEP_URL_SCHEME}:`
     _url = `${Site.DEEP_URL_SCHEME}://?${url}`
   }
@@ -14,20 +16,20 @@ const parseDeepUrl = ({ url, expectedProtocol = `quiet:` }: { url: string; expec
   try {
     validUrl = new URL(_url)
   } catch (e) {
-    console.error(`Could not retrieve invitation code from deep url ${url}. Reason: ${e.message}`)
+    console.error(`Could not retrieve invitation code from deep url '${url}'. Reason: ${e.message}`)
     throw e
   }
   if (!validUrl || validUrl.protocol !== expectedProtocol) {
-    console.error(`Could not retrieve invitation code from deep url ${url}`)
+    console.error(`Could not retrieve invitation code from deep url '${url}'`)
     throw new Error()
   }
   const params = validUrl.searchParams
   const codes: InvitationPair[] = []
   let psk = params.get(Site.PSK_PARAM_KEY)
-  if (!psk) throw new Error(`No psk found in invitation code ${url}`)
+  if (!psk) throw new Error(`No psk found in invitation code '${url}'`)
 
   psk = decodeURIComponent(psk)
-  // Validate base64
+  if (!validator.isBase64(psk)) throw new Error(`Invalid psk in invitation code '${url}'`)
 
   params.delete(Site.PSK_PARAM_KEY)
 
@@ -61,12 +63,11 @@ export const parseInvitationCode = (code: string): InvitationData => {
 }
 
 export const invitationShareUrl = (peers: string[] = [], psk: string): string => {
-  // TODO: rename to 'composeInvitationShareUrl'
+  // TODO: rename
   /**
    * @arg {string[]} peers - List of peer's p2p addresses
    * @returns {string} - Complete shareable invitation link, e.g. https://tryquiet.org/join/#<peerid1>=<address1>&<peerid2>=<addresss2>&k=<psk>
    */
-  console.log('Invitation share url, peers:', peers)
   const pairs: InvitationPair[] = []
   for (const peerAddress of peers) {
     let peerId: string
@@ -144,7 +145,7 @@ export const argvInvitationCode = (argv: string[]): InvitationData | null => {
   return invitationData
 }
 
-export const peerDataValid = ({ peerId, onionAddress }: { peerId: string; onionAddress: string }): boolean => {
+const peerDataValid = ({ peerId, onionAddress }: { peerId: string; onionAddress: string }): boolean => {
   // TODO: rename to peerDataValid?
   if (!peerId.match(PEER_ID_REGEX)) {
     // TODO: test it more properly e.g with PeerId.createFromB58String(peerId.trim())
diff --git a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx
index e5920095e1..1d094db8b0 100644
--- a/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx
+++ b/packages/desktop/src/renderer/components/CreateJoinCommunity/PerformCommunityActionComponent.tsx
@@ -20,7 +20,7 @@ import { InviteLinkErrors } from '../../forms/fieldsErrors'
 import { IconButton, InputAdornment } from '@mui/material'
 import VisibilityOff from '@mui/icons-material/VisibilityOff'
 import Visibility from '@mui/icons-material/Visibility'
-import { ONION_ADDRESS_REGEX, composeToInvitationShareUrl, parseName } from '@quiet/common'
+import { ONION_ADDRESS_REGEX, composeInvitationShareUrl, parseName } from '@quiet/common'
 import { getInvitationCodes } from '@quiet/state-manager'
 
 const PREFIX = 'PerformCommunityActionComponent'
@@ -221,7 +221,7 @@ export const PerformCommunityActionComponent: React.FC<PerformCommunityActionPro
   useEffect(() => {
     if (communityOwnership === CommunityOwnership.User && invitationCode?.length && psk) {
       setFormSent(true)
-      setValue('name', composeToInvitationShareUrl({ pairs: invitationCode, psk: psk }))
+      setValue('name', composeInvitationShareUrl({ pairs: invitationCode, psk: psk }))
     }
   }, [communityOwnership, invitationCode])
 
diff --git a/packages/desktop/src/renderer/components/Settings/Settings.stories.tsx b/packages/desktop/src/renderer/components/Settings/Settings.stories.tsx
index 829cfcdffa..80e8663143 100644
--- a/packages/desktop/src/renderer/components/Settings/Settings.stories.tsx
+++ b/packages/desktop/src/renderer/components/Settings/Settings.stories.tsx
@@ -10,9 +10,9 @@ import { InviteComponent } from './Tabs/Invite/Invite.component'
 import { LeaveCommunityComponent } from './Tabs/LeaveCommunity/LeaveCommunityComponent'
 import { Typography } from '@mui/material'
 import { QRCodeComponent } from './Tabs/QRCode/QRCode.component'
-import { composeToInvitationShareUrl } from '@quiet/common'
+import { composeInvitationShareUrl } from '@quiet/common'
 
-const invitationLink = composeToInvitationShareUrl({
+const invitationLink = composeInvitationShareUrl({
   pairs: [
     {
       peerId: 'QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3',
diff --git a/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.component.test.tsx b/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.component.test.tsx
index 3e3508c114..62e01e5e9f 100644
--- a/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.component.test.tsx
+++ b/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.component.test.tsx
@@ -2,11 +2,11 @@ import '@testing-library/jest-dom'
 import React from 'react'
 import { renderComponent } from '../../../../testUtils/renderComponent'
 import { InviteComponent } from './Invite.component'
-import { composeToInvitationShareUrl } from '@quiet/common'
+import { composeInvitationShareUrl } from '@quiet/common'
 
 describe('CopyLink', () => {
   it('renderComponent - hidden long link', () => {
-    const invitationLink = composeToInvitationShareUrl({
+    const invitationLink = composeInvitationShareUrl({
       pairs: [
         {
           peerId: 'QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3',
@@ -127,7 +127,7 @@ describe('CopyLink', () => {
   })
 
   it('renderComponent - revealed short link', () => {
-    const invitationLink = composeToInvitationShareUrl({
+    const invitationLink = composeInvitationShareUrl({
       pairs: [
         {
           peerId: 'QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3',
diff --git a/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.stories.tsx b/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.stories.tsx
index 66530189df..95849b7ca6 100644
--- a/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.stories.tsx
+++ b/packages/desktop/src/renderer/components/Settings/Tabs/Invite/Invite.stories.tsx
@@ -2,7 +2,7 @@ import React from 'react'
 import { ComponentStory, ComponentMeta } from '@storybook/react'
 import { withTheme } from '../../../../storybook/decorators'
 import { InviteComponent, InviteComponentProps } from './Invite.component'
-import { composeToInvitationShareUrl } from '@quiet/common'
+import { composeInvitationShareUrl } from '@quiet/common'
 
 const Template: ComponentStory<typeof InviteComponent> = args => {
   return <InviteComponent {...args} />
@@ -10,7 +10,7 @@ const Template: ComponentStory<typeof InviteComponent> = args => {
 
 export const Component = Template.bind({})
 let revealInputValue = true
-const invitationLink = composeToInvitationShareUrl({
+const invitationLink = composeInvitationShareUrl({
   pairs: [
     {
       peerId: 'QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3',
diff --git a/packages/desktop/src/renderer/components/Settings/Tabs/QRCode/QRCode.stories.tsx b/packages/desktop/src/renderer/components/Settings/Tabs/QRCode/QRCode.stories.tsx
index 888340710d..3eee7762eb 100644
--- a/packages/desktop/src/renderer/components/Settings/Tabs/QRCode/QRCode.stories.tsx
+++ b/packages/desktop/src/renderer/components/Settings/Tabs/QRCode/QRCode.stories.tsx
@@ -3,9 +3,9 @@ import { ComponentStory, ComponentMeta } from '@storybook/react'
 
 import { withTheme } from '../../../../storybook/decorators'
 import QRCodeComponent, { QRCodeProps } from './QRCode.component'
-import { composeToInvitationShareUrl } from '@quiet/common'
+import { composeInvitationShareUrl } from '@quiet/common'
 
-const invitationLink = composeToInvitationShareUrl({
+const invitationLink = composeInvitationShareUrl({
   pairs: [
     {
       peerId: 'QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3',
diff --git a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts
index 90f456d3b1..a87ef32a81 100644
--- a/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts
+++ b/packages/state-manager/src/utils/functions/invitationCode/invitationCode.test.ts
@@ -1,15 +1,18 @@
 import { getInvitationCodes } from './invitationCode'
-import { QUIET_JOIN_PAGE } from '@quiet/common'
+import { QUIET_JOIN_PAGE, Site } from '@quiet/common'
 
 describe('Invitation code helper', () => {
   const peerId1 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSA'
   const address1 = 'gloao6h5plwjy4tdlze24zzgcxll6upq2ex2fmu2ohhyu4gtys4nrjad'
   const peerId2 = 'QmZoiJNAvCffeEHBjk766nLuKVdkxkAT7wfFJDPPLsbKSE'
   const address2 = 'y7yczmugl2tekami7sbdz5pfaemvx7bahwthrdvcbzw5vex2crsr26qd'
+  const psk = 'BNlxfE2WBF7LrlpIX0CvECN5o1oZtA16PkAb7GYiwYw='
+  const encodedPsk = encodeURIComponent(psk)
 
   it('retrieves invitation code if url is a proper share url', () => {
-    const psk = 'abcde'
-    const result = getInvitationCodes(`${QUIET_JOIN_PAGE}#${peerId1}=${address1}&${peerId2}=${address2}&k=${psk}`)
+    const result = getInvitationCodes(
+      `${QUIET_JOIN_PAGE}#${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=${encodedPsk}`
+    )
     expect(result).toEqual({
       pairs: [
         { peerId: peerId1, onionAddress: address1 },
@@ -20,7 +23,6 @@ describe('Invitation code helper', () => {
   })
 
   it('throws error if code is not a proper share url nor a code', () => {
-    // const result = 'invalidCode')
     expect(() => getInvitationCodes('invalidCode')).toThrow()
   })
 
@@ -28,9 +30,16 @@ describe('Invitation code helper', () => {
     expect(() => getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}`)).toThrow()
   })
 
+  it('throws error if psk has invalid format', () => {
+    expect(() =>
+      getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=12345`)
+    ).toThrow()
+  })
+
   it('retrieves invitation code if url is a proper code', () => {
-    const psk = 'abcde'
-    const result = getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}&k=${psk}`)
+    const result = getInvitationCodes(
+      `${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=${encodedPsk}`
+    )
     expect(result).toEqual({
       pairs: [
         { peerId: peerId1, onionAddress: address1 },
@@ -41,8 +50,9 @@ describe('Invitation code helper', () => {
   })
 
   it('retrieves invitation code if url is a proper code', () => {
-    const psk = 'abcde'
-    const result = getInvitationCodes(`${peerId1}=${address1}&${peerId2}=${address2}&k=${psk}`)
+    const result = getInvitationCodes(
+      `${peerId1}=${address1}&${peerId2}=${address2}&${Site.PSK_PARAM_KEY}=${encodedPsk}`
+    )
     expect(result).toEqual({
       pairs: [
         { peerId: peerId1, onionAddress: address1 },