@w3-commons/js-build-resources 0.0.1-security → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @w3-commons/js-build-resources might be problematic. Click here for more details.
- package/package.json +9 -3
- package/settings-service/.eslintrc.js +4 -0
- package/settings-service/.node-version +1 -0
- package/settings-service/.prettierrc +6 -0
- package/settings-service/.whitesource +15 -0
- package/settings-service/LICENSE +4 -0
- package/settings-service/README.md +50 -0
- package/settings-service/build.yml +56 -0
- package/settings-service/collectCodeCoverage.js +9 -0
- package/settings-service/db/cassandra/Dockerfile +3 -0
- package/settings-service/db/cassandra/createkeyspace.dev.cql +4 -0
- package/settings-service/db/cassandra/createkeyspace.dev.sh +3 -0
- package/settings-service/db/cassandra/schema_001.cql +15 -0
- package/settings-service/db/cassandra/schema_002.cql +8 -0
- package/settings-service/db/cassandra/schema_003.cql +10 -0
- package/settings-service/db/cassandra/schema_004.cql +1 -0
- package/settings-service/db/cassandra/schema_005.cql +39 -0
- package/settings-service/db/cassandra/schema_006.cql +255 -0
- package/settings-service/db/cassandra/schema_007.cql +40 -0
- package/settings-service/db/cassandra/schema_008.cql +2 -0
- package/settings-service/db/cassandra/schema_009.cql +143 -0
- package/settings-service/db/cassandra/schema_010.cql +143 -0
- package/settings-service/db/cassandra/schema_011.cql +2 -0
- package/settings-service/db/cassandra/schema_012.cql +8 -0
- package/settings-service/jest.config.fn.js +3 -0
- package/settings-service/jest.config.it.js +3 -0
- package/settings-service/jest.config.js +14 -0
- package/settings-service/jest.config.unit.js +19 -0
- package/settings-service/jest.setup.js +11 -0
- package/settings-service/package-lock.json +11772 -0
- package/settings-service/package.json +101 -0
- package/settings-service/scripts/run-fn-tests.sh +3 -0
- package/settings-service/sonar-project.properties +3 -0
- package/settings-service/src/__tests__/functional/controller/ApiKeyController.fn.ts +132 -0
- package/settings-service/src/__tests__/functional/middleware/AuthMiddlewareNextGenSSO.fn.ts +82 -0
- package/settings-service/src/__tests__/functional/repo/settingsRepo.fn.ts +302 -0
- package/settings-service/src/__tests__/functional/unified-profile/unified-profile.fn.ts +66 -0
- package/settings-service/src/__tests__/integration/repo/ApiKeyRepo.it.ts +43 -0
- package/settings-service/src/__tests__/integration/repo/settingsRepo.it.ts +142 -0
- package/settings-service/src/__tests__/integration/unified-profile/unified-profile.it.ts +31 -0
- package/settings-service/src/__tests__/unit/ErrResponse.ts +4 -0
- package/settings-service/src/__tests__/unit/JWTResponse.ts +18 -0
- package/settings-service/src/__tests__/unit/bluepagesResponse.ts +25 -0
- package/settings-service/src/__tests__/unit/controller/ApiKeyController.spec.ts +217 -0
- package/settings-service/src/__tests__/unit/controller/AppSettingsController.spec.ts +133 -0
- package/settings-service/src/__tests__/unit/controller/UserSettingsController.spec.ts +328 -0
- package/settings-service/src/__tests__/unit/controller/getAllSettings.spec.ts +83 -0
- package/settings-service/src/__tests__/unit/middleware/AuthMiddlewareNextGenSSO.spec.ts +282 -0
- package/settings-service/src/__tests__/unit/middleware/AuthenticationMiddleware.spec.ts +494 -0
- package/settings-service/src/__tests__/unit/repo/ApiKeyRepo.spec.ts +194 -0
- package/settings-service/src/__tests__/unit/repo/getAllSettings.spec.ts +100 -0
- package/settings-service/src/__tests__/unit/repo/getUserSettingsRepo.spec.ts +249 -0
- package/settings-service/src/__tests__/unit/repo/settingsRepo.spec.ts +614 -0
- package/settings-service/src/__tests__/unit/unified-profile/UnifiedProfileClient.spec.ts +31 -0
- package/settings-service/src/__tests__/unit/unified-profile/unifiedProfileUtils.spec.ts +36 -0
- package/settings-service/src/__tests__/utils/test-utils.ts +41 -0
- package/settings-service/src/config/config.ts +190 -0
- package/settings-service/src/controller/ApiKeyController.ts +114 -0
- package/settings-service/src/controller/AppSettingsController.ts +137 -0
- package/settings-service/src/controller/UserSettingsController.ts +202 -0
- package/settings-service/src/helpers/commons.ts +69 -0
- package/settings-service/src/logger/logger.ts +17 -0
- package/settings-service/src/middleware/AuthenticationMiddleware.ts +486 -0
- package/settings-service/src/middleware/AuthenticationMiddlewareFactory.ts +10 -0
- package/settings-service/src/repo/ApiKeyRepo.ts +135 -0
- package/settings-service/src/repo/ApiKeyRepoFactory.ts +10 -0
- package/settings-service/src/repo/CassandraClient.ts +33 -0
- package/settings-service/src/repo/CassandraClientFactory.ts +11 -0
- package/settings-service/src/repo/apiKeyQueries.ts +64 -0
- package/settings-service/src/repo/cassandraDBHelpers.ts +119 -0
- package/settings-service/src/repo/settingsRepo.ts +388 -0
- package/settings-service/src/repo/settingsRepoFactory.ts +10 -0
- package/settings-service/src/repo/settingsRepoQueries.ts +62 -0
- package/settings-service/src/routes/apiKeyRoutes.ts +27 -0
- package/settings-service/src/routes/appSettingsRoutes.ts +30 -0
- package/settings-service/src/routes/healthCheck.ts +10 -0
- package/settings-service/src/routes/swagger.ts +8 -0
- package/settings-service/src/routes/userSettingsRoutes.ts +30 -0
- package/settings-service/src/server.ts +77 -0
- package/settings-service/src/swagger.json +732 -0
- package/settings-service/src/types/ApiKey.ts +19 -0
- package/settings-service/src/types/IRequest.ts +9 -0
- package/settings-service/src/types/IRequestAuthorization.ts +5 -0
- package/settings-service/src/types/IRouteOptions.ts +5 -0
- package/settings-service/src/types/QueryResultsTypes.ts +6 -0
- package/settings-service/src/types/UserSettingsControllerTypes.ts +5 -0
- package/settings-service/src/types/W3IdUser.ts +36 -0
- package/settings-service/src/types/settingsRepoTypes.ts +61 -0
- package/settings-service/src/types/unifiedProfileTypes.ts +10 -0
- package/settings-service/src/unified-profile/UnifiedProfileClient.ts +29 -0
- package/settings-service/src/unified-profile/UnifiedProfileClientFactory.ts +10 -0
- package/settings-service/src/unified-profile/unifiedProfileUtils.ts +22 -0
- package/settings-service/src/util/downloadCassandra.ts +34 -0
- package/settings-service/src/util/isocodeMapper.ts +22 -0
- package/settings-service/src/util/languages.ts +1457 -0
- package/settings-service/test_resources/mockApiKeyDBResult.json +8 -0
- package/settings-service/tsconfig.json +40 -0
- package/README.md +0 -5
@@ -0,0 +1,101 @@
|
|
1
|
+
{
|
2
|
+
"name": "settings-service",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"local": "nodemon --watch src/ -e ts --exec \"npm run build-quick\"",
|
8
|
+
"build": "npm run compile && npm run package && npm run analyze",
|
9
|
+
"build-quick": "npm run compile && npm run package && node ./build/server.js ",
|
10
|
+
"compile": "npm run clean && tsc -p tsconfig.json",
|
11
|
+
"analyze": "npm run unit-test",
|
12
|
+
"clean": "rm -rf build",
|
13
|
+
"test:functional": "sh ./scripts/run-fn-tests.sh",
|
14
|
+
"smoke-test": "npm run --silent",
|
15
|
+
"unit-test": "jest --forceExit -c jest.config.unit.js --coverage && node collectCodeCoverage",
|
16
|
+
"integration-test": "jest -i --forceExit -c jest.config.it.js",
|
17
|
+
"package": "cp jest.config* build && cp -r scripts build",
|
18
|
+
"lint": "eslint \"src/**/*.ts\" --fix"
|
19
|
+
},
|
20
|
+
"repository": {
|
21
|
+
"type": "git",
|
22
|
+
"url": "https://github.ibm.com/w3-profile/settings-service.git"
|
23
|
+
},
|
24
|
+
"author": "",
|
25
|
+
"license": "ISC",
|
26
|
+
"dependencies": {
|
27
|
+
"app-root-path": "^2.2.1",
|
28
|
+
"axios": "^0.19.0",
|
29
|
+
"cors": "^2.8.5",
|
30
|
+
"dotenv": "^6.2.0",
|
31
|
+
"dse-driver": "^2.3.1",
|
32
|
+
"eslint-plugin-import": "^2.25.4",
|
33
|
+
"lodash": "^4.17.21",
|
34
|
+
"npm-run": "^5.0.1",
|
35
|
+
"randomstring": "^1.1.5",
|
36
|
+
"request-promise": "^4.2.6",
|
37
|
+
"restify": "^8.1.0",
|
38
|
+
"restify-cors-middleware": "^1.1.1",
|
39
|
+
"restify-errors": "^8.0.2",
|
40
|
+
"swagger-ui-restify": "^3.0.8",
|
41
|
+
"ts-node": "^10.7.0",
|
42
|
+
"winston": "^3.2.1"
|
43
|
+
},
|
44
|
+
"devDependencies": {
|
45
|
+
"@types/app-root-path": "^1.2.4",
|
46
|
+
"@types/cors": "^2.8.4",
|
47
|
+
"@types/eslint": "^7.29.0",
|
48
|
+
"@types/jest": "^24.0.11",
|
49
|
+
"@types/lodash": "^4.14.123",
|
50
|
+
"@types/node": "^11.9.4",
|
51
|
+
"@types/node-fetch": "^2.1.6",
|
52
|
+
"@types/node-schedule": "^1.2.4",
|
53
|
+
"@types/request": "^2.0.12",
|
54
|
+
"@types/request-promise": "^4.1.42",
|
55
|
+
"@types/restify": "^7.2.5",
|
56
|
+
"@types/restify-errors": "^4.3.3",
|
57
|
+
"@typescript-eslint/eslint-plugin": "^4.6.1",
|
58
|
+
"@typescript-eslint/parser": "^4.6.1",
|
59
|
+
"@w3-commons/js-build-resources": "^1.0.3",
|
60
|
+
"eslint": "^7.27.0",
|
61
|
+
"eslint-config-airbnb-base": "^14.2.1",
|
62
|
+
"eslint-config-prettier": "^6.15.0",
|
63
|
+
"eslint-import-resolver-typescript": "^2.5.0",
|
64
|
+
"eslint-plugin-prettier": "^3.4.1",
|
65
|
+
"jest": "^26.6.3",
|
66
|
+
"nodemon": "^1.18.10",
|
67
|
+
"prettier": "^2.5.1",
|
68
|
+
"request": "^2.88.2",
|
69
|
+
"ts-jest": "^26.5.6",
|
70
|
+
"typescript": "^4.5.4",
|
71
|
+
"typescript-eslint-parser": "^22.0.0"
|
72
|
+
},
|
73
|
+
"jest": {
|
74
|
+
"verbose": false,
|
75
|
+
"transform": {
|
76
|
+
"^.+\\.tsx?$": "ts-jest"
|
77
|
+
},
|
78
|
+
"testRegex": "(/__tests__/unit/.*)spec.ts$",
|
79
|
+
"moduleFileExtensions": [
|
80
|
+
"ts",
|
81
|
+
"tsx",
|
82
|
+
"js",
|
83
|
+
"json"
|
84
|
+
],
|
85
|
+
"coverageDirectory": "test/coverage",
|
86
|
+
"collectCoverageFrom": [
|
87
|
+
"**/src/**/*.{ts,tsx}"
|
88
|
+
],
|
89
|
+
"coveragePathIgnorePatterns": [
|
90
|
+
"(/__tests__/unit/.*)"
|
91
|
+
],
|
92
|
+
"coverageThreshold": {
|
93
|
+
"global": {
|
94
|
+
"branches": 70,
|
95
|
+
"functions": 80,
|
96
|
+
"lines": 80,
|
97
|
+
"statements": 80
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import axios from 'axios';
|
2
|
+
import http from 'axios/lib/adapters/http';
|
3
|
+
import { downloadCassandra } from '../../../util/downloadCassandra';
|
4
|
+
import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
|
5
|
+
import { settings } from '../../../config/config';
|
6
|
+
import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
|
7
|
+
import { sampleAuthorization, TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
|
8
|
+
|
9
|
+
axios.defaults.adapter = http;
|
10
|
+
|
11
|
+
const apiKeyAuthorizedIds: string = settings.apiKeyAuthorizedUserIds;
|
12
|
+
settings.apiKeyAuthorizedUserIds = TEST_USER_ID;
|
13
|
+
|
14
|
+
const urlprefix =
|
15
|
+
process.env.INGRESS_HOSTNAME !== undefined
|
16
|
+
? `https://${process.env.INGRESS_HOSTNAME}`
|
17
|
+
: 'http://localhost:8000';
|
18
|
+
|
19
|
+
let createdApiKey = '';
|
20
|
+
|
21
|
+
const TEST_HEADER = { Authorization: `Bearer ${JSON.stringify(sampleAuthorization)}` };
|
22
|
+
|
23
|
+
beforeAll(async () => {
|
24
|
+
await downloadCassandra();
|
25
|
+
await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
|
26
|
+
});
|
27
|
+
|
28
|
+
afterAll(async () => {
|
29
|
+
await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
|
30
|
+
await cassandraDBHelpers.shutdown();
|
31
|
+
settings.apiKeyAuthorizedUserIds = apiKeyAuthorizedIds;
|
32
|
+
});
|
33
|
+
|
34
|
+
afterEach(() => {
|
35
|
+
jest.clearAllMocks();
|
36
|
+
});
|
37
|
+
|
38
|
+
describe('create api key', () => {
|
39
|
+
it('should allow an authorized user to create an api key', async () => {
|
40
|
+
const data = await axios({
|
41
|
+
method: 'post',
|
42
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
43
|
+
headers: TEST_HEADER,
|
44
|
+
}).then((res) => res.data);
|
45
|
+
createdApiKey = data.key;
|
46
|
+
|
47
|
+
expect(data).toBeDefined();
|
48
|
+
expect(data.key).toHaveLength(48);
|
49
|
+
expect(typeof data.key).toBe('string');
|
50
|
+
});
|
51
|
+
|
52
|
+
it('should not allow an unauthorized user to create an api key', async () => {
|
53
|
+
expect.assertions(3);
|
54
|
+
try {
|
55
|
+
await axios({
|
56
|
+
method: 'post',
|
57
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
58
|
+
headers: {
|
59
|
+
Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
|
60
|
+
},
|
61
|
+
}).then((res) => res.data);
|
62
|
+
} catch (err) {
|
63
|
+
expect(err).toBeDefined();
|
64
|
+
expect(err).toBeInstanceOf(Error);
|
65
|
+
expect(err.message).toBe('Request failed with status code 403');
|
66
|
+
}
|
67
|
+
});
|
68
|
+
});
|
69
|
+
|
70
|
+
describe('get api key', () => {
|
71
|
+
it('should allow an authorized user to create an api key', async () => {
|
72
|
+
const data = await axios({
|
73
|
+
method: 'get',
|
74
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
75
|
+
headers: TEST_HEADER,
|
76
|
+
}).then((res) => res.data);
|
77
|
+
|
78
|
+
expect(data).toBeDefined();
|
79
|
+
expect(data.key).toHaveLength(48);
|
80
|
+
expect(typeof data.key).toBe('string');
|
81
|
+
expect(data.key).toEqual(createdApiKey);
|
82
|
+
});
|
83
|
+
|
84
|
+
it('should not allow an unauthorized user to retrive an api key', async () => {
|
85
|
+
expect.assertions(3);
|
86
|
+
try {
|
87
|
+
await axios({
|
88
|
+
method: 'get',
|
89
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
90
|
+
headers: {
|
91
|
+
Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
|
92
|
+
},
|
93
|
+
}).then((res) => res.data);
|
94
|
+
} catch (err) {
|
95
|
+
expect(err).toBeDefined();
|
96
|
+
expect(err).toBeInstanceOf(Error);
|
97
|
+
expect(err.message).toBe('Request failed with status code 403');
|
98
|
+
}
|
99
|
+
});
|
100
|
+
|
101
|
+
describe('update api key', () => {
|
102
|
+
it('should allow an authorized user to update an api key', async () => {
|
103
|
+
const data = await axios({
|
104
|
+
method: 'put',
|
105
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
106
|
+
headers: TEST_HEADER,
|
107
|
+
}).then((res) => res.data);
|
108
|
+
|
109
|
+
expect(data).toBeDefined();
|
110
|
+
expect(data.key).toHaveLength(48);
|
111
|
+
expect(typeof data.key).toBe('string');
|
112
|
+
expect(data.key).not.toEqual(createdApiKey);
|
113
|
+
});
|
114
|
+
|
115
|
+
it('should not allow an unauthorized user to update an api key', async () => {
|
116
|
+
expect.assertions(3);
|
117
|
+
try {
|
118
|
+
await axios({
|
119
|
+
method: 'put',
|
120
|
+
url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
|
121
|
+
headers: {
|
122
|
+
Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
|
123
|
+
},
|
124
|
+
}).then((res) => res.data);
|
125
|
+
} catch (err) {
|
126
|
+
expect(err).toBeDefined();
|
127
|
+
expect(err).toBeInstanceOf(Error);
|
128
|
+
expect(err.message).toBe('Request failed with status code 403');
|
129
|
+
}
|
130
|
+
});
|
131
|
+
});
|
132
|
+
});
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import axios from 'axios';
|
2
|
+
import http from 'axios/lib/adapters/http';
|
3
|
+
import { ApiKeyRepoFactory } from '../../../repo/ApiKeyRepoFactory';
|
4
|
+
import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
|
5
|
+
import { ApiKeyRepo } from '../../../repo/ApiKeyRepo';
|
6
|
+
import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
|
7
|
+
import { SettingsRepo } from '../../../repo/settingsRepo';
|
8
|
+
import { TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
|
9
|
+
import { SettingsRepoFactory } from '../../../repo/settingsRepoFactory';
|
10
|
+
import { downloadCassandra } from '../../../util/downloadCassandra';
|
11
|
+
|
12
|
+
axios.defaults.adapter = http;
|
13
|
+
|
14
|
+
const TEST_SETTING = 'test';
|
15
|
+
const W3ID_TOKEN = `Bearer Q3ccWQ4TZxK3bm6vnuOk5kQ9JApv7PCr8aLFxtKf`;
|
16
|
+
|
17
|
+
async function apiKeySetup(): Promise<string> {
|
18
|
+
const apiKeyRepo: ApiKeyRepo = ApiKeyRepoFactory.accessOrCreateSingleton();
|
19
|
+
const createdApiKey = await apiKeyRepo.createApiKey(TEST_APP_ID, 'TEST_USER_ID');
|
20
|
+
return Buffer.from(`w3notifications-test:${createdApiKey}`).toString('base64');
|
21
|
+
}
|
22
|
+
|
23
|
+
const TEST_HEADER = { headers: { Authorization: `${W3ID_TOKEN}` } };
|
24
|
+
let TEST_HEADER_API: any = {};
|
25
|
+
|
26
|
+
const urlprefix =
|
27
|
+
process.env.INGRESS_HOSTNAME !== undefined
|
28
|
+
? `https://${process.env.INGRESS_HOSTNAME}`
|
29
|
+
: 'http://localhost:8000';
|
30
|
+
|
31
|
+
const settingsRepo: SettingsRepo = SettingsRepoFactory.accessOrCreateSingleton();
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Below are functional tests for Authentication Middleware NextGen SSO (ISV)
|
35
|
+
*/
|
36
|
+
describe('Authentication fails with invalid token', () => {
|
37
|
+
const TEST_RESP = { general: {} };
|
38
|
+
TEST_RESP[TEST_APP_ID] = {};
|
39
|
+
|
40
|
+
beforeAll(async () => {
|
41
|
+
await downloadCassandra();
|
42
|
+
await settingsRepo.deleteUserSettings(TEST_USER_ID);
|
43
|
+
await settingsRepo.deleteAppSettings(TEST_APP_ID, TEST_SETTING);
|
44
|
+
TEST_HEADER_API = { headers: { Authorization: `apiKey ${await apiKeySetup()}`, nextgen_sso: true } };
|
45
|
+
});
|
46
|
+
|
47
|
+
afterAll(async () => {
|
48
|
+
await settingsRepo.deleteUserSettings(TEST_USER_ID);
|
49
|
+
await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
|
50
|
+
await cassandraDBHelpers.shutdown();
|
51
|
+
});
|
52
|
+
|
53
|
+
it('will not authenticate invalid token', async () => {
|
54
|
+
let caughtError;
|
55
|
+
try {
|
56
|
+
await axios.post(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, {}, TEST_HEADER);
|
57
|
+
expect(false).toBeTruthy();
|
58
|
+
} catch (err) {
|
59
|
+
caughtError = err;
|
60
|
+
}
|
61
|
+
expect(caughtError.response.data.code).toBe(401);
|
62
|
+
expect(caughtError.response.data.message).toBe('User token is expired or is invalid');
|
63
|
+
});
|
64
|
+
|
65
|
+
it('will authenticate API key with nextgen_sso true', async () => {
|
66
|
+
let data = await axios
|
67
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
|
68
|
+
.then((res) => res.data);
|
69
|
+
expect(data).toEqual({});
|
70
|
+
|
71
|
+
data = await axios
|
72
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
73
|
+
.then((res) => res.data);
|
74
|
+
expect(data).toEqual({});
|
75
|
+
});
|
76
|
+
|
77
|
+
it('does not need authentication for user get request', async () => {
|
78
|
+
const resp = await axios.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`);
|
79
|
+
expect(resp.status).toBe(200);
|
80
|
+
expect(resp.data).toBeDefined();
|
81
|
+
});
|
82
|
+
});
|
@@ -0,0 +1,302 @@
|
|
1
|
+
import axios from 'axios';
|
2
|
+
import http from 'axios/lib/adapters/http';
|
3
|
+
import { ApiKeyRepoFactory } from '../../../repo/ApiKeyRepoFactory';
|
4
|
+
import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
|
5
|
+
import { ApiKeyRepo } from '../../../repo/ApiKeyRepo';
|
6
|
+
import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
|
7
|
+
import { SettingsRepo } from '../../../repo/settingsRepo';
|
8
|
+
import { INVALID_APP_ID, sampleAuthorization, TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
|
9
|
+
import { SettingsRepoFactory } from '../../../repo/settingsRepoFactory';
|
10
|
+
import { downloadCassandra } from '../../../util/downloadCassandra';
|
11
|
+
|
12
|
+
axios.defaults.adapter = http;
|
13
|
+
|
14
|
+
const TEST_SETTING = 'test';
|
15
|
+
const TEST_SETTING_OPTIONS_DEFAULT = { default: 'false', options: ['true', 'false'], setting_type: null };
|
16
|
+
const TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE = { default: 'false', options: ['true', 'false'] };
|
17
|
+
|
18
|
+
async function apiKeySetup(): Promise<string> {
|
19
|
+
const apiKeyRepo: ApiKeyRepo = ApiKeyRepoFactory.accessOrCreateSingleton();
|
20
|
+
const createdApiKey = await apiKeyRepo.createApiKey(TEST_APP_ID, 'TEST_USER_ID');
|
21
|
+
return Buffer.from(`w3notifications-test:${createdApiKey}`).toString('base64');
|
22
|
+
}
|
23
|
+
|
24
|
+
const TEST_HEADER = { headers: { Authorization: `Bearer ${JSON.stringify(sampleAuthorization)}` } };
|
25
|
+
let TEST_HEADER_API: any = {};
|
26
|
+
|
27
|
+
const urlprefix =
|
28
|
+
process.env.INGRESS_HOSTNAME !== undefined
|
29
|
+
? `https://${process.env.INGRESS_HOSTNAME}`
|
30
|
+
: 'http://localhost:8000';
|
31
|
+
|
32
|
+
const settingsRepo: SettingsRepo = SettingsRepoFactory.accessOrCreateSingleton();
|
33
|
+
|
34
|
+
const secondaryLanguageSetting = { options: ['sk', 'en', 'fr'], setting_type: 'array' };
|
35
|
+
|
36
|
+
describe('get/update user and app settings', () => {
|
37
|
+
const TEST_RESP = { general: {} };
|
38
|
+
TEST_RESP[TEST_APP_ID] = {};
|
39
|
+
|
40
|
+
beforeAll(async () => {
|
41
|
+
await downloadCassandra();
|
42
|
+
await settingsRepo.deleteUserSettings(TEST_USER_ID);
|
43
|
+
await settingsRepo.deleteAppSettings(TEST_APP_ID, TEST_SETTING);
|
44
|
+
await settingsRepo.deleteAppSettings(TEST_APP_ID, 'secondaryLanguages');
|
45
|
+
TEST_HEADER_API = { headers: { Authorization: `apiKey ${await apiKeySetup()}` } };
|
46
|
+
});
|
47
|
+
|
48
|
+
afterAll(async () => {
|
49
|
+
await settingsRepo.deleteUserSettings(TEST_USER_ID);
|
50
|
+
await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
|
51
|
+
await settingsRepo.deleteAppSettings(TEST_APP_ID, 'secondaryLanguages');
|
52
|
+
await cassandraDBHelpers.shutdown();
|
53
|
+
});
|
54
|
+
|
55
|
+
it('reads empty user settings', async () => {
|
56
|
+
const data = await axios
|
57
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
|
58
|
+
.then((res) => res.data);
|
59
|
+
data.general = {};
|
60
|
+
expect(data).toEqual(TEST_RESP);
|
61
|
+
});
|
62
|
+
|
63
|
+
it('reads empty app settings', async () => {
|
64
|
+
let data = await axios
|
65
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
|
66
|
+
.then((res) => res.data);
|
67
|
+
expect(data).toEqual({});
|
68
|
+
|
69
|
+
data = await axios
|
70
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
71
|
+
.then((res) => res.data);
|
72
|
+
expect(data).toEqual({});
|
73
|
+
});
|
74
|
+
|
75
|
+
it('updates app data', async () => {
|
76
|
+
const data = await axios
|
77
|
+
.post(
|
78
|
+
`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
|
79
|
+
TEST_SETTING_OPTIONS_DEFAULT,
|
80
|
+
TEST_HEADER_API,
|
81
|
+
)
|
82
|
+
.then((res) => res.data);
|
83
|
+
expect(data).toEqual('Success');
|
84
|
+
});
|
85
|
+
|
86
|
+
it('reads updated app settings', async () => {
|
87
|
+
let data = await axios
|
88
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
|
89
|
+
.then((res) => res.data);
|
90
|
+
expect(data[TEST_SETTING]).toEqual(TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE);
|
91
|
+
data = await axios
|
92
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
93
|
+
.then((res) => res.data);
|
94
|
+
expect(data[TEST_SETTING]).toEqual(TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE);
|
95
|
+
});
|
96
|
+
|
97
|
+
it('updates app data with default', async () => {
|
98
|
+
const data = await axios
|
99
|
+
.post(
|
100
|
+
`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
|
101
|
+
TEST_SETTING_OPTIONS_DEFAULT,
|
102
|
+
TEST_HEADER_API,
|
103
|
+
)
|
104
|
+
.then((res) => res.data);
|
105
|
+
expect(data).toEqual('Success');
|
106
|
+
});
|
107
|
+
|
108
|
+
it('reads default user settings', async () => {
|
109
|
+
TEST_RESP[TEST_APP_ID] = {};
|
110
|
+
TEST_RESP[TEST_APP_ID][TEST_SETTING] = 'false';
|
111
|
+
const data = await axios
|
112
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
|
113
|
+
.then((res) => res.data);
|
114
|
+
data.general = {};
|
115
|
+
expect(data).toEqual(TEST_RESP);
|
116
|
+
});
|
117
|
+
|
118
|
+
it('updates user data', async () => {
|
119
|
+
TEST_RESP[TEST_APP_ID] = {};
|
120
|
+
TEST_RESP[TEST_APP_ID][TEST_SETTING] = 'true';
|
121
|
+
const data = await axios
|
122
|
+
.post(
|
123
|
+
`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`,
|
124
|
+
TEST_RESP[TEST_APP_ID],
|
125
|
+
TEST_HEADER,
|
126
|
+
)
|
127
|
+
.then((res) => res.data);
|
128
|
+
expect(data).toEqual(TEST_RESP[TEST_APP_ID]);
|
129
|
+
});
|
130
|
+
|
131
|
+
it('reads updated user settings', async () => {
|
132
|
+
const data = await axios
|
133
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
|
134
|
+
.then((res) => res.data);
|
135
|
+
data.general = {};
|
136
|
+
expect(data).toEqual(TEST_RESP);
|
137
|
+
});
|
138
|
+
|
139
|
+
it('throws error for invalid app', async () => {
|
140
|
+
await axios
|
141
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
|
142
|
+
.catch((error) => expect(error.response.status).toEqual(400));
|
143
|
+
});
|
144
|
+
|
145
|
+
it('deletes app data', async () => {
|
146
|
+
const data = await axios
|
147
|
+
.delete(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
148
|
+
.then((res) => res.data);
|
149
|
+
expect(data).toEqual('Success');
|
150
|
+
});
|
151
|
+
|
152
|
+
it('reads empty app settings', async () => {
|
153
|
+
let data = await axios
|
154
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
|
155
|
+
.then((res) => res.data);
|
156
|
+
expect(data).toEqual({});
|
157
|
+
|
158
|
+
data = await axios
|
159
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
160
|
+
.then((res) => res.data);
|
161
|
+
expect(data).toEqual({});
|
162
|
+
});
|
163
|
+
|
164
|
+
it('throws error for invalid app', async () => {
|
165
|
+
await axios
|
166
|
+
.get(`${urlprefix}/v1/settings/app/${INVALID_APP_ID}`, TEST_HEADER_API)
|
167
|
+
.catch((error) => expect(error.response.status).toEqual(400));
|
168
|
+
await axios
|
169
|
+
.get(`${urlprefix}/v1/settings/app/${INVALID_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
170
|
+
.catch((error) => expect(error.response.status).toEqual(400));
|
171
|
+
});
|
172
|
+
|
173
|
+
it('updates user setting with array value', async () => {
|
174
|
+
await axios.post(
|
175
|
+
`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/secondaryLanguages`,
|
176
|
+
secondaryLanguageSetting,
|
177
|
+
TEST_HEADER_API,
|
178
|
+
);
|
179
|
+
|
180
|
+
const updatedSetting = { secondaryLanguages: ['en', 'fr'] };
|
181
|
+
const data = await axios
|
182
|
+
.post(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, updatedSetting, TEST_HEADER)
|
183
|
+
.then((res) => res.data);
|
184
|
+
expect(data).toEqual({ secondaryLanguages: ['en', 'fr'] });
|
185
|
+
});
|
186
|
+
|
187
|
+
it('reads user settings with array value', async () => {
|
188
|
+
const data = await axios
|
189
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
|
190
|
+
.then((res) => res.data);
|
191
|
+
expect(data[TEST_APP_ID].secondaryLanguages).toEqual(['en', 'fr']);
|
192
|
+
});
|
193
|
+
|
194
|
+
it('updates user setting with null value', async () => {
|
195
|
+
const data = await axios
|
196
|
+
.post(
|
197
|
+
`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`,
|
198
|
+
{ secondaryLanguages: null },
|
199
|
+
TEST_HEADER,
|
200
|
+
)
|
201
|
+
.then((res) => res.data);
|
202
|
+
expect(data).toEqual({ secondaryLanguages: null });
|
203
|
+
});
|
204
|
+
|
205
|
+
it('update general settings', async () => {
|
206
|
+
const data = await axios
|
207
|
+
.post(
|
208
|
+
`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`,
|
209
|
+
{ primaryLanguage: 'pt', secondaryLanguages: ['fr', 'es'], secondaryLocationIds: ['US', 'CH'] },
|
210
|
+
TEST_HEADER,
|
211
|
+
)
|
212
|
+
.then((res) => res.data);
|
213
|
+
expect(data.primaryLanguage).toEqual('pt');
|
214
|
+
expect(data.secondaryLanguages).toStrictEqual(['fr', 'es']);
|
215
|
+
expect(data.secondaryLocationIds).toStrictEqual(['US', 'CH']);
|
216
|
+
});
|
217
|
+
|
218
|
+
it('get general settings', async () => {
|
219
|
+
const data = await axios
|
220
|
+
.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`, TEST_HEADER)
|
221
|
+
.then((res) => res.data);
|
222
|
+
expect(data.general.primaryLanguage).toEqual('pt');
|
223
|
+
expect(data.general.secondaryLanguages).toStrictEqual(['fr', 'es']);
|
224
|
+
expect(data.general.secondaryLocationIds).toStrictEqual(['US', 'CH']);
|
225
|
+
});
|
226
|
+
|
227
|
+
it('update general settings with nulls and empty arrays', async () => {
|
228
|
+
const data = await axios
|
229
|
+
.post(
|
230
|
+
`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`,
|
231
|
+
{ primaryLanguage: null, secondaryLanguages: null, secondaryLocationIds: [] },
|
232
|
+
TEST_HEADER,
|
233
|
+
)
|
234
|
+
.then((res) => res.data);
|
235
|
+
expect(data.primaryLanguage).toEqual(null);
|
236
|
+
expect(data.secondaryLanguages).toStrictEqual(null);
|
237
|
+
expect(data.secondaryLocationIds).toStrictEqual([]);
|
238
|
+
});
|
239
|
+
|
240
|
+
it('get default general settings', async () => {
|
241
|
+
const badUserId = 'ABCDEFGHI'; // uses an invalid userId so it will always return defaults
|
242
|
+
const data = await axios
|
243
|
+
.get(`${urlprefix}/v1/settings/users/${badUserId}/apps/general`, TEST_HEADER)
|
244
|
+
.then((res) => res.data);
|
245
|
+
expect(data.general.primaryLanguage).toEqual('en');
|
246
|
+
expect(data.general.secondaryLanguages).toStrictEqual([]);
|
247
|
+
expect(data.general.secondaryLocationIds).toStrictEqual([]);
|
248
|
+
});
|
249
|
+
|
250
|
+
describe('deprecated_values tests', () => {
|
251
|
+
const settingConfigWithDeprecatedValues = {
|
252
|
+
default: 'false',
|
253
|
+
options: ['true', 'false'],
|
254
|
+
setting_type: null,
|
255
|
+
deprecated_values: { false: 'updatedFalse' },
|
256
|
+
};
|
257
|
+
const settingConfigWithDeprecatedValuesNull = {
|
258
|
+
default: 'false',
|
259
|
+
options: ['true', 'false'],
|
260
|
+
setting_type: null,
|
261
|
+
deprecated_values: null,
|
262
|
+
};
|
263
|
+
it('updates app data with deprecated_values', async () => {
|
264
|
+
const data = await axios
|
265
|
+
.post(
|
266
|
+
`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
|
267
|
+
settingConfigWithDeprecatedValues,
|
268
|
+
TEST_HEADER_API,
|
269
|
+
)
|
270
|
+
.then((res) => res.data);
|
271
|
+
expect(data).toEqual('Success');
|
272
|
+
});
|
273
|
+
it('reads updated app settings with deprecated_values', async () => {
|
274
|
+
let data = await axios
|
275
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
|
276
|
+
.then((res) => res.data);
|
277
|
+
expect(data[TEST_SETTING].deprecated_values).toEqual(
|
278
|
+
settingConfigWithDeprecatedValues.deprecated_values,
|
279
|
+
);
|
280
|
+
data = await axios
|
281
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
282
|
+
.then((res) => res.data);
|
283
|
+
expect(data[TEST_SETTING].deprecated_values).toEqual(
|
284
|
+
settingConfigWithDeprecatedValues.deprecated_values,
|
285
|
+
);
|
286
|
+
});
|
287
|
+
it('updates app data with deprecated_values as null', async () => {
|
288
|
+
const data = await axios
|
289
|
+
.post(
|
290
|
+
`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
|
291
|
+
settingConfigWithDeprecatedValuesNull,
|
292
|
+
TEST_HEADER_API,
|
293
|
+
)
|
294
|
+
.then((res) => res.data);
|
295
|
+
expect(data).toEqual('Success');
|
296
|
+
const getData = await axios
|
297
|
+
.get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
|
298
|
+
.then((res) => res.data);
|
299
|
+
expect(getData.deprecated_values).toBeUndefined();
|
300
|
+
});
|
301
|
+
});
|
302
|
+
});
|