Compare commits

..

28 Commits

Author SHA1 Message Date
standardci
d1d6c753c4 chore(release): publish new version
- @standardnotes/analytics@2.26.6
 - @standardnotes/api-gateway@1.74.2
 - @standardnotes/auth-server@1.138.2
 - @standardnotes/domain-events-infra@1.12.23
 - @standardnotes/domain-events@2.124.0
 - @standardnotes/event-store@1.11.34
 - @standardnotes/files-server@1.22.13
 - @standardnotes/home-server@1.15.27
 - @standardnotes/revisions-server@1.33.0
 - @standardnotes/scheduler-server@1.20.38
 - @standardnotes/syncing-server@1.93.0
 - @standardnotes/websockets-server@1.10.35
2023-09-07 10:46:30 +00:00
Karol Sójko
3bd63f7674 feat: add removing revisions from shared vaults (#811) 2023-09-07 12:02:38 +02:00
standardci
376466d9b2 chore(release): publish new version
- @standardnotes/analytics@2.26.5
 - @standardnotes/api-gateway@1.74.1
 - @standardnotes/auth-server@1.138.1
 - @standardnotes/domain-core@1.28.0
 - @standardnotes/event-store@1.11.33
 - @standardnotes/files-server@1.22.12
 - @standardnotes/home-server@1.15.26
 - @standardnotes/revisions-server@1.32.0
 - @standardnotes/scheduler-server@1.20.37
 - @standardnotes/settings@1.21.30
 - @standardnotes/syncing-server@1.92.1
 - @standardnotes/websockets-server@1.10.34
2023-09-07 09:00:39 +00:00
Karol Sójko
e100c52bbc feat(revisions): fetching single revision in shared vault (#810)
* feat(revisions): fetching single revision in shared vault

* fix(revisions): mapping to http representation
2023-09-07 10:23:03 +02:00
Aman Harwara
d4830dec01 feat: add VaultsUser role name (#809)
* feat: add VaultsUser role name

* fix: test coverage
2023-09-07 08:07:06 +02:00
Karol Sójko
7e11821021 fix(revisions): query for shared vault revisions 2023-09-07 08:05:47 +02:00
standardci
4715e019a2 chore(release): publish new version
- @standardnotes/analytics@2.26.4
 - @standardnotes/api-gateway@1.74.0
 - @standardnotes/auth-server@1.138.0
 - @standardnotes/domain-core@1.27.0
 - @standardnotes/domain-events-infra@1.12.22
 - @standardnotes/domain-events@2.123.0
 - @standardnotes/event-store@1.11.32
 - @standardnotes/files-server@1.22.11
 - @standardnotes/home-server@1.15.25
 - @standardnotes/revisions-server@1.31.0
 - @standardnotes/scheduler-server@1.20.36
 - @standardnotes/security@1.13.0
 - @standardnotes/settings@1.21.29
 - @standardnotes/syncing-server@1.92.0
 - @standardnotes/websockets-server@1.10.33
2023-09-06 14:12:13 +00:00
Karol Sójko
794cd8734a feat: should be able to access shared item revisions as third party user (#807) 2023-09-06 15:36:23 +02:00
standardci
14d42b26bb chore(release): publish new version
- @standardnotes/websockets-server@1.10.32
2023-09-05 12:29:23 +00:00
Karol Sójko
6bb44afd91 fix(websockets): add missing region parameter in api gateway client 2023-09-05 13:50:30 +02:00
standardci
c82345aeeb chore(release): publish new version
- @standardnotes/websockets-server@1.10.31
2023-09-05 06:49:48 +00:00
Karol Sójko
72ab08a0d0 fix(websockets): issue with sending messages to active websocket connections (#806) 2023-09-05 08:13:42 +02:00
standardci
f2d1b47e40 chore(release): publish new version
- @standardnotes/home-server@1.15.24
 - @standardnotes/revisions-server@1.30.14
 - @standardnotes/syncing-server@1.91.3
2023-09-04 12:48:16 +00:00
Karol Sójko
d9ee2c5be2 fix: prevent doubling transitions 2023-09-04 14:10:37 +02:00
standardci
eb59902cf7 chore(release): publish new version
- @standardnotes/home-server@1.15.23
 - @standardnotes/revisions-server@1.30.13
 - @standardnotes/websockets-server@1.10.30
2023-09-04 11:11:04 +00:00
Karol Sójko
002074e4d1 fix(websockets): stringify response from the AWS Api Gateway 2023-09-04 12:32:47 +02:00
Karol Sójko
45b55068f9 fix(revisions): change logs severity in the transition process 2023-09-04 12:19:03 +02:00
Karol Sójko
157eee5d93 chore: increase mocha headless chrome global timeout 2023-09-04 12:06:49 +02:00
standardci
d5f2b4f6eb chore(release): publish new version
- @standardnotes/home-server@1.15.22
 - @standardnotes/revisions-server@1.30.12
 - @standardnotes/websockets-server@1.10.29
2023-09-04 10:05:10 +00:00
Karol Sójko
a7a93497e8 fix(revisions): change order field for transition of revisions 2023-09-04 10:56:14 +02:00
Karol Sójko
8f96f0ed7a fix(websockets): add response debug on websockets sending 2023-09-04 10:43:58 +02:00
standardci
3f064176f2 chore(release): publish new version
- @standardnotes/analytics@2.26.3
 - @standardnotes/api-gateway@1.73.7
 - @standardnotes/auth-server@1.137.6
 - @standardnotes/common@1.50.4
 - @standardnotes/domain-core@1.26.3
 - @standardnotes/domain-events-infra@1.12.21
 - @standardnotes/domain-events@2.122.2
 - @standardnotes/event-store@1.11.31
 - @standardnotes/files-server@1.22.10
 - @standardnotes/home-server@1.15.21
 - @standardnotes/predicates@1.6.11
 - @standardnotes/revisions-server@1.30.11
 - @standardnotes/scheduler-server@1.20.35
 - @standardnotes/security@1.12.2
 - @standardnotes/settings@1.21.28
 - @standardnotes/sncrypto-node@1.15.6
 - @standardnotes/syncing-server@1.91.2
 - @standardnotes/time@1.15.3
 - @standardnotes/websockets-server@1.10.28
2023-09-04 08:26:34 +00:00
Karol Sójko
c7b0c7dfa8 fix(websockets): add debug logs 2023-09-04 09:47:20 +02:00
Karol Sójko
df20dd46db fix(revisions): add more verbose logs to the transition 2023-09-04 09:05:54 +02:00
Karol Sójko
6dfd09989e chore: remove unused nodemon 2023-09-04 08:28:02 +02:00
Karol Sójko
fc821709e2 chore: upgrade docker build push action: 2023-09-04 08:24:39 +02:00
Karol Sójko
e986abaab5 chore: upgrade @types/uuid 2023-09-04 08:23:46 +02:00
Karol Sójko
a006fb3119 chore: upgrade typescript eslint plugin 2023-09-04 08:22:42 +02:00
206 changed files with 3514 additions and 1022 deletions

View File

@@ -90,7 +90,7 @@ jobs:
uses: docker/setup-buildx-action@master
- name: Publish Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ steps.bundle-dir.outputs.temp_dir }}

View File

@@ -57,7 +57,7 @@ jobs:
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
- name: Run E2E Test Suite
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html
- name: Show logs on failure
if: ${{ failure() }}
@@ -162,7 +162,7 @@ jobs:
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
- name: Run E2E Test Suite
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html
- name: Show logs on failure
if: ${{ failure() }}

View File

@@ -35,7 +35,7 @@ jobs:
uses: docker/setup-buildx-action@master
- name: Publish Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: .

760
.pnp.cjs generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.26.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.5...@standardnotes/analytics@2.26.6) (2023-09-07)
**Note:** Version bump only for package @standardnotes/analytics
## [2.26.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.4...@standardnotes/analytics@2.26.5) (2023-09-07)
**Note:** Version bump only for package @standardnotes/analytics
## [2.26.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.3...@standardnotes/analytics@2.26.4) (2023-09-06)
**Note:** Version bump only for package @standardnotes/analytics
## [2.26.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.2...@standardnotes/analytics@2.26.3) (2023-09-04)
**Note:** Version bump only for package @standardnotes/analytics
## [2.26.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.1...@standardnotes/analytics@2.26.2) (2023-09-01)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.26.2",
"version": "2.26.6",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -29,7 +29,7 @@
"@types/jest": "^29.5.1",
"@types/mixpanel": "^2.14.4",
"@types/node": "^20.5.7",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.74.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.1...@standardnotes/api-gateway@1.74.2) (2023-09-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.74.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.0...@standardnotes/api-gateway@1.74.1) (2023-09-07)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.74.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.73.7...@standardnotes/api-gateway@1.74.0) (2023-09-06)
### Features
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/api-gateway/issues/807)) ([794cd87](https://github.com/standardnotes/api-gateway/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
## [1.73.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.73.6...@standardnotes/api-gateway@1.73.7) (2023-09-04)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.73.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.73.5...@standardnotes/api-gateway@1.73.6) (2023-09-01)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.73.6",
"version": "1.74.2",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -54,12 +54,11 @@
"@types/jsonwebtoken": "^9.0.1",
"@types/node": "^20.5.7",
"@types/prettyjson": "^0.0.30",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"nodemon": "^2.0.19",
"npm-check-updates": "^16.13.2",
"prettier": "^3.0.3",
"ts-jest": "^29.1.0",

View File

@@ -72,6 +72,7 @@ export abstract class AuthMiddleware extends BaseMiddleware {
response.locals.session = decodedToken.session
response.locals.roles = decodedToken.roles
response.locals.sharedVaultOwnerContext = decodedToken.shared_vault_owner_context
response.locals.belongsToSharedVaults = decodedToken.belongs_to_shared_vaults ?? []
} catch (error) {
const errorMessage = (error as AxiosError).isAxiosError
? JSON.stringify((error as AxiosError).response?.data)

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.138.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.138.1...@standardnotes/auth-server@1.138.2) (2023-09-07)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.138.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.138.0...@standardnotes/auth-server@1.138.1) (2023-09-07)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.138.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.137.6...@standardnotes/auth-server@1.138.0) (2023-09-06)
### Features
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
## [1.137.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.137.5...@standardnotes/auth-server@1.137.6) (2023-09-04)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.137.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.137.4...@standardnotes/auth-server@1.137.5) (2023-09-01)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddSharedVaultUsers1694000575425 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
'CREATE TABLE `auth_shared_vault_users` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_auth_shared_vault_users` (`shared_vault_uuid`), INDEX `user_uuid_on_auth_shared_vault_users` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('DROP INDEX `user_uuid_on_auth_shared_vault_users` ON `auth_shared_vault_users`')
await queryRunner.query('DROP INDEX `shared_vault_uuid_on_auth_shared_vault_users` ON `auth_shared_vault_users`')
await queryRunner.query('DROP TABLE `auth_shared_vault_users`')
}
}

View File

@@ -0,0 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddSharedVaultUsers1694000640645 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
'CREATE TABLE "auth_shared_vault_users" ("uuid" varchar PRIMARY KEY NOT NULL, "shared_vault_uuid" varchar(36) NOT NULL, "user_uuid" varchar(36) NOT NULL, "permission" varchar(24) NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
)
await queryRunner.query(
'CREATE INDEX "shared_vault_uuid_on_auth_shared_vault_users" ON "auth_shared_vault_users" ("shared_vault_uuid") ',
)
await queryRunner.query(
'CREATE INDEX "user_uuid_on_auth_shared_vault_users" ON "auth_shared_vault_users" ("user_uuid") ',
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('DROP INDEX "user_uuid_on_auth_shared_vault_users"')
await queryRunner.query('DROP INDEX "shared_vault_uuid_on_auth_shared_vault_users"')
await queryRunner.query('DROP TABLE "auth_shared_vault_users"')
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.137.5",
"version": "1.138.2",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -84,13 +84,12 @@
"@types/otplib": "^10.0.0",
"@types/prettyjson": "^0.0.30",
"@types/ua-parser-js": "^0.7.36",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@types/uuid": "^9.0.3",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"nodemon": "^2.0.19",
"npm-check-updates": "^16.13.2",
"prettier": "^3.0.3",
"ts-jest": "^29.1.0",

View File

@@ -189,6 +189,7 @@ import {
ControllerContainer,
ControllerContainerInterface,
MapperInterface,
SharedVaultUser,
} from '@standardnotes/domain-core'
import { SessionTracePersistenceMapper } from '../Mapping/SessionTracePersistenceMapper'
import { SessionTrace } from '../Domain/Session/SessionTrace'
@@ -263,6 +264,14 @@ import { InMemoryTransitionStatusRepository } from '../Infra/InMemory/InMemoryTr
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
import { UpdateTransitionStatus } from '../Domain/UseCase/UpdateTransitionStatus/UpdateTransitionStatus'
import { GetTransitionStatus } from '../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
import { SharedVaultUserPersistenceMapper } from '../Mapping/SharedVaultUserPersistenceMapper'
import { SharedVaultUserRepositoryInterface } from '../Domain/SharedVault/SharedVaultUserRepositoryInterface'
import { TypeORMSharedVaultUserRepository } from '../Infra/TypeORM/TypeORMSharedVaultUserRepository'
import { AddSharedVaultUser } from '../Domain/UseCase/AddSharedVaultUser/AddSharedVaultUser'
import { RemoveSharedVaultUser } from '../Domain/UseCase/RemoveSharedVaultUser/RemoveSharedVaultUser'
import { UserAddedToSharedVaultEventHandler } from '../Domain/Handler/UserAddedToSharedVaultEventHandler'
import { UserRemovedFromSharedVaultEventHandler } from '../Domain/Handler/UserRemovedFromSharedVaultEventHandler'
export class ContainerConfigLoader {
async load(configuration?: {
@@ -372,6 +381,9 @@ export class ContainerConfigLoader {
container
.bind<MapperInterface<CacheEntry, TypeORMCacheEntry>>(TYPES.Auth_CacheEntryPersistenceMapper)
.toConstantValue(new CacheEntryPersistenceMapper())
container
.bind<MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>>(TYPES.Auth_SharedVaultUserPersistenceMapper)
.toConstantValue(new SharedVaultUserPersistenceMapper())
// ORM
container
@@ -412,6 +424,9 @@ export class ContainerConfigLoader {
container
.bind<Repository<TypeORMCacheEntry>>(TYPES.Auth_ORMCacheEntryRepository)
.toConstantValue(appDataSource.getRepository(TypeORMCacheEntry))
container
.bind<Repository<TypeORMSharedVaultUser>>(TYPES.Auth_ORMSharedVaultUserRepository)
.toConstantValue(appDataSource.getRepository(TypeORMSharedVaultUser))
// Repositories
container.bind<SessionRepositoryInterface>(TYPES.Auth_SessionRepository).to(TypeORMSessionRepository)
@@ -468,6 +483,16 @@ export class ContainerConfigLoader {
container.get(TYPES.Auth_CacheEntryPersistenceMapper),
),
)
container
.bind<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository)
.toConstantValue(
new TypeORMSharedVaultUserRepository(
container.get<Repository<TypeORMSharedVaultUser>>(TYPES.Auth_ORMSharedVaultUserRepository),
container.get<MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>>(
TYPES.Auth_SharedVaultUserPersistenceMapper,
),
),
)
// Middleware
container.bind<SessionMiddleware>(TYPES.Auth_SessionMiddleware).to(SessionMiddleware)
@@ -926,6 +951,18 @@ export class ContainerConfigLoader {
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
),
)
container
.bind<AddSharedVaultUser>(TYPES.Auth_AddSharedVaultUser)
.toConstantValue(
new AddSharedVaultUser(container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository)),
)
container
.bind<RemoveSharedVaultUser>(TYPES.Auth_RemoveSharedVaultUser)
.toConstantValue(
new RemoveSharedVaultUser(
container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository),
),
)
// Controller
container
@@ -1075,6 +1112,22 @@ export class ContainerConfigLoader {
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
container
.bind<UserAddedToSharedVaultEventHandler>(TYPES.Auth_UserAddedToSharedVaultEventHandler)
.toConstantValue(
new UserAddedToSharedVaultEventHandler(
container.get<AddSharedVaultUser>(TYPES.Auth_AddSharedVaultUser),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
container
.bind<UserRemovedFromSharedVaultEventHandler>(TYPES.Auth_UserRemovedFromSharedVaultEventHandler)
.toConstantValue(
new UserRemovedFromSharedVaultEventHandler(
container.get<RemoveSharedVaultUser>(TYPES.Auth_RemoveSharedVaultUser),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
['USER_REGISTERED', container.get(TYPES.Auth_UserRegisteredEventHandler)],
@@ -1107,6 +1160,8 @@ export class ContainerConfigLoader {
['EMAIL_SUBSCRIPTION_UNSUBSCRIBED', container.get(TYPES.Auth_EmailSubscriptionUnsubscribedEventHandler)],
['PAYMENTS_ACCOUNT_DELETED', container.get(TYPES.Auth_PaymentsAccountDeletedEventHandler)],
['TRANSITION_STATUS_UPDATED', container.get(TYPES.Auth_TransitionStatusUpdatedEventHandler)],
['USER_ADDED_TO_SHARED_VAULT', container.get(TYPES.Auth_UserAddedToSharedVaultEventHandler)],
['USER_REMOVED_FROM_SHARED_VAULT', container.get(TYPES.Auth_UserRemovedFromSharedVaultEventHandler)],
])
if (isConfiguredForHomeServer) {

View File

@@ -18,6 +18,7 @@ import { TypeORMEmergencyAccessInvitation } from '../Infra/TypeORM/TypeORMEmerge
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
import { Env } from './Env'
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
export class AppDataSource {
private _dataSource: DataSource | undefined
@@ -64,6 +65,7 @@ export class AppDataSource {
TypeORMAuthenticatorChallenge,
TypeORMEmergencyAccessInvitation,
TypeORMCacheEntry,
TypeORMSharedVaultUser,
],
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
migrationsRun: true,

View File

@@ -9,6 +9,7 @@ const TYPES = {
Auth_AuthenticatorPersistenceMapper: Symbol.for('Auth_AuthenticatorPersistenceMapper'),
Auth_AuthenticatorHttpMapper: Symbol.for('Auth_AuthenticatorHttpMapper'),
Auth_CacheEntryPersistenceMapper: Symbol.for('Auth_CacheEntryPersistenceMapper'),
Auth_SharedVaultUserPersistenceMapper: Symbol.for('Auth_SharedVaultUserPersistenceMapper'),
// Controller
Auth_ControllerContainer: Symbol.for('Auth_ControllerContainer'),
Auth_AuthController: Symbol.for('Auth_AuthController'),
@@ -36,6 +37,7 @@ const TYPES = {
Auth_AuthenticatorChallengeRepository: Symbol.for('Auth_AuthenticatorChallengeRepository'),
Auth_CacheEntryRepository: Symbol.for('Auth_CacheEntryRepository'),
Auth_TransitionStatusRepository: Symbol.for('Auth_TransitionStatusRepository'),
Auth_SharedVaultUserRepository: Symbol.for('Auth_SharedVaultUserRepository'),
// ORM
Auth_ORMOfflineSettingRepository: Symbol.for('Auth_ORMOfflineSettingRepository'),
Auth_ORMOfflineUserSubscriptionRepository: Symbol.for('Auth_ORMOfflineUserSubscriptionRepository'),
@@ -51,6 +53,7 @@ const TYPES = {
Auth_ORMAuthenticatorRepository: Symbol.for('Auth_ORMAuthenticatorRepository'),
Auth_ORMAuthenticatorChallengeRepository: Symbol.for('Auth_ORMAuthenticatorChallengeRepository'),
Auth_ORMCacheEntryRepository: Symbol.for('Auth_ORMCacheEntryRepository'),
Auth_ORMSharedVaultUserRepository: Symbol.for('Auth_ORMSharedVaultUserRepository'),
// Middleware
Auth_RequiredCrossServiceTokenMiddleware: Symbol.for('Auth_RequiredCrossServiceTokenMiddleware'),
Auth_OptionalCrossServiceTokenMiddleware: Symbol.for('Auth_OptionalCrossServiceTokenMiddleware'),
@@ -157,6 +160,8 @@ const TYPES = {
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
Auth_UpdateTransitionStatus: Symbol.for('Auth_UpdateTransitionStatus'),
Auth_GetTransitionStatus: Symbol.for('Auth_GetTransitionStatus'),
Auth_AddSharedVaultUser: Symbol.for('Auth_AddSharedVaultUser'),
Auth_RemoveSharedVaultUser: Symbol.for('Auth_RemoveSharedVaultUser'),
// Handlers
Auth_UserRegisteredEventHandler: Symbol.for('Auth_UserRegisteredEventHandler'),
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
@@ -186,6 +191,8 @@ const TYPES = {
Auth_EmailSubscriptionUnsubscribedEventHandler: Symbol.for('Auth_EmailSubscriptionUnsubscribedEventHandler'),
Auth_PaymentsAccountDeletedEventHandler: Symbol.for('Auth_PaymentsAccountDeletedEventHandler'),
Auth_TransitionStatusUpdatedEventHandler: Symbol.for('Auth_TransitionStatusUpdatedEventHandler'),
Auth_UserAddedToSharedVaultEventHandler: Symbol.for('Auth_UserAddedToSharedVaultEventHandler'),
Auth_UserRemovedFromSharedVaultEventHandler: Symbol.for('Auth_UserRemovedFromSharedVaultEventHandler'),
// Services
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
Auth_SessionService: Symbol.for('Auth_SessionService'),

View File

@@ -0,0 +1,24 @@
import { DomainEventHandlerInterface, UserAddedToSharedVaultEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { AddSharedVaultUser } from '../UseCase/AddSharedVaultUser/AddSharedVaultUser'
export class UserAddedToSharedVaultEventHandler implements DomainEventHandlerInterface {
constructor(
private addSharedVaultUser: AddSharedVaultUser,
private logger: Logger,
) {}
async handle(event: UserAddedToSharedVaultEvent): Promise<void> {
const result = await this.addSharedVaultUser.execute({
userUuid: event.payload.userUuid,
sharedVaultUuid: event.payload.sharedVaultUuid,
permission: event.payload.permission,
createdAt: event.payload.createdAt,
updatedAt: event.payload.updatedAt,
})
if (result.isFailed()) {
this.logger.error(`Failed to add user to shared vault: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,22 @@
import { DomainEventHandlerInterface, UserRemovedFromSharedVaultEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { RemoveSharedVaultUser } from '../UseCase/RemoveSharedVaultUser/RemoveSharedVaultUser'
export class UserRemovedFromSharedVaultEventHandler implements DomainEventHandlerInterface {
constructor(
private removeSharedVaultUser: RemoveSharedVaultUser,
private logger: Logger,
) {}
async handle(event: UserRemovedFromSharedVaultEvent): Promise<void> {
const result = await this.removeSharedVaultUser.execute({
userUuid: event.payload.userUuid,
sharedVaultUuid: event.payload.sharedVaultUuid,
})
if (result.isFailed()) {
this.logger.error(`Failed to remove user from shared vault: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,8 @@
import { SharedVaultUser, Uuid } from '@standardnotes/domain-core'
export interface SharedVaultUserRepositoryInterface {
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>
findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]>
save(sharedVaultUser: SharedVaultUser): Promise<void>
remove(sharedVault: SharedVaultUser): Promise<void>
}

View File

@@ -0,0 +1,106 @@
import { Result, SharedVaultUser } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
import { AddSharedVaultUser } from './AddSharedVaultUser'
describe('AddSharedVaultUser', () => {
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
const createUseCase = () => new AddSharedVaultUser(sharedVaultUserRepository)
beforeEach(() => {
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.save = jest.fn()
})
it('should save shared vault user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
createdAt: 1,
updatedAt: 2,
})
expect(result.isFailed()).toBeFalsy()
expect(sharedVaultUserRepository.save).toHaveBeenCalled()
})
it('should fail when user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
createdAt: 1,
updatedAt: 2,
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
})
it('should fail when shared vault uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: 'invalid',
permission: 'read',
createdAt: 1,
updatedAt: 2,
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
})
it('should fail when permission is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
permission: 'invalid',
createdAt: 1,
updatedAt: 2,
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
})
it('should fail when timestamps are invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
createdAt: 'invalid' as unknown as number,
updatedAt: 1,
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
})
it('should fail when shared vault user is invalid', async () => {
const mock = jest.spyOn(SharedVaultUser, 'create')
mock.mockReturnValue(Result.fail('Oops'))
const result = await createUseCase().execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
createdAt: 2,
updatedAt: 1,
})
expect(result.isFailed()).toBeTruthy()
mock.mockRestore()
})
})

View File

@@ -0,0 +1,56 @@
import {
Result,
SharedVaultUser,
SharedVaultUserPermission,
Timestamps,
UseCaseInterface,
Uuid,
} from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
import { AddSharedVaultUserDTO } from './AddSharedVaultUserDTO'
export class AddSharedVaultUser implements UseCaseInterface<void> {
constructor(private sharedVaultUserRepository: SharedVaultUserRepositoryInterface) {}
async execute(dto: AddSharedVaultUserDTO): Promise<Result<void>> {
const userUuidOrError = Uuid.create(dto.userUuid)
if (userUuidOrError.isFailed()) {
return Result.fail(userUuidOrError.getError())
}
const userUuid = userUuidOrError.getValue()
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const permissionOrError = SharedVaultUserPermission.create(dto.permission)
if (permissionOrError.isFailed()) {
return Result.fail(permissionOrError.getError())
}
const permission = permissionOrError.getValue()
const timestampsOrError = Timestamps.create(dto.createdAt, dto.updatedAt)
if (timestampsOrError.isFailed()) {
return Result.fail(timestampsOrError.getError())
}
const timestamps = timestampsOrError.getValue()
const sharedVaultUserOrError = SharedVaultUser.create({
userUuid,
sharedVaultUuid,
permission,
timestamps,
})
if (sharedVaultUserOrError.isFailed()) {
return Result.fail(sharedVaultUserOrError.getError())
}
const sharedVaultUser = sharedVaultUserOrError.getValue()
await this.sharedVaultUserRepository.save(sharedVaultUser)
return Result.ok()
}
}

View File

@@ -0,0 +1,7 @@
export interface AddSharedVaultUserDTO {
sharedVaultUuid: string
userUuid: string
permission: string
createdAt: number
updatedAt: number
}

View File

@@ -9,8 +9,9 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
import { CreateCrossServiceToken } from './CreateCrossServiceToken'
import { GetSetting } from '../GetSetting/GetSetting'
import { Result } from '@standardnotes/domain-core'
import { Result, SharedVaultUser, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
describe('CreateCrossServiceToken', () => {
let userProjector: ProjectorInterface<User>
@@ -20,6 +21,7 @@ describe('CreateCrossServiceToken', () => {
let userRepository: UserRepositoryInterface
let getSettingUseCase: GetSetting
let transitionStatusRepository: TransitionStatusRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
const jwtTTL = 60
let session: Session
@@ -36,6 +38,7 @@ describe('CreateCrossServiceToken', () => {
jwtTTL,
getSettingUseCase,
transitionStatusRepository,
sharedVaultUserRepository,
)
beforeEach(() => {
@@ -70,6 +73,16 @@ describe('CreateCrossServiceToken', () => {
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('TO-DO')
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findByUserUuid = jest.fn().mockReturnValue([
SharedVaultUser.create({
permission: SharedVaultUserPermission.create('read').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123456789, 123456789).getValue(),
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
}).getValue(),
])
})
it('should create a cross service token for user', async () => {
@@ -86,6 +99,12 @@ describe('CreateCrossServiceToken', () => {
uuid: '1-3-4',
},
],
belongs_to_shared_vaults: [
{
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
},
],
session: {
test: 'test',
},
@@ -115,6 +134,12 @@ describe('CreateCrossServiceToken', () => {
uuid: '1-3-4',
},
],
belongs_to_shared_vaults: [
{
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
},
],
session: {
test: 'test',
},
@@ -141,6 +166,12 @@ describe('CreateCrossServiceToken', () => {
uuid: '1-3-4',
},
],
belongs_to_shared_vaults: [
{
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
},
],
user: {
email: 'test@test.te',
uuid: '00000000-0000-0000-0000-000000000000',
@@ -164,6 +195,12 @@ describe('CreateCrossServiceToken', () => {
uuid: '1-3-4',
},
],
belongs_to_shared_vaults: [
{
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
},
],
user: {
email: 'test@test.te',
uuid: '00000000-0000-0000-0000-000000000000',
@@ -208,6 +245,12 @@ describe('CreateCrossServiceToken', () => {
uuid: '1-3-4',
},
],
belongs_to_shared_vaults: [
{
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
permission: 'read',
},
],
session: {
test: 'test',
},

View File

@@ -13,6 +13,7 @@ import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO'
import { GetSetting } from '../GetSetting/GetSetting'
import { SettingName } from '@standardnotes/settings'
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
@injectable()
export class CreateCrossServiceToken implements UseCaseInterface<string> {
@@ -27,6 +28,7 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
private getSettingUseCase: GetSetting,
@inject(TYPES.Auth_TransitionStatusRepository)
private transitionStatusRepository: TransitionStatusRepositoryInterface,
@inject(TYPES.Auth_SharedVaultUserRepository) private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
) {}
async execute(dto: CreateCrossServiceTokenDTO): Promise<Result<string>> {
@@ -49,11 +51,19 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
const roles = await user.roles
const sharedVaultAssociations = await this.sharedVaultUserRepository.findByUserUuid(
Uuid.create(user.uuid).getValue(),
)
const authTokenData: CrossServiceTokenData = {
user: this.projectUser(user),
roles: this.projectRoles(roles),
shared_vault_owner_context: undefined,
ongoing_transition: transitionStatus === 'STARTED',
belongs_to_shared_vaults: sharedVaultAssociations.map((association) => ({
shared_vault_uuid: association.props.sharedVaultUuid.value,
permission: association.props.permission.value,
})),
}
if (dto.sharedVaultOwnerContext !== undefined) {

View File

@@ -0,0 +1,68 @@
import { SharedVaultUser } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
import { RemoveSharedVaultUser } from './RemoveSharedVaultUser'
describe('RemoveSharedVaultUser', () => {
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
const createUseCase = () => new RemoveSharedVaultUser(sharedVaultUserRepository)
beforeEach(() => {
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
.fn()
.mockReturnValue({} as jest.Mocked<SharedVaultUser>)
sharedVaultUserRepository.remove = jest.fn()
})
it('should remove shared vault user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeFalsy()
expect(sharedVaultUserRepository.remove).toHaveBeenCalled()
})
it('should fail when user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
})
it('should fail when shared vault uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
})
it('should fail when shared vault user is not found', async () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockReturnValue(null)
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,34 @@
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
import { RemoveSharedVaultUserDTO } from './RemoveSharedVaultUserDTO'
export class RemoveSharedVaultUser implements UseCaseInterface<void> {
constructor(private sharedVaultUserRepository: SharedVaultUserRepositoryInterface) {}
async execute(dto: RemoveSharedVaultUserDTO): Promise<Result<void>> {
const userUuidOrError = Uuid.create(dto.userUuid)
if (userUuidOrError.isFailed()) {
return Result.fail(userUuidOrError.getError())
}
const userUuid = userUuidOrError.getValue()
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const sharedVaultUser = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
userUuid,
sharedVaultUuid,
})
if (!sharedVaultUser) {
return Result.fail('Shared vault user not found')
}
await this.sharedVaultUserRepository.remove(sharedVaultUser)
return Result.ok()
}
}

View File

@@ -0,0 +1,4 @@
export interface RemoveSharedVaultUserDTO {
sharedVaultUuid: string
userUuid: string
}

View File

@@ -0,0 +1,40 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
@Entity({ name: 'auth_shared_vault_users' })
export class TypeORMSharedVaultUser {
@PrimaryGeneratedColumn('uuid')
declare uuid: string
@Column({
name: 'shared_vault_uuid',
length: 36,
})
@Index('shared_vault_uuid_on_auth_shared_vault_users')
declare sharedVaultUuid: string
@Column({
name: 'user_uuid',
length: 36,
})
@Index('user_uuid_on_auth_shared_vault_users')
declare userUuid: string
@Column({
name: 'permission',
type: 'varchar',
length: 24,
})
declare permission: string
@Column({
name: 'created_at_timestamp',
type: 'bigint',
})
declare createdAtTimestamp: number
@Column({
name: 'updated_at_timestamp',
type: 'bigint',
})
declare updatedAtTimestamp: number
}

View File

@@ -0,0 +1,54 @@
import { Repository } from 'typeorm'
import { MapperInterface, SharedVaultUser, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../Domain/SharedVault/SharedVaultUserRepositoryInterface'
import { TypeORMSharedVaultUser } from './TypeORMSharedVaultUser'
export class TypeORMSharedVaultUserRepository implements SharedVaultUserRepositoryInterface {
constructor(
private ormRepository: Repository<TypeORMSharedVaultUser>,
private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
) {}
async findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]> {
const persistence = await this.ormRepository
.createQueryBuilder('shared_vault_user')
.where('shared_vault_user.user_uuid = :userUuid', {
userUuid: userUuid.value,
})
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
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)
await this.ormRepository.save(persistence)
}
async remove(sharedVaultUser: SharedVaultUser): Promise<void> {
await this.ormRepository.remove(this.mapper.toProjection(sharedVaultUser))
}
}

View File

@@ -0,0 +1,67 @@
import {
Timestamps,
MapperInterface,
UniqueEntityId,
Uuid,
SharedVaultUserPermission,
SharedVaultUser,
} from '@standardnotes/domain-core'
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
export class SharedVaultUserPersistenceMapper implements MapperInterface<SharedVaultUser, TypeORMSharedVaultUser> {
toDomain(projection: TypeORMSharedVaultUser): SharedVaultUser {
const userUuidOrError = Uuid.create(projection.userUuid)
if (userUuidOrError.isFailed()) {
throw new Error(`Failed to create shared vault user from projection: ${userUuidOrError.getError()}`)
}
const userUuid = userUuidOrError.getValue()
const sharedVaultUuidOrError = Uuid.create(projection.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
throw new Error(`Failed to create shared vault user from projection: ${sharedVaultUuidOrError.getError()}`)
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
const timestampsOrError = Timestamps.create(projection.createdAtTimestamp, projection.updatedAtTimestamp)
if (timestampsOrError.isFailed()) {
throw new Error(`Failed to create shared vault user from projection: ${timestampsOrError.getError()}`)
}
const timestamps = timestampsOrError.getValue()
const permissionOrError = SharedVaultUserPermission.create(projection.permission)
if (permissionOrError.isFailed()) {
throw new Error(`Failed to create shared vault user from projection: ${permissionOrError.getError()}`)
}
const permission = permissionOrError.getValue()
const sharedVaultUserOrError = SharedVaultUser.create(
{
userUuid,
sharedVaultUuid,
permission,
timestamps,
},
new UniqueEntityId(projection.uuid),
)
if (sharedVaultUserOrError.isFailed()) {
throw new Error(`Failed to create shared vault user from projection: ${sharedVaultUserOrError.getError()}`)
}
const sharedVaultUser = sharedVaultUserOrError.getValue()
return sharedVaultUser
}
toProjection(domain: SharedVaultUser): TypeORMSharedVaultUser {
const typeorm = new TypeORMSharedVaultUser()
typeorm.uuid = domain.id.toString()
typeorm.sharedVaultUuid = domain.props.sharedVaultUuid.value
typeorm.userUuid = domain.props.userUuid.value
typeorm.permission = domain.props.permission.value
typeorm.createdAtTimestamp = domain.props.timestamps.createdAt
typeorm.updatedAtTimestamp = domain.props.timestamps.updatedAt
return typeorm
}
}

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.50.4](https://github.com/standardnotes/server/compare/@standardnotes/common@1.50.3...@standardnotes/common@1.50.4) (2023-09-04)
**Note:** Version bump only for package @standardnotes/common
## [1.50.3](https://github.com/standardnotes/server/compare/@standardnotes/common@1.50.2...@standardnotes/common@1.50.3) (2023-09-01)
**Note:** Version bump only for package @standardnotes/common

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/common",
"version": "1.50.3",
"version": "1.50.4",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -25,7 +25,7 @@
"devDependencies": {
"@types/jest": "^29.5.1",
"@types/node": "^20.5.7",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.28.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.27.0...@standardnotes/domain-core@1.28.0) (2023-09-07)
### Features
* add VaultsUser role name ([#809](https://github.com/standardnotes/server/issues/809)) ([d4830de](https://github.com/standardnotes/server/commit/d4830dec018139ffaf93d0e91d6655c5dcc6be9c))
# [1.27.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.26.3...@standardnotes/domain-core@1.27.0) (2023-09-06)
### Features
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
## [1.26.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.26.2...@standardnotes/domain-core@1.26.3) (2023-09-04)
**Note:** Version bump only for package @standardnotes/domain-core
## [1.26.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.26.1...@standardnotes/domain-core@1.26.2) (2023-09-01)
**Note:** Version bump only for package @standardnotes/domain-core

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-core",
"version": "1.26.2",
"version": "1.28.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -29,8 +29,8 @@
"devDependencies": {
"@types/jest": "^29.5.1",
"@types/node": "^20.5.7",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@types/uuid": "^9.0.3",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

View File

@@ -9,6 +9,7 @@ export class RoleName extends ValueObject<RoleNameProps> {
ProUser: 'PRO_USER',
InternalTeamUser: 'INTERNAL_TEAM_USER',
TransitionUser: 'TRANSITION_USER',
VaultsUser: 'VAULTS_USER',
}
get value(): string {
@@ -32,6 +33,7 @@ export class RoleName extends ValueObject<RoleNameProps> {
)
case RoleName.NAMES.CoreUser:
case RoleName.NAMES.TransitionUser:
case RoleName.NAMES.VaultsUser:
return [RoleName.NAMES.CoreUser, RoleName.NAMES.TransitionUser].includes(roleName.value)
/*istanbul ignore next*/
default:

View File

@@ -51,7 +51,7 @@ describe('RoleNameCollection', () => {
})
it('should tell if collection has a role with more or equal power to', () => {
let roles = [RoleName.NAMES.CoreUser]
let roles = [RoleName.NAMES.VaultsUser]
let valueOrError = RoleNameCollection.create(roles)
let roleNames = valueOrError.getValue()
@@ -63,6 +63,18 @@ describe('RoleNameCollection', () => {
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.CoreUser).getValue()),
).toBeTruthy()
roles = [RoleName.NAMES.CoreUser]
valueOrError = RoleNameCollection.create(roles)
roleNames = valueOrError.getValue()
expect(
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.PlusUser).getValue()),
).toBeFalsy()
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.ProUser).getValue())).toBeFalsy()
expect(
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.CoreUser).getValue()),
).toBeTruthy()
roles = [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser]
valueOrError = RoleNameCollection.create(roles)
roleNames = valueOrError.getValue()

View File

@@ -0,0 +1,23 @@
import { Timestamps } from './Timestamps'
describe('Timestamps', () => {
it('should create a value object', () => {
const valueOrError = Timestamps.create(123, 234)
expect(valueOrError.isFailed()).toBeFalsy()
expect(valueOrError.getValue().createdAt).toEqual(123)
expect(valueOrError.getValue().updatedAt).toEqual(234)
})
it('should not create an invalid value object', () => {
const valueOrError = Timestamps.create('' as unknown as number, 123)
expect(valueOrError.isFailed()).toBeTruthy()
})
it('should not create an invalid value object', () => {
const valueOrError = Timestamps.create(123, '' as unknown as number)
expect(valueOrError.isFailed()).toBeTruthy()
})
})

View File

@@ -16,12 +16,12 @@ export class Timestamps extends ValueObject<TimestampsProps> {
}
static create(createdAt: number, updatedAt: number): Result<Timestamps> {
if (isNaN(createdAt)) {
if (isNaN(createdAt) || typeof createdAt !== 'number') {
return Result.fail<Timestamps>(
`Could not create Timestamps. Creation date should be a number, given: ${createdAt}`,
)
}
if (isNaN(updatedAt)) {
if (isNaN(updatedAt) || typeof updatedAt !== 'number') {
return Result.fail<Timestamps>(`Could not create Timestamps. Update date should be a number, given: ${updatedAt}`)
}

View File

@@ -1,6 +1,7 @@
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
import { SharedVaultUser } from './SharedVaultUser'
import { Uuid } from '../Common/Uuid'
import { Timestamps } from '../Common/Timestamps'
describe('SharedVaultUser', () => {
it('should create an entity', () => {

View File

@@ -1,5 +1,6 @@
import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { Entity } from '../Core/Entity'
import { Result } from '../Core/Result'
import { UniqueEntityId } from '../Core/UniqueEntityId'
import { SharedVaultUserProps } from './SharedVaultUserProps'
export class SharedVaultUser extends Entity<SharedVaultUserProps> {

View File

@@ -0,0 +1,10 @@
import { Timestamps } from '../Common/Timestamps'
import { Uuid } from '../Common/Uuid'
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
export interface SharedVaultUserProps {
sharedVaultUuid: Uuid
userUuid: Uuid
permission: SharedVaultUserPermission
timestamps: Timestamps
}

View File

@@ -59,8 +59,10 @@ export * from './Service/ServiceIdentifier'
export * from './Service/ServiceIdentifierProps'
export * from './Service/ServiceInterface'
export * from './SharedVault/SharedVaultUser'
export * from './SharedVault/SharedVaultUserPermission'
export * from './SharedVault/SharedVaultUserPermissionProps'
export * from './SharedVault/SharedVaultUserProps'
export * from './Subscription/SubscriptionPlanName'
export * from './Subscription/SubscriptionPlanNameProps'

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.12.23](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.22...@standardnotes/domain-events-infra@1.12.23) (2023-09-07)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.12.22](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.21...@standardnotes/domain-events-infra@1.12.22) (2023-09-06)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.12.21](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.20...@standardnotes/domain-events-infra@1.12.21) (2023-09-04)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.12.20](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.19...@standardnotes/domain-events-infra@1.12.20) (2023-09-01)
**Note:** Version bump only for package @standardnotes/domain-events-infra

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.12.20",
"version": "1.12.23",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -35,7 +35,7 @@
"devDependencies": {
"@types/ioredis": "^5.0.0",
"@types/jest": "^29.5.1",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.124.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.123.0...@standardnotes/domain-events@2.124.0) (2023-09-07)
### Features
* add removing revisions from shared vaults ([#811](https://github.com/standardnotes/server/issues/811)) ([3bd63f7](https://github.com/standardnotes/server/commit/3bd63f767464baf9b9f1ffa52eea9eed4a4e11b5))
# [2.123.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.122.2...@standardnotes/domain-events@2.123.0) (2023-09-06)
### Features
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
## [2.122.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.122.1...@standardnotes/domain-events@2.122.2) (2023-09-04)
**Note:** Version bump only for package @standardnotes/domain-events
## [2.122.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.122.0...@standardnotes/domain-events@2.122.1) (2023-09-01)
**Note:** Version bump only for package @standardnotes/domain-events

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.122.1",
"version": "2.124.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -28,7 +28,7 @@
},
"devDependencies": {
"@types/jest": "^29.5.1",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

View File

@@ -0,0 +1,7 @@
import { DomainEventInterface } from './DomainEventInterface'
import { ItemRemovedFromSharedVaultEventPayload } from './ItemRemovedFromSharedVaultEventPayload'
export interface ItemRemovedFromSharedVaultEvent extends DomainEventInterface {
type: 'ITEM_REMOVED_FROM_SHARED_VAULT'
payload: ItemRemovedFromSharedVaultEventPayload
}

View File

@@ -0,0 +1,6 @@
export interface ItemRemovedFromSharedVaultEventPayload {
userUuid: string
itemUuid: string
sharedVaultUuid: string
roleNames: string[]
}

View File

@@ -0,0 +1,7 @@
import { DomainEventInterface } from './DomainEventInterface'
import { UserAddedToSharedVaultEventPayload } from './UserAddedToSharedVaultEventPayload'
export interface UserAddedToSharedVaultEvent extends DomainEventInterface {
type: 'USER_ADDED_TO_SHARED_VAULT'
payload: UserAddedToSharedVaultEventPayload
}

View File

@@ -0,0 +1,7 @@
export interface UserAddedToSharedVaultEventPayload {
sharedVaultUuid: string
userUuid: string
permission: string
createdAt: number
updatedAt: number
}

View File

@@ -0,0 +1,7 @@
import { DomainEventInterface } from './DomainEventInterface'
import { UserRemovedFromSharedVaultEventPayload } from './UserRemovedFromSharedVaultEventPayload'
export interface UserRemovedFromSharedVaultEvent extends DomainEventInterface {
type: 'USER_REMOVED_FROM_SHARED_VAULT'
payload: UserRemovedFromSharedVaultEventPayload
}

View File

@@ -0,0 +1,4 @@
export interface UserRemovedFromSharedVaultEventPayload {
sharedVaultUuid: string
userUuid: string
}

View File

@@ -32,6 +32,8 @@ export * from './Event/FileUploadedEvent'
export * from './Event/FileUploadedEventPayload'
export * from './Event/ItemDumpedEvent'
export * from './Event/ItemDumpedEventPayload'
export * from './Event/ItemRemovedFromSharedVaultEvent'
export * from './Event/ItemRemovedFromSharedVaultEventPayload'
export * from './Event/ItemRevisionCreationRequestedEvent'
export * from './Event/ItemRevisionCreationRequestedEventPayload'
export * from './Event/ListedAccountCreatedEvent'
@@ -96,6 +98,8 @@ export * from './Event/SubscriptionSyncRequestedEvent'
export * from './Event/SubscriptionSyncRequestedEventPayload'
export * from './Event/TransitionStatusUpdatedEvent'
export * from './Event/TransitionStatusUpdatedEventPayload'
export * from './Event/UserAddedToSharedVaultEvent'
export * from './Event/UserAddedToSharedVaultEventPayload'
export * from './Event/UserDisabledSessionUserAgentLoggingEvent'
export * from './Event/UserDisabledSessionUserAgentLoggingEventPayload'
export * from './Event/UserEmailChangedEvent'
@@ -104,6 +108,8 @@ export * from './Event/UserInvitedToSharedVaultEvent'
export * from './Event/UserInvitedToSharedVaultEventPayload'
export * from './Event/UserRegisteredEvent'
export * from './Event/UserRegisteredEventPayload'
export * from './Event/UserRemovedFromSharedVaultEvent'
export * from './Event/UserRemovedFromSharedVaultEventPayload'
export * from './Event/UserRolesChangedEvent'
export * from './Event/UserRolesChangedEventPayload'
export * from './Event/WebSocketMessageRequestedEvent'

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.34](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.33...@standardnotes/event-store@1.11.34) (2023-09-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.33](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.32...@standardnotes/event-store@1.11.33) (2023-09-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.32](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.31...@standardnotes/event-store@1.11.32) (2023-09-06)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.31](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.30...@standardnotes/event-store@1.11.31) (2023-09-04)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.30](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.29...@standardnotes/event-store@1.11.30) (2023-09-01)
**Note:** Version bump only for package @standardnotes/event-store

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.11.30",
"version": "1.11.34",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",
@@ -22,7 +22,7 @@
"@types/ioredis": "^5.0.0",
"@types/jest": "^29.5.1",
"@types/nodemailer": "^6.4.1",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "^5.0.0",

Some files were not shown because too many files have changed in this diff Show More