Skip to content

Commit

Permalink
Contract ids instead of usernames (#1829)
Browse files Browse the repository at this point in the history
* Changes to use contract IDs internally and bugfixes

* Added missing comments

* Feedback

* Unamiguous @ALL mention (using channel ID)

* Feedback

* Revert "Unamiguous @ALL mention (using channel ID)"

This reverts commit 6769085.

* Remove console.error in Join.vue
  • Loading branch information
corrideat committed Feb 7, 2024
1 parent 3c7a3ba commit f8cac66
Show file tree
Hide file tree
Showing 95 changed files with 1,468 additions and 1,310 deletions.
15 changes: 10 additions & 5 deletions frontend/controller/actions/chatroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ export default (sbp('sbp/selectors/register', {
name: `${userID}/${userCSKid}`
})
],
data: {
...params.data,
attributes: {
...params.data?.attributes,
creatorID: userID
}
},
contractName: 'gi.contracts/chatroom'
})

Expand All @@ -159,8 +166,7 @@ export default (sbp('sbp/selectors/register', {
const originatingContractID = state.attributes.groupContractID ? state.attributes.groupContractID : contractID

// $FlowFixMe
return Promise.all(Object.keys(state.users).map(async (username) => {
const pContractID = await sbp('namespace/lookup', username)
return Promise.all(Object.keys(state.members).map((pContractID) => {
const CEKid = findKeyIdByName(rootState[pContractID], 'cek')
if (!CEKid) {
console.warn(`Unable to share rotated keys for ${originatingContractID} with ${pContractID}: Missing CEK`)
Expand Down Expand Up @@ -188,9 +194,8 @@ export default (sbp('sbp/selectors/register', {
...encryptedAction('gi.actions/chatroom/deleteMessage', L('Failed to delete message.')),
...encryptedAction('gi.actions/chatroom/makeEmotion', L('Failed to make emotion.')),
...encryptedAction('gi.actions/chatroom/join', L('Failed to join chat channel.'), async (sendMessage, params, signingKeyId) => {
const rootGetters = sbp('state/vuex/getters')
const rootState = sbp('state/vuex/state')
const userID = rootGetters.ourContactProfiles[params.data.username]?.contractID
const userID = params.data.memberID || rootState.loggedIn.identityContractID

// We need to read values from both the chatroom and the identity contracts'
// state, so we call wait to run the rest of this function after all
Expand Down Expand Up @@ -244,7 +249,7 @@ export default (sbp('sbp/selectors/register', {
...encryptedAction('gi.actions/chatroom/changeDescription', L('Failed to change chat channel description.')),
...encryptedAction('gi.actions/chatroom/leave', L('Failed to leave chat channel.'), async (sendMessage, params, signingKeyId) => {
const rootGetters = sbp('state/vuex/getters')
const userID = rootGetters.ourContactProfiles[params.data.member]?.contractID
const userID = rootGetters.ourContactProfiles[params.data.memberID]?.contractID

const keyIds = userID && sbp('chelonia/contract/foreignKeysByContractID', params.contractID, userID)

Expand Down
156 changes: 68 additions & 88 deletions frontend/controller/actions/group.js

Large diffs are not rendered by default.

29 changes: 16 additions & 13 deletions frontend/controller/actions/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,10 @@ export default (sbp('sbp/selectors/register', {
// (2) Check whether the join process is still incomplete
// This needs to be re-checked because it may have changed after
// sync
state[groupId]?.profiles?.[username]?.status !== PROFILE_STATUS.ACTIVE &&
// // We only check for groups where we don't have a profile, as
// // re-joining is handled by the group contract itself.
// !state[groupId]?.profiles?.[identityContractID] && // ?.status !== PROFILE_STATUS.
state[groupId]?.profiles?.[identityContractID]?.status !== PROFILE_STATUS.ACTIVE &&
// (3) Call join
sbp('gi.actions/group/join', {
originatingContractID: identityContractID,
Expand All @@ -413,7 +416,7 @@ export default (sbp('sbp/selectors/register', {
.forEach(cId => {
// We send this action only for groups we have fully joined (i.e.,
// accepted an invite add added our profile)
if (state[cId]?.profiles?.[username]?.status === PROFILE_STATUS.ACTIVE) {
if (state[cId]?.profiles?.[identityContractID]?.status === PROFILE_STATUS.ACTIVE) {
sbp('gi.actions/group/updateLastLoggedIn', { contractID: cId }).catch((e) => console.error('Error sending updateLastLoggedIn', e))
}
})
Expand Down Expand Up @@ -530,7 +533,7 @@ export default (sbp('sbp/selectors/register', {
'gi.actions/identity/shareNewPEK': async (contractID: string, newKeys) => {
const rootState = sbp('state/vuex/state')
const state = rootState[contractID]
const username = state.attributes.username
const identityContractID = state.attributes.identityContractID

// TODO: Also share PEK with DMs
await Promise.all((state.loginState?.groupIds || []).filter(groupID => !!rootState.contracts[groupID]).map(groupID => {
Expand Down Expand Up @@ -562,7 +565,7 @@ export default (sbp('sbp/selectors/register', {
hooks: {
preSendCheck: (_, state) => {
// Don't send this message if we're no longer a group member
return state?.profiles?.[username]?.status === PROFILE_STATUS.ACTIVE
return state?.profiles?.[identityContractID]?.status === PROFILE_STATUS.ACTIVE
}
}
}).catch(e => {
Expand All @@ -585,7 +588,7 @@ export default (sbp('sbp/selectors/register', {
...encryptedAction('gi.actions/identity/createDirectMessage', L('Failed to create a new direct message channel.'), async function (sendMessage, params) {
const rootState = sbp('state/vuex/state')
const rootGetters = sbp('state/vuex/getters')
const partnerProfiles = params.data.usernames.map(username => rootGetters.ourContactProfiles[username])
const partnerIDs = params.data.memberIDs.map(memberID => rootGetters.ourContactProfilesById[memberID].contractID)
// NOTE: 'rootState.currentGroupId' could be changed while waiting for the sbp functions to be proceeded
// So should save it as a constant variable 'currentGroupId', and use it which can't be changed
const currentGroupId = rootState.currentGroupId
Expand Down Expand Up @@ -616,14 +619,14 @@ export default (sbp('sbp/selectors/register', {
await sbp('gi.actions/chatroom/join', {
...omit(params, ['options', 'contractID', 'data', 'hooks']),
contractID: message.contractID(),
data: { username: rootState.loggedIn.username }
data: {}
})

for (const profile of partnerProfiles) {
for (const partnerID of partnerIDs) {
await sbp('gi.actions/chatroom/join', {
...omit(params, ['options', 'contractID', 'data', 'hooks']),
contractID: message.contractID(),
data: { username: profile.username }
data: { memberID: partnerID }
})
}

Expand All @@ -638,22 +641,22 @@ export default (sbp('sbp/selectors/register', {
}
})

for (const [index, profile] of partnerProfiles.entries()) {
const hooks = index < partnerProfiles.length - 1 ? undefined : { prepublish: null, postpublish: params.hooks?.postpublish }
for (let index = 0; index < partnerIDs.length; index++) {
const hooks = index < partnerIDs.length - 1 ? undefined : { prepublish: null, postpublish: params.hooks?.postpublish }

// Share the keys to the newly created chatroom with partners
// TODO: We need to handle multiple groups and the possibility of not
// having any groups in common
await sbp('gi.actions/out/shareVolatileKeys', {
contractID: profile.contractID,
contractID: partnerIDs[index],
contractName: 'gi.contracts/identity',
subjectContractID: message.contractID(),
keyIds: '*'
})

await sbp('gi.actions/identity/joinDirectMessage', {
...omit(params, ['options', 'contractID', 'data', 'hooks']),
contractID: profile.contractID,
contractID: partnerIDs[index],
data: {
groupContractID: currentGroupId,
// TODO: We need to handle multiple groups and the possibility of not
Expand All @@ -662,7 +665,7 @@ export default (sbp('sbp/selectors/register', {
},
// For now, we assume that we're messaging someone which whom we
// share a group
signingKeyId: sbp('chelonia/contract/suitableSigningKey', profile.contractID, [GIMessage.OP_ACTION_ENCRYPTED], ['sig'], undefined, ['gi.contracts/identity/joinDirectMessage']),
signingKeyId: sbp('chelonia/contract/suitableSigningKey', partnerIDs[index], [GIMessage.OP_ACTION_ENCRYPTED], ['sig'], undefined, ['gi.contracts/identity/joinDirectMessage']),
innerSigningContractID: rootState.currentGroupId,
hooks
})
Expand Down
8 changes: 4 additions & 4 deletions frontend/controller/actions/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ export const encryptedNotification = (
}
}

export async function createInvite ({ quantity = 1, creator, expires, invitee }: {
quantity: number, creator: string, expires: number, invitee?: string
}): Promise<{inviteKeyId: string; creator: string; invitee?: string; }> {
export async function createInvite ({ quantity = 1, creatorID, expires, invitee }: {
quantity: number, creatorID: string, expires: number, invitee?: string
}): Promise<{inviteKeyId: string; creatorID: string; invitee?: string; }> {
const rootState = sbp('state/vuex/state')

if (!rootState.currentGroupId) {
Expand Down Expand Up @@ -308,7 +308,7 @@ export async function createInvite ({ quantity = 1, creator, expires, invitee }:

return {
inviteKeyId,
creator,
creatorID,
invitee
}
}
4 changes: 2 additions & 2 deletions frontend/controller/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ const loginGuard = {

const inviteGuard = {
guard: (to, from) => {
// ex: http://localhost:8000/app/join?groupId=21XWnNRE7vggw4ngGqmQz5D4vAwPYqcREhEkGop2mYZTKVkx8H&secret=5157
return !(to.query.groupId && to.query.secret)
// ex: http://localhost:8000/app/join#groupId=21XWnNRE7vggw4ngGqmQz5D4vAwPYqcREhEkGop2mYZTKVkx8H&secret=5157
return !(to.hash.includes('groupId=') && to.hash.includes('secret='))
},
redirect: (to, from) => ({ path: '/' })
}
Expand Down
10 changes: 5 additions & 5 deletions frontend/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ async function startApp () {
allowedSelectors: [
'namespace/lookup',
'state/vuex/state', 'state/vuex/settings', 'state/vuex/commit', 'state/vuex/getters',
'chelonia/contract/sync', 'chelonia/contract/isSyncing', 'chelonia/contract/remove', 'controller/router',
'chelonia/contract/sync', 'chelonia/contract/isSyncing', 'chelonia/contract/remove', 'chelonia/contract/cancelRemove', 'controller/router',
'chelonia/contract/suitableSigningKey', 'chelonia/contract/currentKeyIdByName',
'chelonia/storeSecretKeys', 'chelonia/crypto/keyId',
'chelonia/queueInvocation',
'chelonia/contract/waitingForKeyShareTo',
'chelonia/contract/successfulKeySharesByContractID',
'gi.actions/chatroom/leave',
'gi.actions/group/removeOurselves',
'gi.actions/group/groupProfileUpdate', 'gi.actions/group/displayMincomeChangedPrompt', 'gi.actions/group/addChatRoom',
'gi.actions/group/removeOurselves', 'gi.actions/group/groupProfileUpdate', 'gi.actions/group/displayMincomeChangedPrompt', 'gi.actions/group/addChatRoom',
'gi.actions/group/join', 'gi.actions/group/joinChatRoom',
'gi.actions/identity/addJoinDirectMessageKey', 'gi.actions/identity/leaveGroup',
'gi.notifications/emit',
Expand Down Expand Up @@ -149,10 +149,10 @@ async function startApp () {
errorNotification('handleEvent', e, message)
}
},
processError: (e: Error, message: GIMessage) => {
processError: (e: Error, message: GIMessage, msgMeta: { signingKeyId: string, signingContractID: string, innerSigningKeyId: string, innerSigningContractID: string }) => {
if (e.name === 'GIErrorIgnoreAndBan') {
sbp('okTurtles.eventQueue/queueEvent', message.contractID(), [
'gi.actions/group/autobanUser', message, e
'gi.actions/group/autobanUser', message, e, msgMeta
])
}
// For now, we ignore all missing keys errors
Expand Down
Loading

0 comments on commit f8cac66

Please sign in to comment.