@apolitical/server 1.5.2-beta.7 → 2.0.0-beta.1
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.
- package/CHANGELOG.md +4 -0
- package/README.md +1 -1
- package/package.json +31 -31
- package/src/config.js +17 -13
- package/src/container.js +3 -1
- package/src/helpers/logger.helper.js +4 -8
- package/src/index.js +5 -0
- package/src/loaders/documentation.loader.js +9 -4
- package/src/loaders/logger.loader.js +20 -13
- package/src/loaders/middlewares.loader.js +3 -8
- package/src/middlewares/auth.middleware.js +7 -6
- package/src/middlewares/error.middleware.js +3 -3
- package/src/middlewares/permissions.middleware.js +39 -0
- package/src/services/server.service.js +3 -3
- package/.gitlab-ci.yml +0 -22
- package/.husky/pre-commit +0 -6
- package/doc/swagger.json +0 -52
- package/index.js +0 -5
- package/test/integration/__snapshots__/jwt.apolitical.spec.js.snap +0 -14
- package/test/integration/container.js +0 -40
- package/test/integration/errors.spec.js +0 -102
- package/test/integration/example.spec.js +0 -43
- package/test/integration/jwt.apolitical.spec.js +0 -74
- package/test/integration/jwt.auth0.spec.js +0 -57
- package/test/integration/mocks/configs/jwks.config.js +0 -17
- package/test/integration/mocks/endpoints/errors.endpoint.js +0 -40
- package/test/integration/mocks/endpoints/example.endpoint.js +0 -8
- package/test/integration/mocks/endpoints/index.html +0 -14
- package/test/integration/mocks/endpoints/index.js +0 -15
- package/test/integration/mocks/endpoints/jwt/apolitical.endpoint.js +0 -9
- package/test/integration/mocks/endpoints/jwt/auth0.endpoint.js +0 -13
- package/test/integration/mocks/endpoints/static.endpoint.js +0 -15
- package/test/integration/probes.spec.js +0 -42
- package/test/integration/static.spec.js +0 -94
- package/test/test.env +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.5.2] - 2021-10-18
|
|
9
|
+
### Changed
|
|
10
|
+
- Allow cors options to be passed in as params on start
|
|
11
|
+
|
|
8
12
|
## [1.5.1] - 2021-09-15
|
|
9
13
|
### Added
|
|
10
14
|
- Extend error class to handle too many request error
|
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apolitical/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
4
|
"description": "Node.js module to encapsulate Apolitical's express server setup",
|
|
5
5
|
"author": "Apolitical Group Limited <engineering@apolitical.co>",
|
|
6
|
-
"contributors": [
|
|
7
|
-
"Anouska Hopkins <anouska.hopkins@apolitical.co>",
|
|
8
|
-
"Antonio Cordasco <antonio.cordasco@apolitical.co>",
|
|
9
|
-
"Dorothy Yau <dorothy.yau@apolitical.co>",
|
|
10
|
-
"Laura Hanna-White <laura.hanna-white@apolitical.co>",
|
|
11
|
-
"Fatimat Gbajabiamila <fatimat.gbajabiamila@apolitical.co>",
|
|
12
|
-
"Renzo Rozza <renzo.rozza@apolitical.co>",
|
|
13
|
-
"Rihards Jukna <rihards.jukna@apolitical.co>"
|
|
14
|
-
],
|
|
15
6
|
"license": "MIT",
|
|
16
|
-
"main": "index.js",
|
|
7
|
+
"main": "src/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
17
11
|
"scripts": {
|
|
18
12
|
"test": "jest --bail --runInBand",
|
|
19
13
|
"unit-test": "jest test/unit/**/* --bail --runInBand",
|
|
@@ -30,38 +24,39 @@
|
|
|
30
24
|
"Node Modules"
|
|
31
25
|
],
|
|
32
26
|
"dependencies": {
|
|
33
|
-
"@apolitical/logger": "
|
|
27
|
+
"@apolitical/logger": "2.0.0-beta.6",
|
|
34
28
|
"@cloudnative/health-connect": "2.1.0",
|
|
35
|
-
"awilix": "
|
|
36
|
-
"body-parser": "1.19.
|
|
29
|
+
"awilix": "6.0.0",
|
|
30
|
+
"body-parser": "1.19.1",
|
|
37
31
|
"compression": "1.7.4",
|
|
38
|
-
"cookie-parser": "1.4.
|
|
32
|
+
"cookie-parser": "1.4.6",
|
|
39
33
|
"cors": "2.8.5",
|
|
40
|
-
"dotenv": "
|
|
41
|
-
"express": "4.17.
|
|
34
|
+
"dotenv": "14.2.0",
|
|
35
|
+
"express": "4.17.2",
|
|
42
36
|
"express-jwt": "6.1.0",
|
|
43
|
-
"http-status-codes": "2.
|
|
44
|
-
"http-terminator": "3.0.
|
|
45
|
-
"jsrsasign": "10.
|
|
46
|
-
"jwks-rsa": "2.0.
|
|
37
|
+
"http-status-codes": "2.2.0",
|
|
38
|
+
"http-terminator": "3.0.4",
|
|
39
|
+
"jsrsasign": "10.5.1",
|
|
40
|
+
"jwks-rsa": "2.0.5",
|
|
47
41
|
"jwt-decode": "3.1.2",
|
|
48
42
|
"morgan": "1.10.0",
|
|
49
|
-
"passport": "0.
|
|
43
|
+
"passport": "0.5.2",
|
|
50
44
|
"passport-jwt": "4.0.0",
|
|
51
|
-
"swagger-ui-express": "4.
|
|
45
|
+
"swagger-ui-express": "4.3.0"
|
|
52
46
|
},
|
|
53
47
|
"devDependencies": {
|
|
54
|
-
"@apolitical/eslint-config": "0.0.
|
|
48
|
+
"@apolitical/eslint-config": "1.0.0-beta.0",
|
|
55
49
|
"@apolitical/testing": "0.0.4",
|
|
56
|
-
"audit-ci": "
|
|
57
|
-
"husky": "7.0.
|
|
58
|
-
"jest": "27.
|
|
59
|
-
"
|
|
50
|
+
"audit-ci": "5.1.2",
|
|
51
|
+
"husky": "7.0.4",
|
|
52
|
+
"jest": "27.4.7",
|
|
53
|
+
"jest-junit": "13.0.0",
|
|
54
|
+
"lint-staged": "12.2.0",
|
|
60
55
|
"mock-jwks": "1.0.1",
|
|
61
|
-
"nock": "13.
|
|
56
|
+
"nock": "13.2.2"
|
|
62
57
|
},
|
|
63
58
|
"engines": {
|
|
64
|
-
"node": ">=
|
|
59
|
+
"node": ">=16.13.2"
|
|
65
60
|
},
|
|
66
61
|
"eslintConfig": {
|
|
67
62
|
"extends": "@apolitical/eslint-config/base.config"
|
|
@@ -86,7 +81,12 @@
|
|
|
86
81
|
"testEnvironment": "node",
|
|
87
82
|
"testTimeout": 60000,
|
|
88
83
|
"maxConcurrency": 1,
|
|
89
|
-
"maxWorkers": 1
|
|
84
|
+
"maxWorkers": 1,
|
|
85
|
+
"reporters": [
|
|
86
|
+
"default",
|
|
87
|
+
"jest-junit"
|
|
88
|
+
],
|
|
89
|
+
"testResultsProcessor": "jest-junit"
|
|
90
90
|
},
|
|
91
91
|
"lint-staged": {
|
|
92
92
|
"*.js": "eslint --cache --fix --ignore-path .gitignore",
|
package/src/config.js
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
const { NODE_ENV, LOG_LEVEL } = process.env;
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const NAME = 'apolitical-server';
|
|
6
|
+
const VERSION = 'v2.0.0';
|
|
7
|
+
const ADMIN_ROLE = 'administrator';
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
8
10
|
NODE_ENV,
|
|
9
11
|
LOG_LEVEL,
|
|
10
12
|
LOGGER_OPTIONS: {
|
|
11
13
|
logLevel: LOG_LEVEL,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
labels: {
|
|
15
|
+
name: NAME,
|
|
16
|
+
version: VERSION,
|
|
14
17
|
},
|
|
15
18
|
},
|
|
16
19
|
ENDPOINTS: {
|
|
@@ -20,15 +23,16 @@ module.exports = {
|
|
|
20
23
|
},
|
|
21
24
|
DOCUMENTATION: '/docs/',
|
|
22
25
|
},
|
|
26
|
+
MIDDLEWARES: {
|
|
27
|
+
PERMISSIONS: {
|
|
28
|
+
ADMIN_ROLE,
|
|
29
|
+
MYSELF_SLUG: 'me',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
23
32
|
SERVER: {
|
|
24
33
|
CORS_OPTIONS: {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
credentials: true,
|
|
28
|
-
},
|
|
29
|
-
ORIGIN_FALSE: {
|
|
30
|
-
origin: false,
|
|
31
|
-
},
|
|
34
|
+
origin: true,
|
|
35
|
+
credentials: true,
|
|
32
36
|
},
|
|
33
37
|
BODY_PARSER_OPTIONS: {
|
|
34
38
|
extended: false,
|
|
@@ -60,10 +64,10 @@ module.exports = {
|
|
|
60
64
|
ALGORITHM: 'HS256',
|
|
61
65
|
HEADER: { alg: 'HS256', typ: 'JWT' },
|
|
62
66
|
DEFAULT_PAYLOAD: {
|
|
63
|
-
role:
|
|
67
|
+
role: ADMIN_ROLE,
|
|
64
68
|
admin: true,
|
|
65
|
-
slug:
|
|
66
|
-
iss:
|
|
69
|
+
slug: NAME,
|
|
70
|
+
iss: NAME,
|
|
67
71
|
sub: 'login',
|
|
68
72
|
},
|
|
69
73
|
},
|
package/src/container.js
CHANGED
|
@@ -23,7 +23,7 @@ const apoliticalLogger = require('@apolitical/logger');
|
|
|
23
23
|
// Configuration
|
|
24
24
|
const config = require('./config');
|
|
25
25
|
// Logger
|
|
26
|
-
const logger = apoliticalLogger(config.LOGGER_OPTIONS);
|
|
26
|
+
const logger = apoliticalLogger.createLogger(config.LOGGER_OPTIONS);
|
|
27
27
|
// Errors
|
|
28
28
|
const serverError = require('./errors/server.error');
|
|
29
29
|
// Helpers
|
|
@@ -42,6 +42,7 @@ const authMiddleware = require('./middlewares/auth.middleware');
|
|
|
42
42
|
const jwtApoliticalMiddleware = require('./middlewares/jwt/apolitical.middleware');
|
|
43
43
|
const jwtAuth0Middleware = require('./middlewares/jwt/auth0.middleware');
|
|
44
44
|
const errorMiddleware = require('./middlewares/error.middleware');
|
|
45
|
+
const permissionsMiddleware = require('./middlewares/permissions.middleware');
|
|
45
46
|
// Services
|
|
46
47
|
const jwtService = require('./services/jwt.service');
|
|
47
48
|
const serverService = require('./services/server.service');
|
|
@@ -90,6 +91,7 @@ container.register({
|
|
|
90
91
|
jwtApoliticalMiddleware: asFunction(jwtApoliticalMiddleware).singleton(),
|
|
91
92
|
jwtAuth0Middleware: asFunction(jwtAuth0Middleware).singleton(),
|
|
92
93
|
errorMiddleware: asFunction(errorMiddleware).singleton(),
|
|
94
|
+
permissionsMiddleware: asFunction(permissionsMiddleware).singleton(),
|
|
93
95
|
// Services
|
|
94
96
|
jwtService: asFunction(jwtService).singleton(),
|
|
95
97
|
serverService: asFunction(serverService).singleton(),
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
module.exports = ({ apoliticalLogger, config: { LOG_LEVEL } }) => ({
|
|
4
|
-
build({ filename, method,
|
|
4
|
+
build({ filename, method, labels }) {
|
|
5
5
|
const options = { logLevel: LOG_LEVEL };
|
|
6
|
-
if (
|
|
7
|
-
Object.assign(options, {
|
|
8
|
-
metadata: {
|
|
9
|
-
serviceName,
|
|
10
|
-
},
|
|
11
|
-
});
|
|
6
|
+
if (labels) {
|
|
7
|
+
Object.assign(options, { labels });
|
|
12
8
|
}
|
|
13
|
-
const logger = apoliticalLogger(options);
|
|
9
|
+
const logger = apoliticalLogger.createLogger(options);
|
|
14
10
|
return logger.where(filename, method);
|
|
15
11
|
},
|
|
16
12
|
});
|
package/src/index.js
ADDED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
module.exports = ({
|
|
4
|
-
|
|
3
|
+
module.exports = ({
|
|
4
|
+
httpStatusCodes: { MOVED_PERMANENTLY },
|
|
5
|
+
config,
|
|
6
|
+
logger,
|
|
7
|
+
swaggerUi: { serve, setup },
|
|
8
|
+
permissionsMiddleware,
|
|
9
|
+
}) => {
|
|
5
10
|
const { DOCUMENTATION } = config.ENDPOINTS;
|
|
6
11
|
|
|
7
12
|
return function load(app, { swaggerDocument }) {
|
|
8
13
|
const childLogger = logger.where(__filename, 'load');
|
|
9
14
|
childLogger.debug('Started');
|
|
10
15
|
// Load document endpoint
|
|
11
|
-
if (
|
|
16
|
+
if (swaggerDocument) {
|
|
12
17
|
// Redirection to documentation
|
|
13
18
|
app.use(`${DOCUMENTATION}index.html`, (req, res) => res.redirect(MOVED_PERMANENTLY, DOCUMENTATION));
|
|
14
19
|
// Documentation express setup
|
|
15
|
-
app.use(DOCUMENTATION, serve, setup(swaggerDocument));
|
|
20
|
+
app.use(DOCUMENTATION, permissionsMiddleware(), serve, setup(swaggerDocument));
|
|
16
21
|
}
|
|
17
22
|
childLogger.debug('Finished');
|
|
18
23
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
module.exports = ({ morgan, config, logger, loggerHelper }) => {
|
|
3
|
+
module.exports = ({ apoliticalLogger, morgan, config, logger, loggerHelper }) => {
|
|
4
4
|
const {
|
|
5
5
|
LOGGED_OUT_SLUG,
|
|
6
6
|
TOKENS: { USER_SLUG },
|
|
@@ -21,22 +21,29 @@ module.exports = ({ morgan, config, logger, loggerHelper }) => {
|
|
|
21
21
|
].join(' ');
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
return function load(app, {
|
|
24
|
+
return async function load(app, { labels }) {
|
|
25
25
|
const childLogger = logger.where(__filename, 'load');
|
|
26
26
|
childLogger.debug('Started');
|
|
27
|
-
//
|
|
27
|
+
// Setup Morgan with custom format and Apolitical Logger stream
|
|
28
28
|
morgan.token(USER_SLUG, getUserSlug);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
serviceName,
|
|
37
|
-
}),
|
|
38
|
-
),
|
|
29
|
+
const morganMiddleware = morgan(
|
|
30
|
+
buildCustomFormat,
|
|
31
|
+
loggerHelper.build({
|
|
32
|
+
filename: __filename,
|
|
33
|
+
method: 'loggerMiddlewareMorgan',
|
|
34
|
+
labels,
|
|
35
|
+
}),
|
|
39
36
|
);
|
|
37
|
+
app.use(morganMiddleware);
|
|
38
|
+
// Setup Google Cloud with Apolitical Logger
|
|
39
|
+
const googleMiddleware = await apoliticalLogger.loggerMiddleware(
|
|
40
|
+
loggerHelper.build({
|
|
41
|
+
filename: __filename,
|
|
42
|
+
method: 'loggerMiddlewareWinston',
|
|
43
|
+
labels,
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
app.use(googleMiddleware);
|
|
40
47
|
childLogger.debug('Finished');
|
|
41
48
|
};
|
|
42
49
|
};
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
module.exports = ({ bodyParser: { json, urlencoded }, compression, cors, cookieParser, config, logger }) => {
|
|
4
|
-
const {
|
|
5
|
-
BODY_PARSER_OPTIONS,
|
|
6
|
-
CORS_OPTIONS: { ORIGIN_TRUE, ORIGIN_FALSE },
|
|
7
|
-
} = config.SERVER;
|
|
4
|
+
const { BODY_PARSER_OPTIONS, CORS_OPTIONS } = config.SERVER;
|
|
8
5
|
|
|
9
|
-
return function load(app, {
|
|
6
|
+
return function load(app, { corsOptions }) {
|
|
10
7
|
const childLogger = logger.where(__filename, 'load');
|
|
11
8
|
childLogger.debug('Started');
|
|
12
|
-
// Compute cors config
|
|
13
|
-
const corsOptions = disableCors ? ORIGIN_FALSE : ORIGIN_TRUE;
|
|
14
9
|
// Load useful middlewares
|
|
15
10
|
app.use(cookieParser());
|
|
16
11
|
app.use(json());
|
|
17
12
|
app.use(urlencoded(BODY_PARSER_OPTIONS));
|
|
18
|
-
app.use(cors(corsOptions));
|
|
13
|
+
app.use(cors(Object.assign({}, CORS_OPTIONS, corsOptions)));
|
|
19
14
|
app.use(compression());
|
|
20
15
|
childLogger.debug('Finished');
|
|
21
16
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
module.exports =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
module.exports = ({ jwtApoliticalMiddleware, logger, serverError: { Forbidden }, config }) => {
|
|
4
|
+
const { COOKIE_KEY } = config.JWT.APOLITICAL;
|
|
5
|
+
// Define external options
|
|
6
|
+
return ({ allowLoggedOut = false } = {}) => {
|
|
7
|
+
// Return middleware handler
|
|
8
8
|
return async function handler(req, res, next) {
|
|
9
9
|
const childLogger = logger.where(__filename, 'handler');
|
|
10
10
|
childLogger.debug('Started');
|
|
@@ -12,7 +12,7 @@ module.exports =
|
|
|
12
12
|
const user = await jwtApoliticalMiddleware(req, res);
|
|
13
13
|
// If logged out users are not allowed and there is no user object throws forbidden error
|
|
14
14
|
if (!allowLoggedOut && !user) {
|
|
15
|
-
return next(new Forbidden('
|
|
15
|
+
return next(new Forbidden('Cannot authenticate action', ['cookie-jwt', 'logged-out']));
|
|
16
16
|
}
|
|
17
17
|
// Assigns user to the request object
|
|
18
18
|
Object.assign(req, { user });
|
|
@@ -22,3 +22,4 @@ module.exports =
|
|
|
22
22
|
return next();
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
|
+
};
|
|
@@ -10,12 +10,12 @@ module.exports =
|
|
|
10
10
|
loggerHelper,
|
|
11
11
|
serverError: { GeneralError },
|
|
12
12
|
}) =>
|
|
13
|
-
({
|
|
13
|
+
({ labels, redirectURL }) => {
|
|
14
14
|
// Apolitical Logger (with service metadata)
|
|
15
15
|
const errorLogger = loggerHelper.build({
|
|
16
16
|
filename: __filename,
|
|
17
|
-
method: '
|
|
18
|
-
|
|
17
|
+
method: 'errorMiddleware',
|
|
18
|
+
labels,
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = ({ logger, serverError: { Forbidden }, config }) => {
|
|
4
|
+
const { ADMIN_ROLE, MYSELF_SLUG } = config.MIDDLEWARES.PERMISSIONS;
|
|
5
|
+
// Define external options
|
|
6
|
+
return ({ myselfSource = null, myselfTarget = null, allowNonAdmin = false } = {}) => {
|
|
7
|
+
// Return middleware handler
|
|
8
|
+
return async function handler(req, res, next) {
|
|
9
|
+
const childLogger = logger.where(__filename, 'handler');
|
|
10
|
+
childLogger.debug('Started');
|
|
11
|
+
let isNotMyselfSlug = false;
|
|
12
|
+
let isNotAdmin = false;
|
|
13
|
+
// Check myself param
|
|
14
|
+
if (myselfSource) {
|
|
15
|
+
isNotMyselfSlug = req.params[myselfSource] !== MYSELF_SLUG;
|
|
16
|
+
}
|
|
17
|
+
// Check user role (from JWT)
|
|
18
|
+
if (!allowNonAdmin) {
|
|
19
|
+
isNotAdmin = req.user && req.user.role !== ADMIN_ROLE;
|
|
20
|
+
}
|
|
21
|
+
// Check permissions and prevent unauthorised requests
|
|
22
|
+
let unauthorised = false;
|
|
23
|
+
if (isNotMyselfSlug && myselfSource && isNotAdmin && !allowNonAdmin) {
|
|
24
|
+
unauthorised = true;
|
|
25
|
+
} else if (isNotAdmin && !allowNonAdmin) {
|
|
26
|
+
unauthorised = true;
|
|
27
|
+
}
|
|
28
|
+
if (unauthorised) {
|
|
29
|
+
return next(new Forbidden('Cannot authorise action', ['cookie-jwt', 'non-admin']));
|
|
30
|
+
}
|
|
31
|
+
// Update myself slug with real slug (from JWT)
|
|
32
|
+
if (myselfSource && myselfTarget && req.params[myselfSource] === MYSELF_SLUG) {
|
|
33
|
+
Object.assign(req.params, { [myselfSource]: req.user[myselfTarget] });
|
|
34
|
+
}
|
|
35
|
+
childLogger.debug('Finished');
|
|
36
|
+
return next();
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -44,13 +44,13 @@ module.exports = ({
|
|
|
44
44
|
// Load useful middlewares
|
|
45
45
|
middlewaresLoader(app, opts);
|
|
46
46
|
// Load logger
|
|
47
|
-
loggerLoader(app, opts);
|
|
48
|
-
// Load documentation
|
|
49
|
-
documentationLoader(app, opts);
|
|
47
|
+
await loggerLoader(app, opts);
|
|
50
48
|
// Load custom resources
|
|
51
49
|
if (opts.appLoader) {
|
|
52
50
|
await opts.appLoader(app);
|
|
53
51
|
}
|
|
52
|
+
// Load documentation
|
|
53
|
+
documentationLoader(app, opts);
|
|
54
54
|
// Load static resources
|
|
55
55
|
if (opts.staticFiles) {
|
|
56
56
|
staticLoader(app, opts);
|
package/.gitlab-ci.yml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# External jobs
|
|
2
|
-
include:
|
|
3
|
-
- project: 'apolitical/templates/gitlab-pipelines'
|
|
4
|
-
ref: master
|
|
5
|
-
file: 'Node-Testing.gitlab-ci.yml'
|
|
6
|
-
|
|
7
|
-
stages:
|
|
8
|
-
- cache
|
|
9
|
-
- test
|
|
10
|
-
- publish
|
|
11
|
-
|
|
12
|
-
publish-module:
|
|
13
|
-
stage: publish
|
|
14
|
-
image: node:12.20.1-alpine3.11
|
|
15
|
-
extends:
|
|
16
|
-
- .yarn-install
|
|
17
|
-
only:
|
|
18
|
-
- tags
|
|
19
|
-
- /^v\d+\.\d+\.\d+$/
|
|
20
|
-
script:
|
|
21
|
-
- echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > ~/.npmrc
|
|
22
|
-
- yarn publish --access=public
|
package/.husky/pre-commit
DELETED
package/doc/swagger.json
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"openapi": "3.0.1",
|
|
3
|
-
"info": {
|
|
4
|
-
"title": "Apolitical Server",
|
|
5
|
-
"description": "Node.js module to encapsulate Apolitical's express server setup",
|
|
6
|
-
"version": "1.0.0"
|
|
7
|
-
},
|
|
8
|
-
"servers": [
|
|
9
|
-
{
|
|
10
|
-
"url": "http://localhost:3000"
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
"paths": {
|
|
14
|
-
"/example": {
|
|
15
|
-
"get": {
|
|
16
|
-
"description": "Example Endpoint",
|
|
17
|
-
"parameters": [],
|
|
18
|
-
"responses": {
|
|
19
|
-
"200": {
|
|
20
|
-
"description": "Example Response",
|
|
21
|
-
"content": {
|
|
22
|
-
"application/json; charset=utf-8": {
|
|
23
|
-
"schema": {
|
|
24
|
-
"$ref": "#/components/schemas/Response"
|
|
25
|
-
},
|
|
26
|
-
"examples": {
|
|
27
|
-
"message": {
|
|
28
|
-
"summary": "Default Response",
|
|
29
|
-
"value": { "message": "hello" }
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"components": {
|
|
40
|
-
"schemas": {
|
|
41
|
-
"Response": {
|
|
42
|
-
"type": "object",
|
|
43
|
-
"required": ["message"],
|
|
44
|
-
"properties": {
|
|
45
|
-
"message": {
|
|
46
|
-
"type": "string"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
package/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`JWT Apolitical Endpoints GET /jwt should return 200 with token 1`] = `
|
|
4
|
-
Object {
|
|
5
|
-
"admin": true,
|
|
6
|
-
"email": "apolitical.testing@email.com",
|
|
7
|
-
"exp": Any<Number>,
|
|
8
|
-
"iss": "apolitical-testing",
|
|
9
|
-
"name": "Apolitical Testing",
|
|
10
|
-
"role": "public-servant",
|
|
11
|
-
"slug": "apolitical-testing",
|
|
12
|
-
"sub": "login",
|
|
13
|
-
}
|
|
14
|
-
`;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// External Modules
|
|
4
|
-
require('dotenv').config({ path: `${__dirname}/../test.env` });
|
|
5
|
-
const { createContainer, asValue } = require('awilix');
|
|
6
|
-
const { default: jwksClient } = require('mock-jwks');
|
|
7
|
-
// Internal Modules
|
|
8
|
-
const apoliticalTesting = require('@apolitical/testing');
|
|
9
|
-
// API Container
|
|
10
|
-
const apiContainer = require('../../src/container');
|
|
11
|
-
// API Documentation
|
|
12
|
-
const swaggerDocument = require('../../doc/swagger.json');
|
|
13
|
-
// Mocks
|
|
14
|
-
const jwksConfig = require('./mocks/configs/jwks.config');
|
|
15
|
-
const mockEndpoints = require('./mocks/endpoints');
|
|
16
|
-
// Testing environment variables
|
|
17
|
-
const config = apiContainer.resolve('config');
|
|
18
|
-
Object.assign(config.SERVER, {
|
|
19
|
-
PORT: process.env.PORT,
|
|
20
|
-
SESSION_SECRET: process.env.SESSION_SECRET,
|
|
21
|
-
});
|
|
22
|
-
// Test Container
|
|
23
|
-
const testContainer = createContainer();
|
|
24
|
-
testContainer.register(apiContainer.registrations);
|
|
25
|
-
testContainer.register({
|
|
26
|
-
// Internal Modules
|
|
27
|
-
apoliticalTesting: asValue(apoliticalTesting),
|
|
28
|
-
// Configuration
|
|
29
|
-
config: asValue(config),
|
|
30
|
-
// Documentation
|
|
31
|
-
swaggerDocument: asValue(swaggerDocument),
|
|
32
|
-
// Mocks
|
|
33
|
-
mockEndpoints: asValue(mockEndpoints),
|
|
34
|
-
mockJwks: asValue({
|
|
35
|
-
jwksClient,
|
|
36
|
-
jwksConfig,
|
|
37
|
-
}),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
module.exports = testContainer;
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
// Configuration
|
|
7
|
-
const {
|
|
8
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
9
|
-
} = resolve('config');
|
|
10
|
-
// Services
|
|
11
|
-
const { start, stop, errors } = resolve('serverService');
|
|
12
|
-
// Mocks
|
|
13
|
-
const { errorsEndpoint } = resolve('mockEndpoints');
|
|
14
|
-
const { metadata, url, controller } = errorsEndpoint(errors);
|
|
15
|
-
|
|
16
|
-
describe('Error Handling', () => {
|
|
17
|
-
let agents = null;
|
|
18
|
-
|
|
19
|
-
beforeAll(async () => {
|
|
20
|
-
const app = await start({
|
|
21
|
-
port: PORT,
|
|
22
|
-
appLoader: (app) => {
|
|
23
|
-
app.get(url, controller);
|
|
24
|
-
},
|
|
25
|
-
handleErrors: true,
|
|
26
|
-
serviceName: 'test-service',
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterAll(async () => {
|
|
33
|
-
await stop();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('GET /error', () => {
|
|
37
|
-
test('should return 400', async () => {
|
|
38
|
-
const res = await agents.loggedOut.get(url.replace(':code', 400));
|
|
39
|
-
expect(res.statusCode).toEqual(400);
|
|
40
|
-
expect(res.body).toEqual(metadata);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('should return 403', async () => {
|
|
44
|
-
const res = await agents.loggedOut.get(url.replace(':code', 403));
|
|
45
|
-
expect(res.statusCode).toEqual(403);
|
|
46
|
-
expect(res.body).toEqual(metadata);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('should return 404', async () => {
|
|
50
|
-
const res = await agents.loggedOut.get(url.replace(':code', 404));
|
|
51
|
-
expect(res.statusCode).toEqual(404);
|
|
52
|
-
expect(res.body).toEqual(metadata);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('should return 429', async () => {
|
|
56
|
-
const res = await agents.loggedOut.get(url.replace(':code', 429));
|
|
57
|
-
expect(res.statusCode).toEqual(429);
|
|
58
|
-
expect(res.body).toEqual(metadata);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('should return 500', async () => {
|
|
62
|
-
const res = await agents.loggedOut.get(url.replace(':code', 500));
|
|
63
|
-
expect(res.statusCode).toEqual(500);
|
|
64
|
-
expect(res.body).toEqual({ message: metadata.message, errors: [] });
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('should return 500 (unexpected error)', async () => {
|
|
68
|
-
const res = await agents.loggedOut.get(url.replace(':code', 501));
|
|
69
|
-
expect(res.statusCode).toEqual(500);
|
|
70
|
-
expect(res.body).toEqual({ message: 'Unexpected error: Some Unexpected Error', errors: ['unknown-error'] });
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('Error Redirect', () => {
|
|
76
|
-
let agents = null;
|
|
77
|
-
const redirectURL = `http://localhost:${PORT}/not-found`;
|
|
78
|
-
|
|
79
|
-
beforeAll(async () => {
|
|
80
|
-
const app = await start({
|
|
81
|
-
port: PORT,
|
|
82
|
-
appLoader: (app) => {
|
|
83
|
-
app.get(url, controller);
|
|
84
|
-
},
|
|
85
|
-
handleErrors: true,
|
|
86
|
-
redirectURL,
|
|
87
|
-
serviceName: 'test-service',
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
afterAll(async () => {
|
|
94
|
-
await stop();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('should return 307', async () => {
|
|
98
|
-
const res = await agents.loggedOut.get(url.replace(':code', 500));
|
|
99
|
-
expect(res.statusCode).toEqual(307);
|
|
100
|
-
expect(res.headers.location).toEqual(`${redirectURL}?errorMessage=${encodeURI(metadata.message)}`);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
// Configuration
|
|
7
|
-
const {
|
|
8
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
9
|
-
} = resolve('config');
|
|
10
|
-
// Services
|
|
11
|
-
const { start, stop } = resolve('serverService');
|
|
12
|
-
// Mocks
|
|
13
|
-
const { exampleEndpoint } = resolve('mockEndpoints');
|
|
14
|
-
const { url, controller } = exampleEndpoint();
|
|
15
|
-
|
|
16
|
-
describe('Example Endpoint', () => {
|
|
17
|
-
let agents = null;
|
|
18
|
-
|
|
19
|
-
beforeAll(async () => {
|
|
20
|
-
const app = await start({
|
|
21
|
-
port: PORT,
|
|
22
|
-
appLoader: (app) => {
|
|
23
|
-
app.get(url, controller);
|
|
24
|
-
},
|
|
25
|
-
handleErrors: false,
|
|
26
|
-
serviceName: 'test-service',
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterAll(async () => {
|
|
33
|
-
await stop();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('GET /dummy', () => {
|
|
37
|
-
test('should return 200', async () => {
|
|
38
|
-
const res = await agents.loggedOut.get(url);
|
|
39
|
-
expect(res.statusCode).toEqual(200);
|
|
40
|
-
expect(res.body).toEqual({ message: 'some-message' });
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
// Configuration
|
|
7
|
-
const {
|
|
8
|
-
ENDPOINTS: { DOCUMENTATION },
|
|
9
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
10
|
-
} = resolve('config');
|
|
11
|
-
// Documentation
|
|
12
|
-
const swaggerDocument = resolve('swaggerDocument');
|
|
13
|
-
// Services
|
|
14
|
-
const {
|
|
15
|
-
start,
|
|
16
|
-
stop,
|
|
17
|
-
jwt,
|
|
18
|
-
middlewares: { auth },
|
|
19
|
-
} = resolve('serverService');
|
|
20
|
-
// Mocks
|
|
21
|
-
const { jwtApoliticalEndpoint } = resolve('mockEndpoints');
|
|
22
|
-
const { url, controller } = jwtApoliticalEndpoint();
|
|
23
|
-
|
|
24
|
-
describe('JWT Apolitical Endpoints', () => {
|
|
25
|
-
let agents = null;
|
|
26
|
-
|
|
27
|
-
beforeAll(async () => {
|
|
28
|
-
const app = await start({
|
|
29
|
-
port: PORT,
|
|
30
|
-
appLoader: (app) => {
|
|
31
|
-
jwt.apolitical.setup(SESSION_SECRET);
|
|
32
|
-
app.use(auth());
|
|
33
|
-
app.get(url, controller);
|
|
34
|
-
},
|
|
35
|
-
swaggerDocument,
|
|
36
|
-
handleErrors: true,
|
|
37
|
-
serviceName: 'test-service',
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterAll(async () => {
|
|
44
|
-
await stop();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('GET /jwt', () => {
|
|
48
|
-
test('should return 200 with token', async () => {
|
|
49
|
-
const res = await agents.loggedIn.get(url);
|
|
50
|
-
expect(res.statusCode).toEqual(200);
|
|
51
|
-
expect(res.body.user).toMatchSnapshot({ exp: expect.any(Number) });
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('should return 403 without token', async () => {
|
|
55
|
-
const res = await agents.loggedOut.get(url);
|
|
56
|
-
expect(res.statusCode).toEqual(403);
|
|
57
|
-
expect(res.body.message).toEqual('No Apolitical authorization token');
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('GET /docs', () => {
|
|
62
|
-
test('should return 200 with token', async () => {
|
|
63
|
-
const res = await agents.loggedIn.get(DOCUMENTATION);
|
|
64
|
-
expect(res.statusCode).toEqual(200);
|
|
65
|
-
expect(res.headers['content-type']).toEqual('text/html; charset=utf-8');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('should return 301 with token (index file)', async () => {
|
|
69
|
-
const res = await agents.loggedIn.get(`${DOCUMENTATION}index.html`);
|
|
70
|
-
expect(res.statusCode).toEqual(301);
|
|
71
|
-
expect(res.headers.location).toEqual(DOCUMENTATION);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
// Configuration
|
|
7
|
-
const {
|
|
8
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
9
|
-
} = resolve('config');
|
|
10
|
-
// Services
|
|
11
|
-
const { start, stop, jwt } = resolve('serverService');
|
|
12
|
-
// Mocks
|
|
13
|
-
const { jwksClient, jwksConfig } = resolve('mockJwks');
|
|
14
|
-
const { jwtAuth0Endpoint } = resolve('mockEndpoints');
|
|
15
|
-
const { url, controller, auth } = jwtAuth0Endpoint(jwt, jwksConfig);
|
|
16
|
-
|
|
17
|
-
describe('JWT Auth0 Endpoints', () => {
|
|
18
|
-
let agents = null;
|
|
19
|
-
|
|
20
|
-
const jwksMock = jwksClient(jwksConfig.ISSUER);
|
|
21
|
-
|
|
22
|
-
beforeAll(async () => {
|
|
23
|
-
jwksMock.start();
|
|
24
|
-
|
|
25
|
-
const app = await start({
|
|
26
|
-
port: PORT,
|
|
27
|
-
appLoader: (app) => {
|
|
28
|
-
app.get(url, auth, controller);
|
|
29
|
-
},
|
|
30
|
-
handleErrors: true,
|
|
31
|
-
serviceName: 'test-service',
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterAll(async () => {
|
|
38
|
-
jwksMock.stop();
|
|
39
|
-
await stop();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('GET /jwt', () => {
|
|
43
|
-
test('should return 200 with token', async () => {
|
|
44
|
-
const token = jwksMock.token(jwksConfig.PAYLOAD);
|
|
45
|
-
agents.loggedInMyself.set('Authorization', `Bearer ${token}`);
|
|
46
|
-
const res = await agents.loggedInMyself.get(url);
|
|
47
|
-
expect(res.statusCode).toEqual(200);
|
|
48
|
-
expect(res.body).toEqual({ ok: true });
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('should return 403 without token', async () => {
|
|
52
|
-
const res = await agents.loggedOut.get(url);
|
|
53
|
-
expect(res.statusCode).toEqual(403);
|
|
54
|
-
expect(res.body.message).toEqual('Unauthorized error: No authorization token was found');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const DOMAIN = 'some-domain.eu.auth0.com';
|
|
4
|
-
const AUDIENCE = `https://some.url.co/api/auth-api/`;
|
|
5
|
-
const ISSUER = `https://${DOMAIN}/`;
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
DOMAIN,
|
|
9
|
-
AUDIENCE,
|
|
10
|
-
ISSUER,
|
|
11
|
-
PAYLOAD: {
|
|
12
|
-
iss: ISSUER,
|
|
13
|
-
sub: 'some-sub@clients',
|
|
14
|
-
aud: AUDIENCE,
|
|
15
|
-
gty: 'client-credentials',
|
|
16
|
-
},
|
|
17
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const errorArray = ['some-error'];
|
|
4
|
-
const errorMessage = 'Some Error Message';
|
|
5
|
-
|
|
6
|
-
module.exports = (errors) => ({
|
|
7
|
-
metadata: {
|
|
8
|
-
errors: errorArray,
|
|
9
|
-
message: errorMessage,
|
|
10
|
-
},
|
|
11
|
-
url: '/error/:code',
|
|
12
|
-
controller: (req, res, next) => {
|
|
13
|
-
switch (parseInt(req.params.code)) {
|
|
14
|
-
case 400: {
|
|
15
|
-
next(new errors.BadRequest(errorMessage, errorArray));
|
|
16
|
-
break;
|
|
17
|
-
}
|
|
18
|
-
case 403: {
|
|
19
|
-
next(new errors.Forbidden(errorMessage, errorArray));
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
case 404: {
|
|
23
|
-
next(new errors.NotFound(errorMessage, errorArray));
|
|
24
|
-
break;
|
|
25
|
-
}
|
|
26
|
-
case 429: {
|
|
27
|
-
next(new errors.TooManyRequests(errorMessage, errorArray));
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
case 500: {
|
|
31
|
-
next(new errors.InternalError(errorMessage));
|
|
32
|
-
break;
|
|
33
|
-
}
|
|
34
|
-
default: {
|
|
35
|
-
next(new Error('Some Unexpected Error'));
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<meta name="theme-color" content="#000000" />
|
|
7
|
-
<meta property="og:title" content="__OG_TITLE__" />
|
|
8
|
-
<title>Static Server | Apolitical</title>
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
12
|
-
<div id="root"></div>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const exampleEndpoint = require('./example.endpoint');
|
|
4
|
-
const errorsEndpoint = require('./errors.endpoint');
|
|
5
|
-
const jwtApoliticalEndpoint = require('./jwt/apolitical.endpoint');
|
|
6
|
-
const jwtAuth0Endpoint = require('./jwt/auth0.endpoint');
|
|
7
|
-
const staticEndpoint = require('./static.endpoint');
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
exampleEndpoint,
|
|
11
|
-
errorsEndpoint,
|
|
12
|
-
jwtApoliticalEndpoint,
|
|
13
|
-
jwtAuth0Endpoint,
|
|
14
|
-
staticEndpoint,
|
|
15
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = (jwt, { DOMAIN, AUDIENCE, ISSUER }) => ({
|
|
4
|
-
url: '/jwt',
|
|
5
|
-
controller: (req, res) => {
|
|
6
|
-
res.status(200).json({ ok: true });
|
|
7
|
-
},
|
|
8
|
-
auth: jwt.auth0.parse({
|
|
9
|
-
domain: DOMAIN,
|
|
10
|
-
audience: AUDIENCE,
|
|
11
|
-
issuer: ISSUER,
|
|
12
|
-
}),
|
|
13
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
module.exports = () => ({
|
|
7
|
-
baseUrl: '/',
|
|
8
|
-
folderPath: path.join(__dirname),
|
|
9
|
-
indexFilePath: path.join(__dirname, 'index.html'),
|
|
10
|
-
controller: (req, res) => {
|
|
11
|
-
const indexFile = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
|
|
12
|
-
const indexModified = indexFile.replace('__OG_TITLE__', 'some-title');
|
|
13
|
-
res.send(indexModified);
|
|
14
|
-
},
|
|
15
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
const {
|
|
7
|
-
ENDPOINTS: {
|
|
8
|
-
PROBES: { LIVENESS, READINESS },
|
|
9
|
-
},
|
|
10
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
11
|
-
} = resolve('config');
|
|
12
|
-
// Services
|
|
13
|
-
const { start, stop } = resolve('serverService');
|
|
14
|
-
|
|
15
|
-
describe('Probes Endpoints', () => {
|
|
16
|
-
let agents = null;
|
|
17
|
-
|
|
18
|
-
beforeAll(async () => {
|
|
19
|
-
const app = await start({ port: PORT, serviceName: 'test-service' });
|
|
20
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
afterAll(async () => {
|
|
24
|
-
await stop();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('GET /liveness', () => {
|
|
28
|
-
test('should return 200', async () => {
|
|
29
|
-
const res = await agents.loggedOut.get(LIVENESS);
|
|
30
|
-
expect(res.statusCode).toEqual(200);
|
|
31
|
-
expect(res.body).toEqual({});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('GET /readiness', () => {
|
|
36
|
-
test('should return 200', async () => {
|
|
37
|
-
const res = await agents.loggedOut.get(READINESS);
|
|
38
|
-
expect(res.statusCode).toEqual(200);
|
|
39
|
-
expect(res.body).toEqual({});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { resolve } = require('./container');
|
|
4
|
-
// Internal Modules
|
|
5
|
-
const { request } = resolve('apoliticalTesting');
|
|
6
|
-
// Configuration
|
|
7
|
-
const {
|
|
8
|
-
SERVER: { PORT, SESSION_SECRET },
|
|
9
|
-
} = resolve('config');
|
|
10
|
-
// Services
|
|
11
|
-
const { start, stop } = resolve('serverService');
|
|
12
|
-
// Mocks
|
|
13
|
-
const { staticEndpoint } = resolve('mockEndpoints');
|
|
14
|
-
const { baseUrl, folderPath, indexFilePath, controller } = staticEndpoint();
|
|
15
|
-
|
|
16
|
-
describe('Static Server', () => {
|
|
17
|
-
let agents = null;
|
|
18
|
-
|
|
19
|
-
describe('Default static loader', () => {
|
|
20
|
-
beforeAll(async () => {
|
|
21
|
-
const app = await start({
|
|
22
|
-
port: PORT,
|
|
23
|
-
staticFiles: {
|
|
24
|
-
baseUrl,
|
|
25
|
-
folderPath,
|
|
26
|
-
indexFilePath,
|
|
27
|
-
},
|
|
28
|
-
handleErrors: true,
|
|
29
|
-
serviceName: 'test-service',
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
afterAll(async () => {
|
|
36
|
-
await stop();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('GET /index.html', () => {
|
|
40
|
-
test('should return 200 with token', async () => {
|
|
41
|
-
const res = await agents.loggedIn.get('/');
|
|
42
|
-
expect(res.statusCode).toEqual(200);
|
|
43
|
-
expect(res.headers['content-type']).toEqual('text/html; charset=UTF-8');
|
|
44
|
-
expect(res.text.includes('__OG_TITLE__')).toBeTruthy();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('should return 200 without token', async () => {
|
|
48
|
-
const res = await agents.loggedOut.get('/');
|
|
49
|
-
expect(res.statusCode).toEqual(200);
|
|
50
|
-
expect(res.headers['content-type']).toEqual('text/html; charset=UTF-8');
|
|
51
|
-
expect(res.text.includes('__OG_TITLE__')).toBeTruthy();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('Custom static loader', () => {
|
|
57
|
-
beforeAll(async () => {
|
|
58
|
-
const app = await start({
|
|
59
|
-
port: PORT,
|
|
60
|
-
staticFiles: {
|
|
61
|
-
baseUrl,
|
|
62
|
-
folderPath,
|
|
63
|
-
},
|
|
64
|
-
appLoader: (app) => {
|
|
65
|
-
app.get(`${baseUrl}*`, controller);
|
|
66
|
-
},
|
|
67
|
-
handleErrors: true,
|
|
68
|
-
serviceName: 'test-service',
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
agents = request({ sessionSecret: SESSION_SECRET }).generateAgents(app);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
afterAll(async () => {
|
|
75
|
-
await stop();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('GET /index.html', () => {
|
|
79
|
-
test('should return 200 with token', async () => {
|
|
80
|
-
const res = await agents.loggedIn.get('/');
|
|
81
|
-
expect(res.statusCode).toEqual(200);
|
|
82
|
-
expect(res.headers['content-type']).toEqual('text/html; charset=utf-8');
|
|
83
|
-
expect(res.text.includes('some-title')).toBeTruthy();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('should return 200 without token', async () => {
|
|
87
|
-
const res = await agents.loggedOut.get('/');
|
|
88
|
-
expect(res.statusCode).toEqual(200);
|
|
89
|
-
expect(res.headers['content-type']).toEqual('text/html; charset=utf-8');
|
|
90
|
-
expect(res.text.includes('some-title')).toBeTruthy();
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
});
|
package/test/test.env
DELETED