CreateSharedVaultFileValetToken.spec.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
  2. import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
  3. import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
  4. import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
  5. import { SharedVault } from '../../../SharedVault/SharedVault'
  6. import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
  7. import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
  8. describe('CreateSharedVaultFileValetToken', () => {
  9. let sharedVaultRepository: SharedVaultRepositoryInterface
  10. let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
  11. let tokenEncoder: TokenEncoderInterface<SharedVaultValetTokenData>
  12. const valetTokenTTL = 3600
  13. let sharedVault: SharedVault
  14. let sharedVaultUser: SharedVaultUser
  15. const createUseCase = () =>
  16. new CreateSharedVaultFileValetToken(sharedVaultRepository, sharedVaultUserRepository, tokenEncoder, valetTokenTTL)
  17. beforeEach(() => {
  18. sharedVault = SharedVault.create({
  19. fileUploadBytesUsed: 2,
  20. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  21. timestamps: Timestamps.create(123, 123).getValue(),
  22. }).getValue()
  23. sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
  24. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(sharedVault)
  25. sharedVaultUser = SharedVaultUser.create({
  26. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
  27. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  28. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  29. timestamps: Timestamps.create(123, 123).getValue(),
  30. }).getValue()
  31. sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
  32. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
  33. tokenEncoder = {} as jest.Mocked<TokenEncoderInterface<SharedVaultValetTokenData>>
  34. tokenEncoder.encodeExpirableToken = jest.fn().mockReturnValue('encoded-token')
  35. })
  36. it('should return error when shared vault uuid is invalid', async () => {
  37. const useCase = createUseCase()
  38. const result = await useCase.execute({
  39. userUuid: '00000000-0000-0000-0000-000000000000',
  40. sharedVaultUuid: 'invalid-uuid',
  41. remoteIdentifier: 'remote-identifier',
  42. operation: ValetTokenOperation.Read,
  43. })
  44. expect(result.isFailed()).toBe(true)
  45. expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
  46. })
  47. it('should return error when user uuid is invalid', async () => {
  48. const useCase = createUseCase()
  49. const result = await useCase.execute({
  50. userUuid: 'invalid-uuid',
  51. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  52. remoteIdentifier: 'remote-identifier',
  53. operation: ValetTokenOperation.Read,
  54. })
  55. expect(result.isFailed()).toBe(true)
  56. expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
  57. })
  58. it('should return error when shared vault is not found', async () => {
  59. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(null)
  60. const useCase = createUseCase()
  61. const result = await useCase.execute({
  62. userUuid: '00000000-0000-0000-0000-000000000000',
  63. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  64. remoteIdentifier: 'remote-identifier',
  65. operation: ValetTokenOperation.Read,
  66. })
  67. expect(result.isFailed()).toBe(true)
  68. expect(result.getError()).toBe('Shared vault not found')
  69. })
  70. it('should return error when shared vault user is not found', async () => {
  71. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
  72. const useCase = createUseCase()
  73. const result = await useCase.execute({
  74. userUuid: '00000000-0000-0000-0000-000000000000',
  75. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  76. remoteIdentifier: 'remote-identifier',
  77. operation: ValetTokenOperation.Read,
  78. })
  79. expect(result.isFailed()).toBe(true)
  80. expect(result.getError()).toBe('Shared vault user not found')
  81. })
  82. it('should return error when shared vault user does not have permission', async () => {
  83. const useCase = createUseCase()
  84. const result = await useCase.execute({
  85. userUuid: '00000000-0000-0000-0000-000000000000',
  86. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  87. remoteIdentifier: 'remote-identifier',
  88. operation: ValetTokenOperation.Write,
  89. })
  90. expect(result.isFailed()).toBe(true)
  91. expect(result.getError()).toBe('User does not have permission to perform this operation')
  92. })
  93. it('should create a shared vault file valet token', async () => {
  94. sharedVaultUser = SharedVaultUser.create({
  95. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  96. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  97. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  98. timestamps: Timestamps.create(123, 123).getValue(),
  99. }).getValue()
  100. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
  101. const useCase = createUseCase()
  102. const result = await useCase.execute({
  103. userUuid: '00000000-0000-0000-0000-000000000000',
  104. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  105. remoteIdentifier: 'remote-identifier',
  106. operation: ValetTokenOperation.Write,
  107. })
  108. expect(result.isFailed()).toBe(false)
  109. expect(result.getValue()).toBe('encoded-token')
  110. })
  111. describe('move operation', () => {
  112. beforeEach(() => {
  113. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  114. .fn()
  115. .mockReturnValueOnce(
  116. SharedVaultUser.create({
  117. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  118. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  119. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  120. timestamps: Timestamps.create(123, 123).getValue(),
  121. }).getValue(),
  122. )
  123. .mockReturnValueOnce(
  124. SharedVaultUser.create({
  125. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
  126. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  127. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  128. timestamps: Timestamps.create(123, 123).getValue(),
  129. }).getValue(),
  130. )
  131. })
  132. it('should return error when move operation type is not specified', async () => {
  133. const useCase = createUseCase()
  134. const result = await useCase.execute({
  135. userUuid: '00000000-0000-0000-0000-000000000000',
  136. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  137. remoteIdentifier: 'remote-identifier',
  138. operation: ValetTokenOperation.Move,
  139. })
  140. expect(result.isFailed()).toBe(true)
  141. expect(result.getError()).toBe('Move operation type is required')
  142. })
  143. it('should return error when target uuid is missing on a shared-vault-to-shared-vault move operation', async () => {
  144. const useCase = createUseCase()
  145. const result = await useCase.execute({
  146. userUuid: '00000000-0000-0000-0000-000000000000',
  147. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  148. remoteIdentifier: 'remote-identifier',
  149. operation: ValetTokenOperation.Move,
  150. moveOperationType: 'shared-vault-to-shared-vault',
  151. })
  152. expect(result.isFailed()).toBe(true)
  153. expect(result.getError()).toBe('Shared vault to shared vault move target uuid is required')
  154. })
  155. it('should return error when target uuid is invalid on a shared-vault-to-shared-vault move operation', async () => {
  156. const useCase = createUseCase()
  157. const result = await useCase.execute({
  158. userUuid: '00000000-0000-0000-0000-000000000000',
  159. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  160. remoteIdentifier: 'remote-identifier',
  161. operation: ValetTokenOperation.Move,
  162. moveOperationType: 'shared-vault-to-shared-vault',
  163. sharedVaultToSharedVaultMoveTargetUuid: 'invalid-uuid',
  164. })
  165. expect(result.isFailed()).toBe(true)
  166. expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
  167. })
  168. it('should return error when target shared vault user is not found on a shared-vault-to-shared-vault move operation', async () => {
  169. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  170. .fn()
  171. .mockReturnValueOnce(
  172. SharedVaultUser.create({
  173. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  174. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  175. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  176. timestamps: Timestamps.create(123, 123).getValue(),
  177. }).getValue(),
  178. )
  179. .mockReturnValueOnce(null)
  180. const useCase = createUseCase()
  181. const result = await useCase.execute({
  182. userUuid: '00000000-0000-0000-0000-000000000000',
  183. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  184. remoteIdentifier: 'remote-identifier',
  185. operation: ValetTokenOperation.Move,
  186. moveOperationType: 'shared-vault-to-shared-vault',
  187. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  188. })
  189. expect(result.isFailed()).toBe(true)
  190. expect(result.getError()).toBe('Shared vault target user not found')
  191. })
  192. it('should return error when target shared vault user does not have permission on a shared-vault-to-shared-vault move operation', async () => {
  193. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  194. .fn()
  195. .mockReturnValueOnce(
  196. SharedVaultUser.create({
  197. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  198. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  199. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  200. timestamps: Timestamps.create(123, 123).getValue(),
  201. }).getValue(),
  202. )
  203. .mockReturnValueOnce(
  204. SharedVaultUser.create({
  205. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
  206. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  207. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  208. timestamps: Timestamps.create(123, 123).getValue(),
  209. }).getValue(),
  210. )
  211. const useCase = createUseCase()
  212. const result = await useCase.execute({
  213. userUuid: '00000000-0000-0000-0000-000000000000',
  214. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  215. remoteIdentifier: 'remote-identifier',
  216. operation: ValetTokenOperation.Move,
  217. moveOperationType: 'shared-vault-to-shared-vault',
  218. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  219. })
  220. expect(result.isFailed()).toBe(true)
  221. expect(result.getError()).toBe('User does not have permission to perform this operation')
  222. })
  223. it('should return error when target shared vault does not exist for shared-vault-to-shared-vault move operation', async () => {
  224. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValueOnce(sharedVault).mockResolvedValueOnce(null)
  225. const useCase = createUseCase()
  226. const result = await useCase.execute({
  227. userUuid: '00000000-0000-0000-0000-000000000000',
  228. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  229. remoteIdentifier: 'remote-identifier',
  230. operation: ValetTokenOperation.Move,
  231. moveOperationType: 'shared-vault-to-shared-vault',
  232. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  233. })
  234. expect(result.isFailed()).toBe(true)
  235. expect(result.getError()).toBe('Target shared vault not found')
  236. })
  237. it('should create move valet token for shared-vault-to-shared-vault operation', async () => {
  238. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  239. .fn()
  240. .mockReturnValueOnce(
  241. SharedVaultUser.create({
  242. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  243. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  244. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  245. timestamps: Timestamps.create(123, 123).getValue(),
  246. }).getValue(),
  247. )
  248. .mockReturnValueOnce(
  249. SharedVaultUser.create({
  250. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  251. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  252. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  253. timestamps: Timestamps.create(123, 123).getValue(),
  254. }).getValue(),
  255. )
  256. const useCase = createUseCase()
  257. const result = await useCase.execute({
  258. userUuid: '00000000-0000-0000-0000-000000000000',
  259. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  260. remoteIdentifier: 'remote-identifier',
  261. operation: ValetTokenOperation.Move,
  262. moveOperationType: 'shared-vault-to-shared-vault',
  263. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  264. })
  265. expect(result.isFailed()).toBe(false)
  266. expect(result.getValue()).toBe('encoded-token')
  267. })
  268. it('should create move valet token for shared-vault-to-user operation', async () => {
  269. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  270. .fn()
  271. .mockReturnValueOnce(
  272. SharedVaultUser.create({
  273. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  274. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  275. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  276. timestamps: Timestamps.create(123, 123).getValue(),
  277. }).getValue(),
  278. )
  279. .mockReturnValueOnce(
  280. SharedVaultUser.create({
  281. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  282. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  283. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  284. timestamps: Timestamps.create(123, 123).getValue(),
  285. }).getValue(),
  286. )
  287. const useCase = createUseCase()
  288. const result = await useCase.execute({
  289. userUuid: '00000000-0000-0000-0000-000000000000',
  290. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  291. remoteIdentifier: 'remote-identifier',
  292. operation: ValetTokenOperation.Move,
  293. moveOperationType: 'shared-vault-to-user',
  294. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  295. })
  296. expect(result.isFailed()).toBe(false)
  297. expect(result.getValue()).toBe('encoded-token')
  298. })
  299. it('should create move valet token for user-to-shared-vault operation', async () => {
  300. sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
  301. .fn()
  302. .mockReturnValueOnce(
  303. SharedVaultUser.create({
  304. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  305. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  306. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  307. timestamps: Timestamps.create(123, 123).getValue(),
  308. }).getValue(),
  309. )
  310. .mockReturnValueOnce(
  311. SharedVaultUser.create({
  312. permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
  313. sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  314. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  315. timestamps: Timestamps.create(123, 123).getValue(),
  316. }).getValue(),
  317. )
  318. const useCase = createUseCase()
  319. const result = await useCase.execute({
  320. userUuid: '00000000-0000-0000-0000-000000000000',
  321. sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
  322. remoteIdentifier: 'remote-identifier',
  323. operation: ValetTokenOperation.Move,
  324. moveOperationType: 'user-to-shared-vault',
  325. sharedVaultToSharedVaultMoveTargetUuid: '00000000-0000-0000-0000-000000000000',
  326. })
  327. expect(result.isFailed()).toBe(false)
  328. expect(result.getValue()).toBe('encoded-token')
  329. })
  330. })
  331. })