feat: add creating shared vault file valet tokens. (#635)

Co-authored-by: Mo <[email protected]>
This commit is contained in:
Karol Sójko
2023-07-03 18:43:32 +02:00
committed by GitHub
co-authored by Mo
parent bf84be0136
commit 04b3bb034f
7 changed files with 531 additions and 3 deletions
@@ -3,6 +3,12 @@ import { Result, ValueObject } from '@standardnotes/domain-core'
import { SharedVaultUserPermissionProps } from './SharedVaultUserPermissionProps'
export class SharedVaultUserPermission extends ValueObject<SharedVaultUserPermissionProps> {
static readonly PERMISSIONS = {
Read: 'read',
Write: 'write',
Admin: 'admin',
}
get value(): string {
return this.props.value
}
@@ -12,7 +18,8 @@ export class SharedVaultUserPermission extends ValueObject<SharedVaultUserPermis
}
static create(sharedVaultUserPermission: string): Result<SharedVaultUserPermission> {
if (!['read', 'write', 'admin'].includes(sharedVaultUserPermission)) {
const isValidPermission = Object.values(this.PERMISSIONS).includes(sharedVaultUserPermission)
if (!isValidPermission) {
return Result.fail<SharedVaultUserPermission>(`Invalid shared vault user permission ${sharedVaultUserPermission}`)
} else {
return Result.ok<SharedVaultUserPermission>(new SharedVaultUserPermission({ value: sharedVaultUserPermission }))
@@ -6,4 +6,5 @@ export interface SharedVaultUserRepositoryInterface {
findByUuid(sharedVaultUserUuid: Uuid): Promise<SharedVaultUser | null>
save(sharedVaultUser: SharedVaultUser): Promise<void>
remove(sharedVault: SharedVaultUser): Promise<void>
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>
}
@@ -0,0 +1,363 @@
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
describe('CreateSharedVaultFileValetToken', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let tokenEncoder: TokenEncoderInterface<SharedVaultValetTokenData>
const valetTokenTTL = 3600
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
const createUseCase = () =>
new CreateSharedVaultFileValetToken(sharedVaultRepository, sharedVaultUserRepository, tokenEncoder, valetTokenTTL)
beforeEach(() => {
sharedVault = SharedVault.create({
fileUploadBytesLimit: 100,
fileUploadBytesUsed: 2,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(sharedVault)
sharedVaultUser = SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
tokenEncoder = {} as jest.Mocked<TokenEncoderInterface<SharedVaultValetTokenData>>
tokenEncoder.encodeExpirableToken = jest.fn().mockReturnValue('encoded-token')
})
it('should return error when shared vault uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: 'invalid-uuid',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Read,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
})
it('should return error when user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid-uuid',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Read,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
})
it('should return error when shared vault is not found', async () => {
sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(null)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Read,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Shared vault not found')
})
it('should return error when shared vault user is not found', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Read,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Shared vault user not found')
})
it('should return error when shared vault user does not have permission', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Write,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('User does not have permission to perform this operation')
})
it('should create a shared vault file valet token', async () => {
sharedVaultUser = SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Write,
})
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe('encoded-token')
})
describe('move operation', () => {
beforeEach(() => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
})
it('should return error when move operation type is not specified', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Move operation type is required')
})
it('should return error when target uuid is missing on a shared-vault-to-shared-vault move operation', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-shared-vault',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Shared vault to shared vault move target uuid is required')
})
it('should return error when target uuid is invalid on a shared-vault-to-shared-vault move operation', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: 'invalid-uuid',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
})
it('should return error when target shared vault user is not found on a shared-vault-to-shared-vault move operation', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(null)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Shared vault target user not found')
})
it('should return error when target shared vault user does not have permission on a shared-vault-to-shared-vault move operation', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('User does not have permission to perform this operation')
})
it('should create move valet token for shared-vault-to-shared-vault operation', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe('encoded-token')
})
it('should create move valet token for shared-vault-to-user operation', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'shared-vault-to-user',
sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe('encoded-token')
})
it('should create move valet token for user-to-shared-vault operation', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
.mockReturnValueOnce(
SharedVaultUser.create({
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
remoteIdentifier: 'remote-identifier',
operation: ValetTokenOperation.Move,
moveOperationType: 'user-to-shared-vault',
sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe('encoded-token')
})
})
})
@@ -0,0 +1,124 @@
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { CreateSharedVaultFileValetTokenDTO } from './CreateSharedVaultFileValetTokenDTO'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
export class CreateSharedVaultFileValetToken implements UseCaseInterface<string> {
constructor(
private sharedVaultRepository: SharedVaultRepositoryInterface,
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private tokenEncoder: TokenEncoderInterface<SharedVaultValetTokenData>,
private valetTokenTTL: number,
) {}
async execute(dto: CreateSharedVaultFileValetTokenDTO): Promise<Result<string>> {
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const userUuidOrError = Uuid.create(dto.userUuid)
if (userUuidOrError.isFailed()) {
return Result.fail(userUuidOrError.getError())
}
const userUuid = userUuidOrError.getValue()
const sharedVault = await this.sharedVaultRepository.findByUuid(sharedVaultUuid)
if (!sharedVault) {
return Result.fail('Shared vault not found')
}
const sharedVaultUser = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
userUuid: userUuid,
sharedVaultUuid: sharedVaultUuid,
})
if (!sharedVaultUser) {
return Result.fail('Shared vault user not found')
}
if (
sharedVaultUser.props.permission.value === SharedVaultUserPermission.PERMISSIONS.Read &&
dto.operation !== ValetTokenOperation.Read
) {
return Result.fail('User does not have permission to perform this operation')
}
if (dto.operation === ValetTokenOperation.Move) {
if (!dto.moveOperationType) {
return Result.fail('Move operation type is required')
}
if (dto.moveOperationType === 'shared-vault-to-shared-vault') {
if (!dto.sharedVaultToSharedVaultMoveTargetUuid) {
return Result.fail('Shared vault to shared vault move target uuid is required')
}
const sharedVaultTargetUuidOrError = Uuid.create(dto.sharedVaultToSharedVaultMoveTargetUuid)
if (sharedVaultTargetUuidOrError.isFailed()) {
return Result.fail(sharedVaultTargetUuidOrError.getError())
}
const sharedVaultTargetUuid = sharedVaultTargetUuidOrError.getValue()
const toSharedVaultUser = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
userUuid: userUuid,
sharedVaultUuid: sharedVaultTargetUuid,
})
if (!toSharedVaultUser) {
return Result.fail('Shared vault target user not found')
}
if (toSharedVaultUser.props.permission.value === SharedVaultUserPermission.PERMISSIONS.Read) {
return Result.fail('User does not have permission to perform this operation')
}
}
}
const tokenData: SharedVaultValetTokenData = {
sharedVaultUuid: dto.sharedVaultUuid,
permittedOperation: dto.operation,
remoteIdentifier: dto.remoteIdentifier,
uploadBytesUsed: sharedVault.props.fileUploadBytesUsed,
uploadBytesLimit: sharedVault.props.fileUploadBytesLimit,
unencryptedFileSize: dto.unencryptedFileSize,
moveOperation: this.createMoveOperationData(dto),
}
const valetToken = this.tokenEncoder.encodeExpirableToken(tokenData, this.valetTokenTTL)
return Result.ok(valetToken)
}
private createMoveOperationData(dto: CreateSharedVaultFileValetTokenDTO): SharedVaultValetTokenData['moveOperation'] {
if (!dto.moveOperationType) {
return undefined
}
let fromUuid: string
let toUuid: string
switch (dto.moveOperationType) {
case 'shared-vault-to-user':
fromUuid = dto.sharedVaultUuid
toUuid = dto.userUuid
break
case 'user-to-shared-vault':
fromUuid = dto.userUuid
toUuid = dto.sharedVaultUuid
break
case 'shared-vault-to-shared-vault':
fromUuid = dto.sharedVaultUuid
toUuid = dto.sharedVaultToSharedVaultMoveTargetUuid as string
break
}
return {
type: dto.moveOperationType,
fromUuid,
toUuid,
}
}
}
@@ -0,0 +1,12 @@
import { SharedVaultMoveType, ValetTokenOperation } from '@standardnotes/security'
export interface CreateSharedVaultFileValetTokenDTO {
userUuid: string
sharedVaultUuid: string
fileUuid?: string
remoteIdentifier: string
operation: ValetTokenOperation
unencryptedFileSize?: number
moveOperationType?: SharedVaultMoveType
sharedVaultToSharedVaultMoveTargetUuid?: string
}
@@ -21,7 +21,7 @@ export class TypeORMSharedVaultRepository implements SharedVaultRepositoryInterf
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault')
.where('shared_vault.uuid = :uuid', {
uuid: uuid.toString(),
uuid: uuid.value,
})
.getOne()
@@ -11,6 +11,27 @@ export class TypeORMSharedVaultUserRepository implements SharedVaultUserReposito
private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
) {}
async findByUserUuidAndSharedVaultUuid(dto: {
userUuid: Uuid
sharedVaultUuid: Uuid
}): Promise<SharedVaultUser | null> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_user')
.where('shared_vault_user.user_uuid = :userUuid', {
userUuid: dto.userUuid.value,
})
.andWhere('shared_vault_user.shared_vault_uuid = :sharedVaultUuid', {
sharedVaultUuid: dto.sharedVaultUuid.value,
})
.getOne()
if (persistence === null) {
return null
}
return this.mapper.toDomain(persistence)
}
async save(sharedVaultUser: SharedVaultUser): Promise<void> {
const persistence = this.mapper.toProjection(sharedVaultUser)
@@ -21,7 +42,7 @@ export class TypeORMSharedVaultUserRepository implements SharedVaultUserReposito
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_user')
.where('shared_vault_user.uuid = :uuid', {
uuid: uuid.toString(),
uuid: uuid.value,
})
.getOne()