Skip to content

Commit 671ab35

Browse files
committedSep 3, 2021
Merge branch 'release/1.18.0'
2 parents f056ece + 03a38d9 commit 671ab35

28 files changed

+1071
-759
lines changed
 

‎.env.sample

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ SNS_AWS_REGION=
4141
SQS_QUEUE_URL=
4242
SQS_AWS_REGION=
4343

44-
USER_SERVER_REGISTRATION_URL=
45-
USER_SERVER_AUTH_KEY=
46-
4744
SYNCING_SERVER_URL=http://syncing-server-js:3000
4845

4946
REDIS_EVENTS_CHANNEL=events
@@ -59,3 +56,8 @@ NEW_RELIC_LOG_LEVEL=info
5956

6057
# (Optional) Extensions Server
6158
EXTENSION_SERVER_URL=
59+
60+
# (Optional) User Server
61+
USER_SERVER_REGISTRATION_URL=
62+
USER_SERVER_CHANGE_EMAIL_URL=
63+
USER_SERVER_AUTH_KEY=

‎bin/server.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import '../src/Controller/SessionController'
77
import '../src/Controller/SessionsController'
88
import '../src/Controller/AuthController'
99
import '../src/Controller/UsersController'
10+
import '../src/Controller/SettingsController'
11+
import '../src/Controller/FeaturesController'
1012
import '../src/Controller/WebSocketsController'
1113
import '../src/Controller/AdminController'
1214

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm'
2+
3+
export class fixEncryptionVersionOnMfaSettings1630661830850 implements MigrationInterface {
4+
public async up(queryRunner: QueryRunner): Promise<void> {
5+
await queryRunner.query('UPDATE `settings` SET `server_encryption_version` = 1 WHERE `server_encryption_version` = 2')
6+
}
7+
8+
public async down(): Promise<void> {
9+
return
10+
}
11+
}

‎package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"@newrelic/native-metrics": "^6.0.0",
2626
"@standardnotes/auth": "3.7.0",
2727
"@standardnotes/common": "1.0.0",
28-
"@standardnotes/domain-events": "1.9.0",
28+
"@standardnotes/domain-events": "2.1.0",
29+
"@standardnotes/domain-events-infra": "1.0.1",
2930
"@standardnotes/features": "1.3.0",
3031
"@standardnotes/settings": "1.1.0",
3132
"@standardnotes/sncrypto-common": "1.3.0",

‎src/Bootstrap/Container.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ import {
66
DomainEventHandlerInterface,
77
DomainEventMessageHandlerInterface,
88
DomainEventSubscriberFactoryInterface,
9-
RedisDomainEventPublisher,
10-
RedisDomainEventSubscriberFactory,
11-
RedisEventMessageHandler,
12-
SNSDomainEventPublisher,
13-
SQSDomainEventSubscriberFactory,
14-
SQSEventMessageHandler,
15-
SQSNewRelicEventMessageHandler,
169
} from '@standardnotes/domain-events'
1710
import { TimerInterface, Timer } from '@standardnotes/time'
1811
import { UAParser } from 'ua-parser-js'
@@ -102,6 +95,7 @@ import { FeatureServiceInterface } from '../Domain/Feature/FeatureServiceInterfa
10295
import { FeatureService } from '../Domain/Feature/FeatureService'
10396
import { SettingServiceInterface } from '../Domain/Setting/SettingServiceInterface'
10497
import { ExtensionKeyGrantedEventHandler } from '../Domain/Handler/ExtensionKeyGrantedEventHandler'
98+
import { RedisDomainEventPublisher, RedisDomainEventSubscriberFactory, RedisEventMessageHandler, SNSDomainEventPublisher, SQSDomainEventSubscriberFactory, SQSEventMessageHandler, SQSNewRelicEventMessageHandler } from '@standardnotes/domain-events-infra'
10599

106100
export class ContainerConfigLoader {
107101
async load(): Promise<Container> {
@@ -231,6 +225,7 @@ export class ContainerConfigLoader {
231225
container.bind(TYPES.SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL', true))
232226
container.bind(TYPES.USER_SERVER_REGISTRATION_URL).toConstantValue(env.get('USER_SERVER_REGISTRATION_URL', true))
233227
container.bind(TYPES.USER_SERVER_AUTH_KEY).toConstantValue(env.get('USER_SERVER_AUTH_KEY', true))
228+
container.bind(TYPES.USER_SERVER_CHANGE_EMAIL_URL).toConstantValue(env.get('USER_SERVER_CHANGE_EMAIL_URL', true))
234229
container.bind(TYPES.REDIS_EVENTS_CHANNEL).toConstantValue(env.get('REDIS_EVENTS_CHANNEL'))
235230
container.bind(TYPES.NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
236231
container.bind(TYPES.SYNCING_SERVER_URL).toConstantValue(env.get('SYNCING_SERVER_URL'))

‎src/Bootstrap/Types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const TYPES = {
4747
SQS_AWS_REGION: Symbol.for('SQS_AWS_REGION'),
4848
USER_SERVER_REGISTRATION_URL: Symbol.for('USER_SERVER_REGISTRATION_URL'),
4949
USER_SERVER_AUTH_KEY: Symbol.for('USER_SERVER_AUTH_KEY'),
50+
USER_SERVER_CHANGE_EMAIL_URL: Symbol.for('USER_SERVER_CHANGE_EMAIL_URL'),
5051
REDIS_EVENTS_CHANNEL: Symbol.for('REDIS_EVENTS_CHANNEL'),
5152
NEW_RELIC_ENABLED: Symbol.for('NEW_RELIC_ENABLED'),
5253
SYNCING_SERVER_URL: Symbol.for('SYNCING_SERVER_URL'),
+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import 'reflect-metadata'
2+
3+
import * as express from 'express'
4+
5+
import { FeaturesController } from './FeaturesController'
6+
import { results } from 'inversify-express-utils'
7+
import { User } from '../Domain/User/User'
8+
import { GetUserFeatures } from '../Domain/UseCase/GetUserFeatures/GetUserFeatures'
9+
10+
describe('FeaturesController', () => {
11+
let getUserFeatures: GetUserFeatures
12+
13+
let request: express.Request
14+
let response: express.Response
15+
let user: User
16+
17+
const createController = () => new FeaturesController(
18+
getUserFeatures,
19+
)
20+
21+
beforeEach(() => {
22+
user = {} as jest.Mocked<User>
23+
user.uuid = '123'
24+
25+
getUserFeatures = {} as jest.Mocked<GetUserFeatures>
26+
getUserFeatures.execute = jest.fn()
27+
28+
request = {
29+
headers: {},
30+
body: {},
31+
params: {},
32+
} as jest.Mocked<express.Request>
33+
34+
response = {
35+
locals: {},
36+
} as jest.Mocked<express.Response>
37+
})
38+
39+
it('should get authenticated user features', async () => {
40+
request.params.userUuid = '1-2-3'
41+
response.locals.user = {
42+
uuid: '1-2-3',
43+
}
44+
45+
getUserFeatures.execute = jest.fn().mockReturnValue({ success: true })
46+
47+
const httpResponse = <results.JsonResult> await createController().getFeatures(request, response)
48+
const result = await httpResponse.executeAsync()
49+
50+
expect(getUserFeatures.execute).toHaveBeenCalledWith({
51+
userUuid: '1-2-3',
52+
})
53+
54+
expect(result.statusCode).toEqual(200)
55+
})
56+
57+
it('should not get user features if the user with provided uuid does not exist', async () => {
58+
request.params.userUuid = '1-2-3'
59+
response.locals.user = {
60+
uuid: '1-2-3',
61+
}
62+
63+
getUserFeatures.execute = jest.fn().mockReturnValue({ success: false })
64+
65+
const httpResponse = <results.JsonResult> await createController().getFeatures(request, response)
66+
const result = await httpResponse.executeAsync()
67+
68+
expect(getUserFeatures.execute).toHaveBeenCalledWith({ userUuid: '1-2-3' })
69+
70+
expect(result.statusCode).toEqual(400)
71+
72+
})
73+
74+
it('should not get user features if not allowed', async () => {
75+
request.params.userUuid = '1-2-3'
76+
response.locals.user = {
77+
uuid: '2-3-4',
78+
}
79+
80+
getUserFeatures.execute = jest.fn()
81+
82+
const httpResponse = <results.JsonResult> await createController().getFeatures(request, response)
83+
const result = await httpResponse.executeAsync()
84+
85+
expect(getUserFeatures.execute).not.toHaveBeenCalled()
86+
87+
expect(result.statusCode).toEqual(401)
88+
})
89+
})

‎src/Controller/FeaturesController.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Request, Response } from 'express'
2+
import { inject } from 'inversify'
3+
import {
4+
BaseHttpController,
5+
controller,
6+
httpGet,
7+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
8+
results,
9+
} from 'inversify-express-utils'
10+
import TYPES from '../Bootstrap/Types'
11+
import { GetUserFeatures } from '../Domain/UseCase/GetUserFeatures/GetUserFeatures'
12+
13+
@controller('/users/:userUuid/features')
14+
export class FeaturesController extends BaseHttpController {
15+
constructor(
16+
@inject(TYPES.GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
17+
) {
18+
super()
19+
}
20+
21+
@httpGet('/', TYPES.AuthMiddleware)
22+
async getFeatures(request: Request, response: Response): Promise<results.JsonResult> {
23+
if (request.params.userUuid !== response.locals.user.uuid) {
24+
return this.json({
25+
error: {
26+
message: 'Operation not allowed.',
27+
},
28+
}, 401)
29+
}
30+
31+
const result = await this.doGetUserFeatures.execute({
32+
userUuid: request.params.userUuid,
33+
})
34+
35+
if (result.success) {
36+
return this.json(result)
37+
}
38+
39+
return this.json(result, 400)
40+
}
41+
}

0 commit comments

Comments
 (0)
Please sign in to comment.