Skip to content

Commit

Permalink
feat: Check if psk in invitation link is base64 encoded #1897
Browse files Browse the repository at this point in the history
  • Loading branch information
EmiM committed Oct 24, 2023
1 parent 4a843cf commit 8ae801d
Show file tree
Hide file tree
Showing 15 changed files with 161 additions and 63 deletions.
22 changes: 14 additions & 8 deletions packages/backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
31 changes: 31 additions & 0 deletions packages/backend/src/nest/common/a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { randomBytes } from '@libp2p/crypto'
import crypto from 'crypto'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import fs from 'fs'

const KEY_LENGTH = 32

export function generateKey(bytes: Uint8Array | NodeJS.WriteStream, key?: Uint8Array) {
/**
* Based on 'libp2p/pnet' generateKey
*/
const psk = key || randomBytes(KEY_LENGTH)
const base16StringKey = uint8ArrayToString(psk, 'base16')
const fullKey = uint8ArrayFromString('/key/swarm/psk/1.0.0/\n/base16/\n' + base16StringKey)

if (bytes instanceof Uint8Array) {
bytes.set(fullKey)
} else {
bytes.write(fullKey)
}
return psk
}

const libp2pPSK = new Uint8Array(95)
const psk = generateKey(libp2pPSK)
console.log('Generated new buffer psk', psk)
const pskBase64 = uint8ArrayToString(psk, 'base64')
// Buffer.from(uint8ArrayToString(psk))

// btoa()
8 changes: 5 additions & 3 deletions packages/backend/src/nest/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -276,22 +277,28 @@ 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)
}

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 })
}
Expand Down Expand Up @@ -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,
Expand Down
29 changes: 28 additions & 1 deletion packages/common/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
"@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"
},
"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": {
Expand Down
34 changes: 22 additions & 12 deletions packages/common/src/invitationCode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ 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 = {
pairs: [
{ peerId: peerId1, onionAddress: address1 },
{ peerId: peerId2, onionAddress: address2 },
],
psk: '12345',
psk: pskDecoded,
}
const result = argvInvitationCode([
'something',
Expand All @@ -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', () => {
Expand All @@ -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)
})

Expand All @@ -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}`
)
Expand All @@ -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 })
})
})
Loading

0 comments on commit 8ae801d

Please sign in to comment.