Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should not access group after being leaved #1728

Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
aba617c
fix: error to access group after being kicked
Silver-IT Sep 18, 2023
85b2859
Merge branch 'e2e-protocol' into 1716-should-not-be-accessible-to-the…
Silver-IT Sep 22, 2023
fde1026
Merge branch 'e2e-protocol' into 1716-should-not-be-accessible-to-the…
Silver-IT Sep 24, 2023
8c9a05b
fix: resolved conflicts
Silver-IT Oct 6, 2023
1a05f9f
fix: errors in login process
Silver-IT Oct 23, 2023
9658650
fix: error in importing file
Silver-IT Oct 23, 2023
a791fb6
feat: remove unnecessary variables
Silver-IT Oct 23, 2023
5b81bcb
fix: error in login process after being removed
Silver-IT Oct 24, 2023
5f8d495
fix: simplified codes
Silver-IT Oct 25, 2023
318d313
fix: should wait until contracts are fully removed
Silver-IT Oct 26, 2023
e5a8c96
fix: error in working with queue invocations
Silver-IT Oct 26, 2023
ec5002b
wip: fix error while logging in after leaving group
Silver-IT Oct 26, 2023
74be27a
npm: recovered lost package.json
Silver-IT Oct 27, 2023
957bcbf
fix: wrong params of package
Silver-IT Oct 27, 2023
793cb87
wip: fixing login issue
Silver-IT Oct 30, 2023
9c717db
fix: login issues
Silver-IT Nov 6, 2023
8826ed5
chore: added comment
Silver-IT Nov 6, 2023
8f7519c
fix: error
Silver-IT Nov 6, 2023
433f2ff
fix: login issue regarding join after leaving
Silver-IT Nov 8, 2023
f30bbc0
fix: renamed function to get vuex state
Silver-IT Nov 8, 2023
88cb305
fix: error in chelonia
Silver-IT Nov 9, 2023
c2cada5
fix: error handling intermediate undefined
Silver-IT Nov 9, 2023
7c997c3
fix: error in using variable name
Silver-IT Nov 9, 2023
45d056e
wip: fixing unauthorized error
Silver-IT Nov 9, 2023
255f1ac
fix: error in chelonia
Silver-IT Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/0.2.0/group-slim.js
Original file line number Diff line number Diff line change
Expand Up @@ -8686,7 +8686,7 @@ ${this.getErrorInfo()}`;
const rootState = (0, import_sbp6.default)("state/vuex/state");
const username = data.username || meta.username;
if (username === rootState.loggedIn.username) {
if (!(0, import_sbp6.default)("okTurtles.data/get", "JOINING_GROUP-" + contractID) || (0, import_sbp6.default)("okTurtles.data/get", "JOINING_GROUP_CHAT")) {
if (!(0, import_sbp6.default)("okTurtles.data/get", "JOINING_GROUP-" + contractID)) {
await (0, import_sbp6.default)("chelonia/contract/sync", data.chatRoomID);
(0, import_sbp6.default)("okTurtles.data/set", "JOINING_GROUP_CHAT", false);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/0.2.0/group.0.2.0.manifest.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"head":{"manifestVersion":"1.0.0"},"body":"{\"version\":\"0.2.0\",\"contract\":{\"hash\":\"21XWnNFFQqoQ2fFncUoEPYCnKyaPuZKVYBxRdR6nY9MypMVyQu\",\"file\":\"group.js\"},\"authors\":[{\"cipher\":\"algo\",\"key\":\"<pubkey from deploy-key.json>\"},{\"cipher\":\"algo\",\"key\":\"<pubkey from alex.json>\"}],\"contractSlim\":{\"file\":\"group-slim.js\",\"hash\":\"21XWnNUobHkRALuMvw7jNjkr3o1sWc4YJufJhEg1wDo1ECuy8L\"}}","signature":{"key":"<which of the 'authors' keys was used to sign 'body'>","signature":"<signature>"}}
{"head":{"manifestVersion":"1.0.0"},"body":"{\"version\":\"0.2.0\",\"contract\":{\"hash\":\"21XWnNQEJ99hZpm3nYM3AQUVC8UaijF9PATgMZ5JF3SB3N2Zii\",\"file\":\"group.js\"},\"authors\":[{\"cipher\":\"algo\",\"key\":\"<pubkey from deploy-key.json>\"},{\"cipher\":\"algo\",\"key\":\"<pubkey from alex.json>\"}],\"contractSlim\":{\"file\":\"group-slim.js\",\"hash\":\"21XWnNKefZtYza1ztkLCgPYkroEiSLqq8153xuRQX2dEpw7NSr\"}}","signature":{"key":"<which of the 'authors' keys was used to sign 'body'>","signature":"<signature>"}}
2 changes: 1 addition & 1 deletion contracts/0.2.0/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -17807,7 +17807,7 @@ ${this.getErrorInfo()}`;
const rootState = (0, import_sbp7.default)("state/vuex/state");
const username = data.username || meta.username;
if (username === rootState.loggedIn.username) {
if (!(0, import_sbp7.default)("okTurtles.data/get", "JOINING_GROUP-" + contractID) || (0, import_sbp7.default)("okTurtles.data/get", "JOINING_GROUP_CHAT")) {
if (!(0, import_sbp7.default)("okTurtles.data/get", "JOINING_GROUP-" + contractID)) {
await (0, import_sbp7.default)("chelonia/contract/sync", data.chatRoomID);
(0, import_sbp7.default)("okTurtles.data/set", "JOINING_GROUP_CHAT", false);
}
Expand Down
37 changes: 18 additions & 19 deletions frontend/controller/actions/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,17 +314,29 @@ export default (sbp('sbp/selectors/register', {
// secret keys to be shared with us, (b) ready to call the inviteAccept
// action if we haven't done so yet (because we were previously waiting for
// the keys), or (c) already a member and ready to interact with the group.
'gi.actions/group/join': async function (params: $Exact<ChelKeyRequestParams> & { options?: { skipUsableKeysCheck?: boolean; skipInviteAccept?: boolean } }) {
sbp('okTurtles.data/set', 'JOINING_GROUP-' + params.contractID, true)
'gi.actions/group/join': async function (params: $Exact<ChelKeyRequestParams> & { options?: { skipUsableKeysCheck?: boolean } }) {
try {
const rootState = sbp('state/vuex/state')
const username = rootState.loggedIn.username
const userID = rootState.loggedIn.identityContractID

console.log('@@@@@@@@ AT join for ' + params.contractID)

const isJoiningGroup = !!params.originatingContractID
const preEffectBeforeSync = isJoiningGroup
? () => { sbp('okTurtles.data/set', 'JOINING_GROUP-' + params.contractID, true) }
: () => {}
const postEffectAfterSync = isJoiningGroup
? () => { sbp('okTurtles.data/set', 'JOINING_GROUP-' + params.contractID, false) }
: () => {}

preEffectBeforeSync()
SebinSong marked this conversation as resolved.
Show resolved Hide resolved
await sbp('chelonia/contract/sync', params.contractID)
if (rootState.contracts[params.contractID]?.type !== 'gi.contracts/group') {
postEffectAfterSync()

if (!rootState.contracts[params.contractID]) {
// NOTE: already kicked from the group by someone else
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return looks like it'd fix the issue

} else if (rootState.contracts[params.contractID]?.type !== 'gi.contracts/group') {
throw Error(`Contract ${params.contractID} is not a group`)
}

Expand All @@ -341,7 +353,7 @@ export default (sbp('sbp/selectors/register', {
// params.originatingContractID is set, it means that we're joining
// through an invite link, and we must send a key request to complete
// the joining process.
const sendKeyRequest = (!hasSecretKeys && params.originatingContractID)
const sendKeyRequest = (!hasSecretKeys && isJoiningGroup)

// If we are expecting to receive keys, set up an event listener
// We are expecting to receive keys if:
Expand Down Expand Up @@ -520,8 +532,6 @@ export default (sbp('sbp/selectors/register', {
console.info('found unsynced identity contracts to sync:', missingIDs)
await sbp('chelonia/contract/sync', missingIDs)
}

sbp('okTurtles.data/set', 'JOINING_GROUP-' + params.contractID, false)
// We have already sent a key request that hasn't been answered. We cannot
// do much at this point, so we do nothing.
// This could happen, for example, after logging in if we still haven't
Expand All @@ -536,7 +546,7 @@ export default (sbp('sbp/selectors/register', {
saveLoginState('joining', params.contractID)
}
},
'gi.actions/group/joinAndSwitch': async function (params: $Exact<ChelKeyRequestParams> & { options?: { skipUsableKeysCheck?: boolean; skipInviteAccept: boolean } }) {
'gi.actions/group/joinAndSwitch': async function (params: $Exact<ChelKeyRequestParams> & { options?: { skipUsableKeysCheck?: boolean } }) {
await sbp('gi.actions/group/join', params)
// after joining, we can set the current group
sbp('gi.actions/group/switch', params.contractID)
Expand Down Expand Up @@ -685,17 +695,6 @@ export default (sbp('sbp/selectors/register', {
}
})

if (username === me) {
// 'JOINING_GROUP_CHAT' is necessary to identify the joining chatroom action is NEW or OLD
// Users join the chatroom thru group making group actions
// But when user joins the group, he needs to ignore all the actions about chatroom
// Because the user is joining group, not joining chatroom
// and he is going to make a new action to join 'General' chatroom AGAIN
// While joining group, we don't set this flag because Joining chatroom actions are all OLD ones, which need to be ignored
// Joining 'General' chatroom is one of the steps to join group
// So setting 'JOINING_GROUP_CHAT' can not be out of the 'JOINING_GROUP' scope
sbp('okTurtles.data/set', 'JOINING_GROUP_CHAT', true)
}
await sendMessage({
...omit(params, ['options', 'action', 'hooks']),
hooks: {
Expand Down
38 changes: 22 additions & 16 deletions frontend/controller/actions/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import { GIErrorUIRuntimeError, L, LError } from '@common/common.js'
import {
CHATROOM_PRIVACY_LEVEL,
CHATROOM_TYPES
CHATROOM_TYPES,
PROFILE_STATUS
} from '@model/contracts/shared/constants.js'
import { difference, omit, pickWhere, uniq } from '@model/contracts/shared/giLodash.js'
import sbp from '@sbp/sbp'
Expand Down Expand Up @@ -294,7 +295,7 @@ export default (sbp('sbp/selectors/register', {
console.info('synchronizing login state:', { groupsJoined })
for (const contractID of groupsJoined) {
try {
await sbp('gi.actions/group/join', { contractID, options: { skipInviteAccept: true } })
await sbp('gi.actions/group/join', { contractID })
} catch (e) {
console.error(`updateLoginStateUponLogin: ${e.name} attempting to join group ${contractID}`, e)
if (state.contracts[contractID] || state[contractID]) {
Expand Down Expand Up @@ -373,6 +374,9 @@ export default (sbp('sbp/selectors/register', {
const groupsToRejoin = []
// login can be called when no settings are saved (e.g. from Signup.vue)
if (state) {
if (!username) {
username = state.loggedIn.username
}
// The retrieved local data might need to be completed in case it was originally saved
// under an older version of the app where fewer/other Vuex modules were implemented.
sbp('state/vuex/postUpgradeVerification', state)
Expand All @@ -389,8 +393,8 @@ export default (sbp('sbp/selectors/register', {
// (1) We're looking for group contracts
state.contracts[contractID].type === 'gi.contracts/group' &&
// (2) That potentially haven't been joined by us
// (in which case state.profiles?.[username] will be undefined)
!state.profiles?.[username]
// (in which case state[contractID].profiles?.[username] will be undefined)
!state[contractID].profiles?.[username]
)
}))
}
Expand Down Expand Up @@ -437,9 +441,9 @@ export default (sbp('sbp/selectors/register', {

throw new Error('Unable to sync identity contract')
}).then(() =>
sbp('chelonia/contract/sync', contractIDs).then(async function () {
// contract sync might've triggered an async call to /remove, so wait before proceeding
await sbp('chelonia/contract/wait', contractIDs)
sbp('chelonia/contract/sync', contractIDs, { force: true }).then(async function () {
// contract sync might've triggered an async call to /remove, so wait before proceeding
await sbp('chelonia/contract/wait', { waitSideEffect: true })
// similarly, since removeMember may have triggered saveOurLoginState asynchronously,
// we must re-sync our identity contract again to ensure we don't rejoin a group we
// were just kicked out of
Expand All @@ -453,15 +457,17 @@ export default (sbp('sbp/selectors/register', {
// Call 'gi.actions/group/join' on all groups which may need re-joining
await Promise.all(groupsToRejoin.map(groupId => {
return (
// (1) Check whether the contract exists (may have been removed
// after sync)
// (1) Check whether the contract exists (may have been removed after sync)
state.contracts[groupId] &&
// (2) Check whether the join process is still incomplete
// This needs to be re-checked because it may have changed after
// sync
!state.profiles?.[username] &&
// (3) Call join
sbp('gi.actions/group/join', { contractID: groupId, contractName: 'gi.contracts/group' })
// (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] &&
// (3) Call join
sbp('gi.actions/group/join', {
contractID: groupId,
contractName: 'gi.contracts/group'
// TODO: consider to add 'originatingContractID' parameter here
})
)
}))

Expand All @@ -471,7 +477,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]) {
if (state[cId]?.profiles?.[username]?.status === PROFILE_STATUS.ACTIVE) {
sbp('gi.actions/group/updateLastLoggedIn', { contractID: cId }).catch(console.error)
}
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/model/contracts/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,7 @@ sbp('chelonia/defineContract', {
const rootState = sbp('state/vuex/state')
const username = data.username || meta.username
if (username === rootState.loggedIn.username) {
if (!sbp('okTurtles.data/get', 'JOINING_GROUP-' + contractID) || sbp('okTurtles.data/get', 'JOINING_GROUP_CHAT')) {
if (!sbp('okTurtles.data/get', 'JOINING_GROUP-' + contractID)) {
// while users are joining chatroom, they don't need to leave chatrooms
// this is similar to setting 'JOINING_GROUP' before joining group
await sbp('chelonia/contract/sync', data.chatRoomID)
Expand Down
2 changes: 1 addition & 1 deletion frontend/model/contracts/manifests.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifests": {
"gi.contracts/chatroom": "21XWnNJr1tLQM1XwNVBUxVCuKADSSJmXVK3DWShAEt6HJeAvD8",
"gi.contracts/group": "21XWnNHZDdLhYw8tYLsEENxoPVTSa3PfAyJLyxk8WGspEiEzJe",
"gi.contracts/group": "21XWnNRjkvyAZXw2tipBUpMGbcRat48vAz4iQt2BC5MDxucQSE",
"gi.contracts/identity": "21XWnNSxNrVFTMBCUVcZV3CG833gTbJ9V8ZyX7Fxgmpj9rNy4r"
}
}
13 changes: 10 additions & 3 deletions shared/domains/chelonia/chelonia.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,13 +519,20 @@ export default (sbp('sbp/selectors/register', {
}
},
// resolves when all pending actions for these contractID(s) finish
'chelonia/contract/wait': function (contractIDs?: string | string[]): Promise<*> {
'chelonia/contract/wait': function ({ contractIDs, waitSideEffect }: {
contractIDs?: string | string[],
waitSideEffect?: boolean
}): Promise<*> {
const listOfIds = contractIDs
? (typeof contractIDs === 'string' ? [contractIDs] : contractIDs)
: Object.keys(sbp(this.config.stateSelector).contracts)
return Promise.all(listOfIds.map(cID => {
return sbp('chelonia/queueInvocation', cID, ['chelonia/private/noop'])
}))
const invocations = [sbp('chelonia/queueInvocation', cID, ['chelonia/private/noop'])]
if (waitSideEffect) {
invocations.push(sbp('chelonia/queueInvocation', `sideEffect:${cID}`, ['chelonia/private/noop']))
}
return invocations
}).flat())
},
// 'chelonia/contract' - selectors related to injecting remote data and monitoring contracts
// TODO: add an optional parameter to "retain" the contract (see #828)
Expand Down