Skip to content

Commit

Permalink
Fix error with owner cert, fix tests, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Leblow committed Nov 29, 2023
1 parent fafe693 commit b0f3ce2
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ describe('CopyLink', () => {
class="MuiTypography-root MuiTypography-body2 InviteToCommunitylink css-16d47hw-MuiTypography-root"
data-testid="invitation-link"
>
https://tryquiet.org/join#QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3=p3oqdr53dkgg3n5nuezlzyawhxvit5efxzlunvzp7n7lmva6fj3i43ad&k=12345
https://tryquiet.org/join#QmVTkUad2Gq3MkCa8gf12R1gsWDfk2yiTEqb6YGXDG2iQ3=p3oqdr53dkgg3n5nuezlzyawhxvit5efxzlunvzp7n7lmva6fj3i43ad&k=12345&o=testOwnerOrbitDbIdentity
</p>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall InviteToCommunityeyeIcon css-1pe4mpk-MuiButtonBase-root-MuiIconButton-root"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('Handle invitation code', () => {
ownership: CommunityOwnership.User,
peers: validInvitationData.pairs,
psk: validInvitationData.psk,
ownerOrbitDbIdentity: validInvitationData.ownerOrbitDbIdentity,
}
await expectSaga(customProtocolSaga, communities.actions.customProtocol(validInvitationData))
.withState(store.getState())
Expand Down
3 changes: 2 additions & 1 deletion packages/desktop/src/rtl-tests/community.create.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,10 @@ describe('User', () => {
"Network/setLoadingPanelType",
"Modals/openModal",
"Identity/registerCertificate",
"Communities/addOwnerCertificate",
"Communities/updateCommunity",
"Identity/storeUserCertificate",
"Identity/savedOwnerCertificate",
"Communities/updateCommunityData",
"Communities/launchRegistrar",
"Identity/saveUserCsr",
"Files/checkForMissingFiles",
Expand Down
4 changes: 2 additions & 2 deletions packages/identity/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ export const formatPEM = (pemString: string): string => {
return resultString
}

export const loadCertificate = (rootCert: string): Certificate => {
const certificateBuffer = stringToArrayBuffer(fromBase64(rootCert))
export const loadCertificate = (cert: string): Certificate => {
const certificateBuffer = stringToArrayBuffer(fromBase64(cert))
const asn1 = fromBER(certificateBuffer)
return new Certificate({ schema: asn1.result })
}
Expand Down
4 changes: 4 additions & 0 deletions packages/identity/src/extractPubKey.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* TODO: I think we can unify this with common.ts. It seems like there
* is some overlap with the functions.
*/
import { fromBase64, stringToArrayBuffer } from 'pvutils'
import { fromBER } from 'asn1js'
import config from './config'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('communitiesSelectors', () => {

it('select current community', () => {
const community = communitiesSelectors.currentCommunity(store.getState())
expect(community).toEqual({ ...communityAlpha, ownerCertificate: identity.userCertificate })
expect(community).toEqual({ ...communityAlpha })
})

it('returns registrar url without port if no port in the store', async () => {
Expand Down Expand Up @@ -136,44 +136,24 @@ describe('communitiesSelectors', () => {

it('returns proper ownerNickname - ownerCertificate exist', async () => {
const { store } = prepareStore()
expect(identity.userCertificate).not.toBeUndefined()
store.dispatch(
usersActions.responseSendCertificates({
certificates: [identity.userCertificate || ''],
})
)
const expexctedNickname = 'alice'
const factory = await getFactory(store)

const ownerCertificate =
'MIIDdDCCAxugAwIBAgIGAYeiqwwYMAoGCCqGSM49BAMCMA8xDTALBgNVBAMTBHRlc3QwHhcNMjMwNDIxMDcxNTMxWhcNMzAwMTMxMjMwMDAwWjBJMUcwRQYDVQQDEz5qYm1zbXR4Z2Rhd241ZTdyZ3Z5ZGZ3bGFuY3c1bnZkcmZjdXdvdmltNzJqeXY2ZTN5eDR0ZXhxZC5vbmlvbjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBjP55M/p8QVQGdgjtAdGwLS8uyzyIaWzvnuCvOwLs/u+FHUdb0DU2+M4TYEZjVHmqn+hSERs4XHG0/tbaaGSyGjggInMIICIzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIAgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwggFHBgkqhkiG9w0BCQwEggE4BIIBNCqfocsbSvEqAdeRObiywx0KV2r7xEnqFysFuc1InEpwF3707TZGrFxww74g/ccxHCZ9zda4EHawgLoU6oKdeyec8W7qAThnWCRzJcOPINdZaTR45g28jeWAXMAtVG6eYtEQS4t7g915QaB0uYUoM3Teqp/qaMhk/9Hs4jiKlN3wL9WFYRf14XQIIVu3Fb0f3sD2/ejNPRJztJeJCwYtcFNF3fhPpH5bSPlcy6IaxhQrMXboqAfSAUlnMD4PifHFxvQYbfvTEC65Gt+FzwJ956BA5PuKsGFf+NVznyp5/YtFrl0XRRdlBcTzp2jreqhxBCdsvCpPwvM2TRv4OPk+hjMPPzBdPgvs5tytiFFyK9hXemai2TTwP1qo+VuV5SYyAyZP4rPxc/XEDHk+W3QN0vF8Ff+iMBUGCisGAQQBg4wbAgEEBxMFYWxpY2UwPQYJKwYBAgEPAwEBBDATLlFtZVN0WFY5VERXVHhoYXZUd25DZWdaYnNvMndQZ3BYQ2lzdHlCTEo2b0MyZHcwSQYDVR0RBEIwQII+amJtc210eGdkYXduNWU3cmd2eWRmd2xhbmN3NW52ZHJmY3V3b3ZpbTcyanl2NmUzeXg0dGV4cWQub25pb24wCgYIKoZIzj0EAwIDRwAwRAIga3etWmNtiMT/SUZkG0Rf5kwl3HxsGDJXsU7X5aCQAvMCIFKVBnCbTPseU5gQwamWZDG9ZoMf0X1VGzYUixWvmzuc'
const expectedNickname = 'alice'

const factory = await getFactory(store)
store.dispatch(
usersActions.storeUserCertificate({
certificate: ownerCertificate,
})
)
await factory.create<ReturnType<typeof communitiesActions.addOwnerCertificate>['payload']>('Community', {
await factory.create<ReturnType<typeof communitiesActions.updateCommunityData>['payload']>('Community', {
ownerCertificate,
})

const ownerNickname = communitiesSelectors.ownerNickname(store.getState())
expect(ownerNickname).toEqual(expexctedNickname)

expect(ownerNickname).toEqual(expectedNickname)
})

it('returns proper ownerNickname - ownerCertificate not exist - backwards compatibility', async () => {
it('returns proper ownerNickname - ownerCertificate not exist', async () => {
const { store } = prepareStore()
expect(identity.userCertificate).not.toBeUndefined()
store.dispatch(
usersActions.responseSendCertificates({
certificates: [identity.userCertificate || ''],
})
)

store.dispatch(
usersActions.setAllCerts({
certificates: [identity.userCertificate || ''],
})
)
const ownerNickname = communitiesSelectors.ownerNickname(store.getState())
expect(ownerNickname).toEqual(identity.nickname)
expect(ownerNickname).toEqual(undefined)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { communitiesAdapter } from './communities.adapter'
import { type CreatedSelectors, type StoreState } from '../store.types'
import { invitationShareUrl } from '@quiet/common'
import { CertFieldsTypes, getCertFieldValue, parseCertificate } from '@quiet/identity'
import { getOldestParsedCerificate } from '../users/users.selectors'

// Workaround for "The inferred type of 'communitiesSelectors' cannot be named without a reference to
// 'packages/identity/node_modules/pkijs/build'. This is likely not portable. A type annotation is necessary."
Expand Down Expand Up @@ -61,6 +60,10 @@ export const psk = createSelector(communitiesSlice, reducerState => {
return reducerState.psk
})

export const ownerCertificate = createSelector(currentCommunity, currentCommunity => {
return currentCommunity?.ownerCertificate
})

export const ownerOrbitDbIdentity = createSelector(currentCommunity, currentCommunity => {
return currentCommunity?.ownerOrbitDbIdentity
})
Expand All @@ -79,30 +82,19 @@ export const invitationUrl = createSelector(
}
)

export const ownerNickname = createSelector(
currentCommunity,
getOldestParsedCerificate,
(community, oldestParsedCerificate) => {
if (!oldestParsedCerificate) return undefined
const ownerCertificate = community?.ownerCertificate || undefined

let nickname: string | null = null

if (ownerCertificate) {
const certificate = ownerCertificate
const parsedCert = parseCertificate(certificate)
nickname = getCertFieldValue(parsedCert, CertFieldsTypes.nickName)
} else {
nickname = getCertFieldValue(oldestParsedCerificate, CertFieldsTypes.nickName)
}
export const ownerNickname = createSelector(ownerCertificate, ownerCertificate => {
if (!ownerCertificate) return undefined

if (!nickname) {
console.error('Could not retrieve owner nickname from certificate')
}
const certificate = ownerCertificate
const parsedCert = parseCertificate(certificate)
const nickname = getCertFieldValue(parsedCert, CertFieldsTypes.nickName)

return nickname
if (!nickname) {
console.error('Could not retrieve owner nickname from certificate')
}
)

return nickname
})

export const communitiesSelectors = {
selectById,
Expand All @@ -113,7 +105,8 @@ export const communitiesSelectors = {
registrarUrl,
invitationCodes,
invitationUrl,
ownerOrbitDbIdentity,
ownerCertificate,
ownerNickname,
psk,
ownerOrbitDbIdentity,
}
19 changes: 5 additions & 14 deletions packages/state-manager/src/sagas/communities/communities.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { communitiesAdapter } from './communities.adapter'
import {
InvitationPair,
type AddOwnerCertificatePayload,
type Community as CommunityType,
type Community,
type CreateNetworkPayload,
type ResponseCreateNetworkPayload,
type ResponseRegistrarPayload,
Expand All @@ -17,7 +17,7 @@ import {
export class CommunitiesState {
public invitationCodes: InvitationPair[] = []
public currentCommunity = ''
public communities: EntityState<CommunityType> = communitiesAdapter.getInitialState()
public communities: EntityState<Community> = communitiesAdapter.getInitialState()
public psk: string | undefined
}

Expand All @@ -28,11 +28,11 @@ export const communitiesSlice = createSlice({
setCurrentCommunity: (state, action: PayloadAction<string>) => {
state.currentCommunity = action.payload
},
addNewCommunity: (state, action: PayloadAction<CommunityType>) => {
addNewCommunity: (state, action: PayloadAction<Community>) => {
communitiesAdapter.addOne(state.communities, action.payload)
},
updateCommunity: (state, _action: PayloadAction<CommunityType>) => state,
updateCommunityData: (state, action: PayloadAction<CommunityType>) => {
updateCommunity: (state, _action: PayloadAction<Community>) => state,
updateCommunityData: (state, action: PayloadAction<Community>) => {
communitiesAdapter.updateOne(state.communities, {
id: action.payload.id,
changes: {
Expand Down Expand Up @@ -77,15 +77,6 @@ export const communitiesSlice = createSlice({
clearInvitationCodes: state => {
state.invitationCodes = []
},
addOwnerCertificate: (state, action: PayloadAction<AddOwnerCertificatePayload>) => {
const { communityId, ownerCertificate } = action.payload
communitiesAdapter.updateOne(state.communities, {
id: communityId,
changes: {
ownerCertificate,
},
})
},
saveCommunityMetadata: (state, _action: PayloadAction<CommunityMetadata>) => state,
savePSK: (state, action: PayloadAction<string>) => {
state.psk = action.payload
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ export function* saveCommunityMetadataSaga(
id: communityId,
rootCa: action.payload.rootCa,
ownerOrbitDbIdentity: action.payload.ownerOrbitDbIdentity,
})
)
yield* put(
communitiesActions.addOwnerCertificate({
communityId: communityId,
ownerCertificate: action.payload.ownerCertificate,
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ export function* updateCommunitySaga(
}
}

const payload: { id: string; name?: string; rootCa?: string; ownerOrbitDbIdentity?: string } = {
const payload: {
id: string
name?: string
rootCa?: string
ownerCertificate?: string
ownerOrbitDbIdentity?: string
} = {
id: action.payload.id,
}

Expand All @@ -37,5 +43,9 @@ export function* updateCommunitySaga(
payload.ownerOrbitDbIdentity = action.payload.ownerOrbitDbIdentity
}

if (action.payload.ownerCertificate) {
payload.ownerCertificate = action.payload.ownerCertificate
}

yield* put(communitiesActions.updateCommunityData(payload))
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getFactory } from '../../..'
import { prepareStore, reducers } from '../../../utils/tests/prepareStore'
import { combineReducers } from '@reduxjs/toolkit'
import { expectSaga } from 'redux-saga-test-plan'
import { type communitiesActions } from '../../communities/communities.slice'
import { communitiesActions } from '../../communities/communities.slice'
import { type identityActions } from '../../identity/identity.slice'
import { type FactoryGirl } from 'factory-girl'
import { generateChannelId, userCreatedChannelMessage, userJoinedMessage, verifyUserInfoMessage } from '@quiet/common'
Expand Down Expand Up @@ -53,6 +53,13 @@ describe('verifyMessage saga test', () => {

aliceCsr = alice.userCsr?.userCsr || ''

store.dispatch(communitiesActions.updateCommunityData({
id: community.id,
// null/undefined type mismatch here. Might make things easier
// to make it consistent.
ownerCertificate: alice.userCertificate || undefined,
}))

bob = await factory.create<ReturnType<typeof identityActions.addNewIdentity>['payload']>('Identity', {
id: community.id,
nickname: 'bob',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ export function subscribe(socket: Socket) {
| ReturnType<typeof communitiesActions.responseRegistrar>
| ReturnType<typeof communitiesActions.launchRegistrar>
| ReturnType<typeof communitiesActions.launchCommunity>
| ReturnType<typeof communitiesActions.addOwnerCertificate>
| ReturnType<typeof networkActions.addInitializedCommunity>
| ReturnType<typeof networkActions.addInitializedRegistrar>
| ReturnType<typeof networkActions.removeConnectedPeer>
Expand Down Expand Up @@ -213,13 +212,6 @@ export function subscribe(socket: Socket) {
socket.on(SocketActionTypes.SEND_USER_CERTIFICATE, (payload: SendOwnerCertificatePayload) => {
log(`${SocketActionTypes.SEND_USER_CERTIFICATE}: ${payload.communityId}`)

emit(
communitiesActions.addOwnerCertificate({
communityId: payload.communityId,
ownerCertificate: payload.payload.ownerCert,
})
)

emit(
communitiesActions.storePeerList({
communityId: payload.communityId,
Expand All @@ -236,15 +228,16 @@ export function subscribe(socket: Socket) {
communitiesActions.updateCommunity({
id: payload.communityId,
rootCa: payload.payload.rootCa,
ownerCertificate: payload.payload.ownerCert,
})
)
emit(communitiesActions.launchCommunity(payload.communityId))
})
socket.on(SocketActionTypes.SAVED_OWNER_CERTIFICATE, (payload: SavedOwnerCertificatePayload) => {
log(`${SocketActionTypes.SAVED_OWNER_CERTIFICATE}: ${payload.communityId}`)
emit(
communitiesActions.addOwnerCertificate({
communityId: payload.communityId,
communitiesActions.updateCommunity({
id: payload.communityId,
ownerCertificate: payload.network.certificate,
})
)
Expand Down
25 changes: 6 additions & 19 deletions packages/state-manager/src/sagas/users/users.selectors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createSelector } from '@reduxjs/toolkit'
import { getCertFieldValue, getReqFieldValue, keyFromCertificate } from '@quiet/identity'
import { getCertFieldValue, getReqFieldValue, keyFromCertificate, loadCertificate } from '@quiet/identity'
import { CertFieldsTypes } from './const/certFieldTypes'
import { StoreKeys } from '../store.keys'
import { certificatesAdapter } from './users.adapter'
import { type Certificate } from 'pkijs'
import { type CreatedSelectors, type StoreState } from '../store.types'
import { type UserData, User } from '@quiet/types'
import { ownerCertificate } from '../communities/communities.selectors'

const usersSlice: CreatedSelectors[StoreKeys.Users] = (state: StoreState) => state[StoreKeys.Users]

Expand Down Expand Up @@ -122,23 +123,10 @@ export const allUsers = createSelector(csrsMapping, certificatesMapping, (csrs,

export const getUserByPubKey = (pubKey: string) => createSelector(allUsers, users => users[pubKey])

export const getOldestParsedCerificate = createSelector(certificates, certs => {
const getTimestamp = (cert: Certificate) => new Date(cert.notBefore.value).getTime()
let certificates: Certificate[] = []
Object.keys(certs).map(pubKey => {
certificates = [...certificates, certs[pubKey]]
})
certificates.sort((a, b) => {
const aTimestamp = getTimestamp(a)
const bTimestamp = getTimestamp(b)
return aTimestamp - bTimestamp
})

return certificates[0]
})

export const ownerData = createSelector(getOldestParsedCerificate, ownerCert => {
if (!ownerCert) return null
// Perhaps we should move this to communities.selectors.ts?
export const ownerData = createSelector(ownerCertificate, ownerCertificate => {
if (!ownerCertificate) return null
const ownerCert = loadCertificate(ownerCertificate)
const username = getCertFieldValue(ownerCert, CertFieldsTypes.nickName)
const onionAddress = getCertFieldValue(ownerCert, CertFieldsTypes.commonName)
const peerId = getCertFieldValue(ownerCert, CertFieldsTypes.peerId)
Expand All @@ -165,7 +153,6 @@ export const usersSelectors = {
certificates,
certificatesMapping,
csrsMapping,
getOldestParsedCerificate,
ownerData,
allUsers,
duplicateCerts,
Expand Down
Loading

0 comments on commit b0f3ce2

Please sign in to comment.