fix(syncing-server): race condition when adding admin user to newly created shared vault (#688)

This commit is contained in:
Karol Sójko 2023-08-08 11:02:10 +02:00 committed by GitHub
parent a1fe15f7a9
commit 3bd1547ce3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 6 deletions

View file

@ -19,7 +19,8 @@
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
"postversion": "./scripts/push-tags-one-by-one.sh",
"upgrade:snjs": "yarn workspaces foreach --verbose run upgrade:snjs",
"e2e": "yarn build packages/home-server && PORT=3123 yarn workspace @standardnotes/home-server start"
"e2e": "yarn build packages/home-server && PORT=3123 yarn workspace @standardnotes/home-server start",
"start": "yarn build packages/home-server && yarn workspace @standardnotes/home-server start"
},
"devDependencies": {
"@commitlint/cli": "^17.0.2",

View file

@ -115,4 +115,20 @@ describe('AddUserToSharedVault', () => {
expect(result.isFailed()).toBe(false)
expect(sharedVaultUserRepository.save).toHaveBeenCalled()
})
it('should add a user to a shared vault and skip checking if shared vault exists to avoid race conditions', async () => {
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValueOnce(null)
const useCase = createUseCase()
const result = await useCase.execute({
sharedVaultUuid: validUuid,
userUuid: validUuid,
permission: 'read',
skipSharedVaultExistenceCheck: true,
})
expect(result.isFailed()).toBe(false)
expect(sharedVaultUserRepository.save).toHaveBeenCalled()
})
})

View file

@ -20,9 +20,11 @@ export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const sharedVault = await this.sharedVaultRepository.findByUuid(sharedVaultUuid)
if (!sharedVault) {
return Result.fail('Attempting to add a shared vault user to a non-existent shared vault')
if (!dto.skipSharedVaultExistenceCheck) {
const sharedVault = await this.sharedVaultRepository.findByUuid(sharedVaultUuid)
if (!sharedVault) {
return Result.fail('Attempting to add a shared vault user to a non-existent shared vault')
}
}
const userUuidOrError = Uuid.create(dto.userUuid)

View file

@ -2,4 +2,5 @@ export interface AddUserToSharedVaultDTO {
sharedVaultUuid: string
userUuid: string
permission: string
skipSharedVaultExistenceCheck?: boolean
}

View file

@ -93,6 +93,7 @@ describe('CreateSharedVault', () => {
sharedVaultUuid: expect.any(String),
userUuid: '00000000-0000-0000-0000-000000000000',
permission: 'admin',
skipSharedVaultExistenceCheck: true,
})
expect(sharedVaultRepository.save).toHaveBeenCalled()
})

View file

@ -1,4 +1,12 @@
import { Result, RoleName, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
import {
Result,
RoleName,
SharedVaultUserPermission,
Timestamps,
UseCaseInterface,
Uuid,
Validator,
} from '@standardnotes/domain-core'
import { CreateSharedVaultResult } from './CreateSharedVaultResult'
import { CreateSharedVaultDTO } from './CreateSharedVaultDTO'
import { TimerInterface } from '@standardnotes/time'
@ -56,7 +64,8 @@ export class CreateSharedVault implements UseCaseInterface<CreateSharedVaultResu
const sharedVaultUserOrError = await this.addUserToSharedVault.execute({
sharedVaultUuid: sharedVault.id.toString(),
userUuid: dto.userUuid,
permission: 'admin',
permission: SharedVaultUserPermission.PERMISSIONS.Admin,
skipSharedVaultExistenceCheck: true,
})
if (sharedVaultUserOrError.isFailed()) {
return Result.fail(sharedVaultUserOrError.getError())