@joystick.js/node-canary 0.0.0-canary.5 → 0.0.0-canary.51
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/_package.json +1 -1
- package/dist/app/accounts/getBrowserSafeUser.js +2 -1
- package/dist/app/accounts/hasLoginTokenExpired.js +1 -2
- package/dist/app/databases/mongodb/index.js +1 -1
- package/dist/app/getBrowserSafeRequest.js +3 -2
- package/dist/app/index.js +15 -2
- package/dist/app/middleware/index.js +4 -5
- package/dist/app/middleware/render.js +6 -4
- package/dist/app/sanitizeAPIResponse.js +1 -6
- package/dist/app/validateSession.js +3 -0
- package/dist/email/templates/reset-password.js +0 -1
- package/dist/index.js +7 -2
- package/dist/lib/escapeHTML.js +9 -0
- package/dist/lib/escapeKeyValuePair.js +13 -0
- package/dist/lib/getBuildPath.js +1 -1
- package/dist/lib/getSSLCertificates.js +1 -1
- package/dist/lib/log.js +0 -3
- package/dist/lib/nodeUrlPolyfills.js +7 -11
- package/dist/ssr/index.js +3 -2
- package/package.json +1 -1
- package/dist/app/accounts/roles/index.test.js +0 -123
- package/dist/app/index.test.js +0 -575
- package/dist/app/middleware/sanitizeQueryParameters.js +0 -16
- package/dist/email/send.test.js +0 -37
package/_package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isObject } from "../../validation/lib/typeValidators";
|
|
2
|
+
import escapeKeyValuePair from "../../lib/escapeKeyValuePair.js";
|
|
2
3
|
var getBrowserSafeUser_default = (user = null) => {
|
|
3
4
|
if (!user || !isObject(user)) {
|
|
4
5
|
return null;
|
|
@@ -16,7 +17,7 @@ var getBrowserSafeUser_default = (user = null) => {
|
|
|
16
17
|
return fields;
|
|
17
18
|
}
|
|
18
19
|
}, {});
|
|
19
|
-
return browserSafeUser;
|
|
20
|
+
return escapeKeyValuePair(browserSafeUser);
|
|
20
21
|
};
|
|
21
22
|
export {
|
|
22
23
|
getBrowserSafeUser_default as default
|
|
@@ -5,8 +5,7 @@ var hasLoginTokenExpired_default = async (res, token = null, tokenExpiresAt = nu
|
|
|
5
5
|
unsetAuthenticationCookie(res);
|
|
6
6
|
return true;
|
|
7
7
|
}
|
|
8
|
-
const
|
|
9
|
-
const hasExpired = process.env.NODE_ENV === "test" ? _dayjs().isAfter(_dayjs(tokenExpiresAt)) : dayjs().isAfter(dayjs(tokenExpiresAt));
|
|
8
|
+
const hasExpired = dayjs().isAfter(dayjs(tokenExpiresAt));
|
|
10
9
|
if (hasExpired) {
|
|
11
10
|
unsetAuthenticationCookie(res);
|
|
12
11
|
return true;
|
|
@@ -17,7 +17,7 @@ var mongodb_default = async (settings = {}, databasePort = 2610) => {
|
|
|
17
17
|
const connectionOptions = {
|
|
18
18
|
useNewUrlParser: true,
|
|
19
19
|
useUnifiedTopology: true,
|
|
20
|
-
ssl: !process.env.NODE_ENV
|
|
20
|
+
ssl: !["development", "test"].includes(process.env.NODE_ENV),
|
|
21
21
|
...settings?.options || {}
|
|
22
22
|
};
|
|
23
23
|
if (settings?.options?.ca) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import getBrowserSafeUser from "./accounts/getBrowserSafeUser";
|
|
2
|
+
import escapeKeyValuePair from "../lib/escapeKeyValuePair.js";
|
|
2
3
|
var getBrowserSafeRequest_default = (req = {}) => {
|
|
3
4
|
const browserSafeRequest = {};
|
|
4
|
-
browserSafeRequest.params = req.params;
|
|
5
|
-
browserSafeRequest.query = req.query;
|
|
5
|
+
browserSafeRequest.params = escapeKeyValuePair(req.params);
|
|
6
|
+
browserSafeRequest.query = escapeKeyValuePair(req.query);
|
|
6
7
|
browserSafeRequest.context = {
|
|
7
8
|
user: getBrowserSafeUser(req.context.user)
|
|
8
9
|
};
|
package/dist/app/index.js
CHANGED
|
@@ -53,6 +53,7 @@ class App {
|
|
|
53
53
|
this.initWebsockets(options?.websockets || {});
|
|
54
54
|
this.initDevelopmentRoutes();
|
|
55
55
|
this.initAccounts();
|
|
56
|
+
this.initTests();
|
|
56
57
|
this.initDeploy();
|
|
57
58
|
this.initAPI(options?.api);
|
|
58
59
|
this.initRoutes(options?.routes);
|
|
@@ -143,7 +144,9 @@ class App {
|
|
|
143
144
|
process.BUILD_ERROR = JSON.parse(message);
|
|
144
145
|
}
|
|
145
146
|
});
|
|
146
|
-
|
|
147
|
+
if (process.env.NODE_ENV !== "test") {
|
|
148
|
+
console.log(`App running at: http://localhost:${express.port}`);
|
|
149
|
+
}
|
|
147
150
|
}
|
|
148
151
|
setMachineId() {
|
|
149
152
|
generateMachineId();
|
|
@@ -156,6 +159,16 @@ class App {
|
|
|
156
159
|
fs.writeFileSync("./.joystick/PROCESS_ID", `${generateId(32)}`);
|
|
157
160
|
}
|
|
158
161
|
}
|
|
162
|
+
initTests() {
|
|
163
|
+
if (process.env.NODE_ENV === "test") {
|
|
164
|
+
this.express.app.get("/api/_test/bootstrap", async (req, res) => {
|
|
165
|
+
res.status(200).send({
|
|
166
|
+
ping: "pong",
|
|
167
|
+
query: req?.query
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
159
172
|
initDeploy() {
|
|
160
173
|
if (process.env.NODE_ENV === "production" && process.env.IS_PUSH_DEPLOYED) {
|
|
161
174
|
this.express.app.get("/api/_push/pre-version", async (req, res) => {
|
|
@@ -401,7 +414,7 @@ class App {
|
|
|
401
414
|
});
|
|
402
415
|
}
|
|
403
416
|
initDevelopmentRoutes() {
|
|
404
|
-
if (process.env.NODE_ENV
|
|
417
|
+
if (["development", "test"].includes(process.env.NODE_ENV)) {
|
|
405
418
|
this.express.app.get("/api/_joystick/sessions", async (req, res) => {
|
|
406
419
|
const sessions = Array.from(this.sessions.entries())?.reduce((acc = {}, [key, value]) => {
|
|
407
420
|
acc[key] = value;
|
|
@@ -3,6 +3,7 @@ import compression from "compression";
|
|
|
3
3
|
import cookieParser from "cookie-parser";
|
|
4
4
|
import favicon from "serve-favicon";
|
|
5
5
|
import fs from "fs";
|
|
6
|
+
import { __package } from "../../index.js";
|
|
6
7
|
import insecure from "./insecure.js";
|
|
7
8
|
import requestMethods from "./requestMethods.js";
|
|
8
9
|
import bodyParser from "./bodyParser.js";
|
|
@@ -14,11 +15,10 @@ import runUserQuery from "../accounts/runUserQuery.js";
|
|
|
14
15
|
import replaceBackslashesWithForwardSlashes from "../../lib/replaceBackslashesWithForwardSlashes.js";
|
|
15
16
|
import replaceFileProtocol from "../../lib/replaceFileProtocol.js";
|
|
16
17
|
import getBuildPath from "../../lib/getBuildPath.js";
|
|
17
|
-
import sanitizeQueryParameters from "./sanitizeQueryParameters.js";
|
|
18
18
|
import session from "./session.js";
|
|
19
19
|
import csp from "./csp.js";
|
|
20
20
|
const cwd = replaceFileProtocol(replaceBackslashesWithForwardSlashes(process.cwd()));
|
|
21
|
-
const faviconPath =
|
|
21
|
+
const faviconPath = "public/favicon.ico";
|
|
22
22
|
var middleware_default = ({
|
|
23
23
|
app,
|
|
24
24
|
port,
|
|
@@ -41,7 +41,6 @@ var middleware_default = ({
|
|
|
41
41
|
}
|
|
42
42
|
next();
|
|
43
43
|
});
|
|
44
|
-
app.use(sanitizeQueryParameters);
|
|
45
44
|
app.use(requestMethods);
|
|
46
45
|
if (cspConfig) {
|
|
47
46
|
app.use((req, res, next) => csp(req, res, next, cspConfig));
|
|
@@ -54,7 +53,7 @@ var middleware_default = ({
|
|
|
54
53
|
});
|
|
55
54
|
app.use("/_joystick/utils/process.js", (_req, res) => {
|
|
56
55
|
res.set("Content-Type", "text/javascript");
|
|
57
|
-
const processPolyfill = fs.readFileSync(`${
|
|
56
|
+
const processPolyfill = fs.readFileSync(`${__package}/app/utils/process.js`, "utf-8");
|
|
58
57
|
res.send(processPolyfill.replace("${NODE_ENV}", process.env.NODE_ENV));
|
|
59
58
|
});
|
|
60
59
|
app.use("/_joystick/index.client.js", express.static(`${buildPath}index.client.js`, {
|
|
@@ -65,7 +64,7 @@ var middleware_default = ({
|
|
|
65
64
|
app.use("/_joystick/ui", express.static(`${buildPath}ui`, { eTag: false, maxAge: "0" }));
|
|
66
65
|
app.use("/_joystick/hmr/client.js", (_req, res) => {
|
|
67
66
|
res.set("Content-Type", "text/javascript");
|
|
68
|
-
const hmrClient = fs.readFileSync(`${
|
|
67
|
+
const hmrClient = fs.readFileSync(`${__package}/app/middleware/hmr/client.js`, "utf-8");
|
|
69
68
|
res.send(hmrClient.replace("${process.env.PORT}", parseInt(process.env.PORT, 10) + 1));
|
|
70
69
|
});
|
|
71
70
|
app.use(favicon(faviconPath));
|
|
@@ -8,6 +8,8 @@ import generateErrorPage from "../../lib/generateErrorPage.js";
|
|
|
8
8
|
import replaceFileProtocol from "../../lib/replaceFileProtocol.js";
|
|
9
9
|
import replaceBackslashesWithForwardSlashes from "../../lib/replaceBackslashesWithForwardSlashes.js";
|
|
10
10
|
import getBuildPath from "../../lib/getBuildPath.js";
|
|
11
|
+
import escapeHTML from "../../lib/escapeHTML.js";
|
|
12
|
+
import escapeKeyValuePair from "../../lib/escapeKeyValuePair.js";
|
|
11
13
|
const generateHash = (input = "") => {
|
|
12
14
|
return crypto.createHash("sha256").update(input).digest("hex");
|
|
13
15
|
};
|
|
@@ -65,10 +67,10 @@ const getCachedHTML = ({ cachePath, cacheFileName, currentDiff }) => {
|
|
|
65
67
|
const getUrl = (request = {}) => {
|
|
66
68
|
const [path = null] = request.url?.split("?");
|
|
67
69
|
return {
|
|
68
|
-
params: request.params,
|
|
69
|
-
query: request.query,
|
|
70
|
-
route: request.route.path,
|
|
71
|
-
path
|
|
70
|
+
params: escapeKeyValuePair(request.params),
|
|
71
|
+
query: escapeKeyValuePair(request.query),
|
|
72
|
+
route: escapeHTML(request.route.path),
|
|
73
|
+
path: escapeHTML(path)
|
|
72
74
|
};
|
|
73
75
|
};
|
|
74
76
|
const getFile = async (buildPath = "") => {
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import util from "util";
|
|
2
|
-
import
|
|
3
|
-
const escapeHTML = (string = "") => {
|
|
4
|
-
return String(string).replace(/[&<>"'`=\/]/g, function(match) {
|
|
5
|
-
return HTML_ENTITY_MAP[match];
|
|
6
|
-
});
|
|
7
|
-
};
|
|
2
|
+
import escapeHTML from "../lib/escapeHTML.js";
|
|
8
3
|
const sanitizeAPIResponse = (data = null) => {
|
|
9
4
|
let sanitizedData = data;
|
|
10
5
|
if (!util.isString(sanitizedData) && !util.isObject(sanitizedData) && !Array.isArray(sanitizedData)) {
|
|
@@ -3,6 +3,9 @@ var validateSession_default = (req = null, res = null, sessions = null) => {
|
|
|
3
3
|
const sessionToken = req?.cookies?.joystickSession;
|
|
4
4
|
const csrfToken = req?.headers["x-joystick-csrf"];
|
|
5
5
|
const session = sessions?.get(sessionToken);
|
|
6
|
+
if (csrfToken === "joystick_test") {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
6
9
|
if (!session || session && session.csrf !== csrfToken) {
|
|
7
10
|
res.status(403).send(JSON.stringify({
|
|
8
11
|
errors: [formatAPIError(new Error("Unauthorized request."))]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import ui from "@joystick.js/ui";
|
|
2
2
|
const ResetPassword = ui.component({
|
|
3
|
-
id: process.env.NODE_ENV === "test" ? "testComponent1234" : null,
|
|
4
3
|
render: ({ props }) => {
|
|
5
4
|
return `
|
|
6
5
|
<p>A password reset was requested for this email address (${props.emailAddress}). If you requested this reset, click the link below to reset your password:</p>
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import sanitizeHTML from "sanitize-html";
|
|
2
1
|
import fs from "fs";
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import sanitizeHTML from "sanitize-html";
|
|
3
5
|
import _accounts from "./app/accounts";
|
|
4
6
|
import _action from "./action/index.js";
|
|
5
7
|
import _websockets from "./websockets";
|
|
@@ -27,16 +29,18 @@ const sanitize = {
|
|
|
27
29
|
allowedTags: sanitizeHTML.defaults.allowedTags
|
|
28
30
|
}
|
|
29
31
|
};
|
|
32
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
33
|
+
const __package = dirname(currentFilePath);
|
|
30
34
|
const __filename = nodeUrlPolyfills.__filename;
|
|
31
35
|
const __dirname = nodeUrlPolyfills.__dirname;
|
|
32
36
|
const id = generateId;
|
|
33
37
|
const origin = getOrigin();
|
|
34
38
|
const settings = loadSettings();
|
|
35
|
-
console.log("HERE", fs.readFileSync(__dirname("dist/app/utils/process.js"), "utf-8"));
|
|
36
39
|
global.joystick = {
|
|
37
40
|
id: generateId,
|
|
38
41
|
emitters: {},
|
|
39
42
|
settings,
|
|
43
|
+
__package,
|
|
40
44
|
__dirname,
|
|
41
45
|
__filename
|
|
42
46
|
};
|
|
@@ -58,6 +62,7 @@ var src_default = {
|
|
|
58
62
|
export {
|
|
59
63
|
__dirname,
|
|
60
64
|
__filename,
|
|
65
|
+
__package,
|
|
61
66
|
accounts,
|
|
62
67
|
action,
|
|
63
68
|
src_default as default,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import escapeHTML from "./escapeHTML.js";
|
|
2
|
+
var escapeKeyValuePair_default = (target = {}) => {
|
|
3
|
+
const parameters = Object.entries(target || {});
|
|
4
|
+
for (let i = 0; i < parameters?.length; i += 1) {
|
|
5
|
+
const [key, value] = parameters[i];
|
|
6
|
+
delete target[key];
|
|
7
|
+
target[escapeHTML(key)] = escapeHTML(value);
|
|
8
|
+
}
|
|
9
|
+
return target;
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
escapeKeyValuePair_default as default
|
|
13
|
+
};
|
package/dist/lib/getBuildPath.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
var getBuildPath_default = () => {
|
|
3
|
-
if (process.env.NODE_ENV
|
|
3
|
+
if (["development", "test"].includes(process.env.NODE_ENV) || fs.existsSync(".joystick/build")) {
|
|
4
4
|
return ".joystick/build/";
|
|
5
5
|
}
|
|
6
6
|
return "";
|
|
@@ -6,7 +6,7 @@ var getSSLCertificates_default = (ssl = null) => {
|
|
|
6
6
|
const keyPath = process.env.IS_PUSH_DEPLOYED ? pushKeyPath : ssl?.key || null;
|
|
7
7
|
const certExists = fs.existsSync(certPath);
|
|
8
8
|
const keyExists = fs.existsSync(keyPath);
|
|
9
|
-
if (process.env.NODE_ENV
|
|
9
|
+
if (["development", "test"].includes(process.env.NODE_ENV) || !certExists || !keyExists) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
12
|
return {
|
package/dist/lib/log.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fileURLToPath } from "url";
|
|
2
|
+
import { dirname } from "path";
|
|
2
3
|
var nodeUrlPolyfills_default = {
|
|
3
|
-
__filename: (url =
|
|
4
|
-
|
|
5
|
-
return "";
|
|
6
|
-
}
|
|
7
|
-
return new URL("", url).pathname;
|
|
4
|
+
__filename: (url = "") => {
|
|
5
|
+
return fileURLToPath(url);
|
|
8
6
|
},
|
|
9
|
-
__dirname: (url =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
return new URL(".", url).pathname;
|
|
7
|
+
__dirname: (url = "") => {
|
|
8
|
+
const currentFilePath = fileURLToPath(url);
|
|
9
|
+
return dirname(currentFilePath);
|
|
14
10
|
}
|
|
15
11
|
};
|
|
16
12
|
export {
|
package/dist/ssr/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
+
import { __package } from "../index.js";
|
|
2
3
|
import get from "../api/get";
|
|
3
4
|
import set from "../api/set";
|
|
4
5
|
import getBrowserSafeRequest from "../app/getBrowserSafeRequest";
|
|
@@ -184,7 +185,7 @@ const getBaseCSS = (baseHTMLName = "") => {
|
|
|
184
185
|
try {
|
|
185
186
|
const customBaseCSSPathForEmail = baseHTMLName ? `${process.cwd()}/email/base_${baseHTMLName}.css` : null;
|
|
186
187
|
const customDefaultBaseCSSPathForEmail = `${process.cwd()}/email/base.css`;
|
|
187
|
-
const defaultBaseCSSPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.css` : `${
|
|
188
|
+
const defaultBaseCSSPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.css` : `${__package}/email/templates/base.css`;
|
|
188
189
|
let baseCSSPathToFetch = defaultBaseCSSPathForEmail;
|
|
189
190
|
if (fs.existsSync(customDefaultBaseCSSPathForEmail)) {
|
|
190
191
|
baseCSSPathToFetch = customDefaultBaseCSSPathForEmail;
|
|
@@ -242,7 +243,7 @@ const getBaseHTML = (isEmailRender = false, baseEmailHTMLName = "") => {
|
|
|
242
243
|
if (isEmailRender) {
|
|
243
244
|
const customBaseHTMLPathForEmail = baseEmailHTMLName ? `${process.cwd()}/email/base_${baseEmailHTMLName}.html` : null;
|
|
244
245
|
const customDefaultBaseHTMLPathForEmail = `${process.cwd()}/email/base.html`;
|
|
245
|
-
const defaultBaseHTMLPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.html` : `${
|
|
246
|
+
const defaultBaseHTMLPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.html` : `${__package}/email/templates/base.html`;
|
|
246
247
|
baseHTMLPathToFetch = defaultBaseHTMLPathForEmail;
|
|
247
248
|
if (fs.existsSync(customDefaultBaseHTMLPathForEmail)) {
|
|
248
249
|
baseHTMLPathToFetch = customDefaultBaseHTMLPathForEmail;
|
package/package.json
CHANGED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { jest } from "@jest/globals";
|
|
2
|
-
import { killPortProcess } from "kill-port-process";
|
|
3
|
-
import setAppSettingsForTest from "../../../tests/lib/setAppSettingsForTest";
|
|
4
|
-
import startTestDatabase from "../../../tests/lib/databases/start";
|
|
5
|
-
import stopTestDatabase from "../../../tests/lib/databases/stop";
|
|
6
|
-
import { beforeEach, expect, test } from "@jest/globals";
|
|
7
|
-
import roles from "./index";
|
|
8
|
-
import accounts from "../index";
|
|
9
|
-
jest.mock("../../../../node_modules/dayjs", () => {
|
|
10
|
-
const _dayjs = jest.requireActual("../../../../node_modules/dayjs");
|
|
11
|
-
const _utc = jest.requireActual("../../../../node_modules/dayjs/plugin/utc");
|
|
12
|
-
_dayjs.extend(_utc);
|
|
13
|
-
return () => _dayjs("2022-01-01T00:00:00.000Z");
|
|
14
|
-
});
|
|
15
|
-
setAppSettingsForTest({
|
|
16
|
-
"config": {
|
|
17
|
-
"databases": [
|
|
18
|
-
{
|
|
19
|
-
"provider": "mongodb",
|
|
20
|
-
"users": true,
|
|
21
|
-
"options": {}
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
"i18n": {
|
|
25
|
-
"defaultLanguage": "en-US"
|
|
26
|
-
},
|
|
27
|
-
"middleware": {},
|
|
28
|
-
"email": {
|
|
29
|
-
"from": "app@test.com",
|
|
30
|
-
"smtp": {
|
|
31
|
-
"host": "fake.email.com",
|
|
32
|
-
"port": 587,
|
|
33
|
-
"username": "test",
|
|
34
|
-
"password": "password"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"global": {},
|
|
39
|
-
"public": {},
|
|
40
|
-
"private": {}
|
|
41
|
-
});
|
|
42
|
-
global.joystick = {
|
|
43
|
-
settings: {
|
|
44
|
-
config: {
|
|
45
|
-
databases: [{
|
|
46
|
-
"provider": "mongodb",
|
|
47
|
-
"users": true,
|
|
48
|
-
"options": {}
|
|
49
|
-
}]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const app = (await import("../../index")).default;
|
|
54
|
-
let instance;
|
|
55
|
-
describe("app/accounts/roles/index.js", () => {
|
|
56
|
-
beforeAll(async () => {
|
|
57
|
-
process.env.PORT = 3600;
|
|
58
|
-
});
|
|
59
|
-
beforeEach(async () => {
|
|
60
|
-
instance = await app({});
|
|
61
|
-
});
|
|
62
|
-
afterEach(async () => {
|
|
63
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
64
|
-
instance.server.close();
|
|
65
|
-
}
|
|
66
|
-
await killPortProcess(process.env.PORT);
|
|
67
|
-
});
|
|
68
|
-
afterAll(async () => {
|
|
69
|
-
});
|
|
70
|
-
test("roles.add adds role to roles collection in database", async () => {
|
|
71
|
-
await roles.add("admin");
|
|
72
|
-
const roleExists = await process.databases.mongodb.collection("roles").findOne({ role: "admin" });
|
|
73
|
-
expect(!!roleExists).toBe(true);
|
|
74
|
-
});
|
|
75
|
-
test("roles.remove removes role from roles collection in database", async () => {
|
|
76
|
-
await roles.add("admin");
|
|
77
|
-
await roles.remove("admin");
|
|
78
|
-
const roleExists = await process.databases.mongodb.collection("roles").findOne({ role: "admin" });
|
|
79
|
-
expect(!!roleExists).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
test("roles.list returns a list of roles in the roles collection in database", async () => {
|
|
82
|
-
await roles.add("admin");
|
|
83
|
-
await roles.add("manager");
|
|
84
|
-
await roles.add("employee");
|
|
85
|
-
const rolesInDatabase = await roles.list();
|
|
86
|
-
await roles.remove("admin");
|
|
87
|
-
await roles.remove("manager");
|
|
88
|
-
await roles.remove("employee");
|
|
89
|
-
expect(rolesInDatabase).toEqual(["admin", "manager", "employee"]);
|
|
90
|
-
});
|
|
91
|
-
test("roles.grant adds role to user in users collection in database", async () => {
|
|
92
|
-
await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
|
|
93
|
-
const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
|
|
94
|
-
await roles.grant(user?.userId, "admin");
|
|
95
|
-
await roles.grant(user?.userId, "rolethatdoesntexist");
|
|
96
|
-
const userAfterGrant = await process.databases.mongodb.collection("users").findOne({ _id: user?.userId });
|
|
97
|
-
const rolesCreated = await process.databases.mongodb.collection("roles").find().toArray();
|
|
98
|
-
expect(userAfterGrant?.roles?.includes("admin")).toBe(true);
|
|
99
|
-
expect(rolesCreated?.length).toBe(2);
|
|
100
|
-
});
|
|
101
|
-
test("roles.revoke removes role from user in users collection in database", async () => {
|
|
102
|
-
await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
|
|
103
|
-
const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
|
|
104
|
-
await roles.grant(user?.userId, "admin");
|
|
105
|
-
await roles.revoke(user?.userId, "admin");
|
|
106
|
-
const userAfterGrant = await process.databases.mongodb.collection("users").findOne({ _id: user?.userId });
|
|
107
|
-
expect(userAfterGrant?.roles?.includes("admin")).toBe(false);
|
|
108
|
-
});
|
|
109
|
-
test("roles.userHasRole returns true if user has role", async () => {
|
|
110
|
-
await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
|
|
111
|
-
const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
|
|
112
|
-
await roles.grant(user?.userId, "admin");
|
|
113
|
-
const userHasRole = await roles.userHasRole(user?.userId, "admin");
|
|
114
|
-
expect(userHasRole).toBe(true);
|
|
115
|
-
});
|
|
116
|
-
test("roles.userHasRole returns false if user does not have role", async () => {
|
|
117
|
-
await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
|
|
118
|
-
const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
|
|
119
|
-
await roles.grant(user?.userId, "admin");
|
|
120
|
-
const userHasRole = await roles.userHasRole(user?.userId, "manager");
|
|
121
|
-
expect(userHasRole).toBe(false);
|
|
122
|
-
});
|
|
123
|
-
});
|
package/dist/app/index.test.js
DELETED
|
@@ -1,575 +0,0 @@
|
|
|
1
|
-
import { afterAll, afterEach, beforeAll, expect, jest, test } from "@jest/globals";
|
|
2
|
-
import { mockRequest, mockResponse } from "jest-mock-req-res";
|
|
3
|
-
import { killPortProcess } from "kill-port-process";
|
|
4
|
-
import assertRoutesDoNotExistInRegexes from "../tests/lib/assertRoutesDoNotExistInRegexes";
|
|
5
|
-
import assertRoutesExistInRegexes from "../tests/lib/assertRoutesExistInRegexes";
|
|
6
|
-
import setAppSettingsForTest from "../tests/lib/setAppSettingsForTest";
|
|
7
|
-
import startTestDatabase from "../tests/lib/databases/start";
|
|
8
|
-
import stopTestDatabase from "../tests/lib/databases/stop";
|
|
9
|
-
import getRouteRegexes from "../tests/lib/getRouteRegexes";
|
|
10
|
-
jest.mock("../../node_modules/crypto-extra", () => {
|
|
11
|
-
return {
|
|
12
|
-
randomString: () => "abc1234"
|
|
13
|
-
};
|
|
14
|
-
});
|
|
15
|
-
jest.mock("../../node_modules/bcrypt", () => {
|
|
16
|
-
return {
|
|
17
|
-
hashSync: () => "hashed$password",
|
|
18
|
-
compareSync: () => {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
});
|
|
23
|
-
jest.mock("../../node_modules/dayjs", () => {
|
|
24
|
-
const _dayjs = jest.requireActual("../../node_modules/dayjs");
|
|
25
|
-
const _utc = jest.requireActual("../../node_modules/dayjs/plugin/utc");
|
|
26
|
-
_dayjs.extend(_utc);
|
|
27
|
-
return () => _dayjs("2022-01-01T00:00:00.000Z");
|
|
28
|
-
});
|
|
29
|
-
const nodemailer = {
|
|
30
|
-
smtp: {
|
|
31
|
-
sendMail: jest.fn()
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
jest.mock("../../node_modules/nodemailer", () => {
|
|
35
|
-
return {
|
|
36
|
-
createTransport: jest.fn(() => {
|
|
37
|
-
return {
|
|
38
|
-
sendMail: nodemailer.smtp.sendMail
|
|
39
|
-
};
|
|
40
|
-
})
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
jest.mock("../../node_modules/@joystick.js/ui/dist/component/generateId.js", () => {
|
|
44
|
-
return "component1234";
|
|
45
|
-
});
|
|
46
|
-
setAppSettingsForTest({
|
|
47
|
-
"config": {
|
|
48
|
-
"databases": [
|
|
49
|
-
{
|
|
50
|
-
"provider": "mongodb",
|
|
51
|
-
"users": true,
|
|
52
|
-
"options": {}
|
|
53
|
-
}
|
|
54
|
-
],
|
|
55
|
-
"i18n": {
|
|
56
|
-
"defaultLanguage": "en-US"
|
|
57
|
-
},
|
|
58
|
-
"middleware": {},
|
|
59
|
-
"email": {
|
|
60
|
-
"from": "app@test.com",
|
|
61
|
-
"smtp": {
|
|
62
|
-
"host": "fake.email.com",
|
|
63
|
-
"port": 587,
|
|
64
|
-
"username": "test",
|
|
65
|
-
"password": "password"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
"global": {},
|
|
70
|
-
"public": {},
|
|
71
|
-
"private": {}
|
|
72
|
-
});
|
|
73
|
-
const dayjs = (await import("dayjs")).default;
|
|
74
|
-
const app = (await import("./index")).default;
|
|
75
|
-
const generateId = (await import("../lib/generateId")).default;
|
|
76
|
-
global.joystick = {
|
|
77
|
-
settings: {
|
|
78
|
-
config: {
|
|
79
|
-
databases: [{
|
|
80
|
-
"provider": "mongodb",
|
|
81
|
-
"users": true,
|
|
82
|
-
"options": {}
|
|
83
|
-
}]
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
describe("index.js", () => {
|
|
88
|
-
beforeAll(async () => {
|
|
89
|
-
process.env.PORT = 3600;
|
|
90
|
-
await startTestDatabase("mongodb");
|
|
91
|
-
});
|
|
92
|
-
afterEach(async () => {
|
|
93
|
-
await killPortProcess(process.env.PORT);
|
|
94
|
-
});
|
|
95
|
-
afterAll(async () => {
|
|
96
|
-
await stopTestDatabase();
|
|
97
|
-
});
|
|
98
|
-
test("registers render-related routes", async () => {
|
|
99
|
-
const instance = await app({});
|
|
100
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
101
|
-
instance.server.close();
|
|
102
|
-
}
|
|
103
|
-
if (instance?.app?._router) {
|
|
104
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
105
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
106
|
-
"/_joystick/heartbeat",
|
|
107
|
-
"/_joystick/utils/process.js",
|
|
108
|
-
"/_joystick/index.client.js",
|
|
109
|
-
"/_joystick/index.css",
|
|
110
|
-
"/_joystick/ui",
|
|
111
|
-
"/_joystick/hmr/client.js"
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
test("registers accounts-related routes", async () => {
|
|
116
|
-
const instance = await app({});
|
|
117
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
118
|
-
instance.server.close();
|
|
119
|
-
}
|
|
120
|
-
if (instance?.app?._router) {
|
|
121
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
122
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
123
|
-
"/api/_accounts/login",
|
|
124
|
-
"/api/_accounts/logout",
|
|
125
|
-
"/api/_accounts/signup",
|
|
126
|
-
"/api/_accounts/recover-password",
|
|
127
|
-
"/api/_accounts/reset-password"
|
|
128
|
-
]);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
test("registers getter routes", async () => {
|
|
132
|
-
const instance = await app({
|
|
133
|
-
api: {
|
|
134
|
-
getters: {
|
|
135
|
-
posts: {
|
|
136
|
-
input: {},
|
|
137
|
-
get: () => {
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
post: {
|
|
141
|
-
input: {},
|
|
142
|
-
get: () => {
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
149
|
-
instance.server.close();
|
|
150
|
-
}
|
|
151
|
-
if (instance?.app?._router) {
|
|
152
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
153
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
154
|
-
"/api/_getters/posts",
|
|
155
|
-
"/api/_getters/post"
|
|
156
|
-
]);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
test("registers setter routes", async () => {
|
|
160
|
-
const instance = await app({
|
|
161
|
-
api: {
|
|
162
|
-
setters: {
|
|
163
|
-
createPost: {
|
|
164
|
-
input: {},
|
|
165
|
-
set: () => {
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
updatePost: {
|
|
169
|
-
input: {},
|
|
170
|
-
set: () => {
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
177
|
-
instance.server.close();
|
|
178
|
-
}
|
|
179
|
-
if (instance?.app?._router) {
|
|
180
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
181
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
182
|
-
"/api/_setters/createPost",
|
|
183
|
-
"/api/_setters/updatePost"
|
|
184
|
-
]);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
test("registers custom routes if passed as function", async () => {
|
|
188
|
-
const instance = await app({
|
|
189
|
-
routes: {
|
|
190
|
-
"/latest": () => {
|
|
191
|
-
},
|
|
192
|
-
"/profile/:_id": () => {
|
|
193
|
-
},
|
|
194
|
-
"/category/:category/posts": () => {
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
if (instance?.app?._router) {
|
|
199
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
200
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
201
|
-
"/latest",
|
|
202
|
-
"/profile/123",
|
|
203
|
-
"/category/tutorials/posts"
|
|
204
|
-
]);
|
|
205
|
-
}
|
|
206
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
207
|
-
instance.server.close();
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
test("does not register custom routes if passed as function not set to a function", async () => {
|
|
211
|
-
const instance = await app({
|
|
212
|
-
routes: {
|
|
213
|
-
"/latest": "function",
|
|
214
|
-
"/profile/:_id": "function",
|
|
215
|
-
"/category/:category/posts": "function"
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
if (instance?.app?._router) {
|
|
219
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
220
|
-
assertRoutesDoNotExistInRegexes(routeRegexes, [
|
|
221
|
-
"/latest",
|
|
222
|
-
"/profile/123",
|
|
223
|
-
"/category/tutorials/posts"
|
|
224
|
-
]);
|
|
225
|
-
}
|
|
226
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
227
|
-
instance.server.close();
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
test("registers custom routes if passed as an object", async () => {
|
|
231
|
-
const instance = await app({
|
|
232
|
-
routes: {
|
|
233
|
-
"/latest": {
|
|
234
|
-
method: "GET",
|
|
235
|
-
handler: () => {
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
"/profile/:_id": {
|
|
239
|
-
method: "POST",
|
|
240
|
-
handler: () => {
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
"/category/:category/posts": {
|
|
244
|
-
method: "PUT",
|
|
245
|
-
handler: () => {
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
251
|
-
instance.server.close();
|
|
252
|
-
}
|
|
253
|
-
if (instance?.app?._router) {
|
|
254
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
255
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
256
|
-
"/latest",
|
|
257
|
-
"/profile/123",
|
|
258
|
-
"/category/tutorials/posts"
|
|
259
|
-
]);
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
test("does not register custom routes if passed as an object without a valid method", async () => {
|
|
263
|
-
const instance = await app({
|
|
264
|
-
routes: {
|
|
265
|
-
"/latest": {
|
|
266
|
-
method: "CAT"
|
|
267
|
-
},
|
|
268
|
-
"/profile/:_id": {
|
|
269
|
-
handler: () => {
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
"/category/:category/posts": {
|
|
273
|
-
method: "PUT",
|
|
274
|
-
handler: () => {
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
280
|
-
instance.server.close();
|
|
281
|
-
}
|
|
282
|
-
if (instance?.app?._router) {
|
|
283
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
284
|
-
assertRoutesDoNotExistInRegexes(routeRegexes, [
|
|
285
|
-
"/latest",
|
|
286
|
-
"/profile/123"
|
|
287
|
-
]);
|
|
288
|
-
assertRoutesExistInRegexes(routeRegexes, [
|
|
289
|
-
"/category/tutorials/posts"
|
|
290
|
-
]);
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
test("does not register custom routes if passed as an object without a handler function", async () => {
|
|
294
|
-
const instance = await app({
|
|
295
|
-
routes: {
|
|
296
|
-
"/latest": {
|
|
297
|
-
method: "GET"
|
|
298
|
-
},
|
|
299
|
-
"/profile/:_id": {
|
|
300
|
-
method: "POST"
|
|
301
|
-
},
|
|
302
|
-
"/category/:category/posts": {
|
|
303
|
-
method: "PUT"
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
308
|
-
instance.server.close();
|
|
309
|
-
}
|
|
310
|
-
if (instance?.app?._router) {
|
|
311
|
-
const routeRegexes = getRouteRegexes(instance.app._router.stack);
|
|
312
|
-
assertRoutesDoNotExistInRegexes(routeRegexes, [
|
|
313
|
-
"/latest",
|
|
314
|
-
"/profile/123",
|
|
315
|
-
"/category/tutorials/posts"
|
|
316
|
-
]);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
test("sets build errors on process", async () => {
|
|
320
|
-
const instance = await app({});
|
|
321
|
-
const testMessage = { id: generateId() };
|
|
322
|
-
process.emit("message", JSON.stringify(testMessage));
|
|
323
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
324
|
-
instance.server.close();
|
|
325
|
-
}
|
|
326
|
-
expect(process.BUILD_ERROR).toEqual(testMessage);
|
|
327
|
-
});
|
|
328
|
-
test("if callback function is assigned to function-based route, it is called as expected", async () => {
|
|
329
|
-
const instance = await app({
|
|
330
|
-
routes: {
|
|
331
|
-
"/test": (req2, res2) => {
|
|
332
|
-
res2.status(200).send("Called as expected.");
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
337
|
-
return stackItem?.route?.path === "/test";
|
|
338
|
-
});
|
|
339
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
340
|
-
instance.server.close();
|
|
341
|
-
}
|
|
342
|
-
const req = mockRequest();
|
|
343
|
-
const res = mockResponse();
|
|
344
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
345
|
-
if (handler) {
|
|
346
|
-
await handler(req, res, () => {
|
|
347
|
-
});
|
|
348
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
349
|
-
expect(res.send).toHaveBeenCalledWith("Called as expected.");
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
test("if callback function is assigned to an object-based route, it is called as expected", async () => {
|
|
353
|
-
const instance = await app({
|
|
354
|
-
routes: {
|
|
355
|
-
"/test": {
|
|
356
|
-
method: "GET",
|
|
357
|
-
handler: (req2, res2) => {
|
|
358
|
-
res2.status(200).send("Called as expected.");
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
364
|
-
return stackItem?.route?.path === "/test";
|
|
365
|
-
});
|
|
366
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
367
|
-
instance.server.close();
|
|
368
|
-
}
|
|
369
|
-
const req = mockRequest();
|
|
370
|
-
const res = mockResponse();
|
|
371
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
372
|
-
if (handler) {
|
|
373
|
-
await handler(req, res, () => {
|
|
374
|
-
});
|
|
375
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
376
|
-
expect(res.send).toHaveBeenCalledWith("Called as expected.");
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
test("verify that a /_accounts/authenticated request will return true if passed a valid cookie", async () => {
|
|
380
|
-
const instance = await app({});
|
|
381
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
382
|
-
return stackItem?.route?.path === "/api/_accounts/authenticated";
|
|
383
|
-
});
|
|
384
|
-
const req = mockRequest({
|
|
385
|
-
cookies: {
|
|
386
|
-
joystickLoginToken: "testToken123",
|
|
387
|
-
joystickLoginTokenExpiresAt: dayjs().add(1, "minute").format()
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
const res = mockResponse();
|
|
391
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
392
|
-
if (handler) {
|
|
393
|
-
await handler(req, res, () => {
|
|
394
|
-
});
|
|
395
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
396
|
-
expect(res.send).toHaveBeenCalledWith('{"status":200,"authenticated":true}');
|
|
397
|
-
}
|
|
398
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
399
|
-
instance.server.close();
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
test("verify that a /_accounts/authenticated request will return false if passed an invalid cookie", async () => {
|
|
403
|
-
const instance = await app({});
|
|
404
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
405
|
-
return stackItem?.route?.path === "/api/_accounts/authenticated";
|
|
406
|
-
});
|
|
407
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
408
|
-
instance.server.close();
|
|
409
|
-
}
|
|
410
|
-
const req = mockRequest({
|
|
411
|
-
cookies: {
|
|
412
|
-
joystickLoginToken: "testToken123",
|
|
413
|
-
joystickLoginTokenExpiresAt: jest.requireActual("../../node_modules/dayjs")().subtract(1, "minute").format()
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
const res = mockResponse();
|
|
417
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
418
|
-
if (handler) {
|
|
419
|
-
await handler(req, res, () => {
|
|
420
|
-
});
|
|
421
|
-
expect(res.status).toHaveBeenCalledWith(401);
|
|
422
|
-
expect(res.send).toHaveBeenCalledWith('{"status":401,"authenticated":false}');
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
test("verify that a /_accounts/signup request will set a cookie and return a user if passed a valid signup request", async () => {
|
|
426
|
-
const instance = await app({});
|
|
427
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
428
|
-
return stackItem?.route?.path === "/api/_accounts/signup";
|
|
429
|
-
});
|
|
430
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
431
|
-
instance.server.close();
|
|
432
|
-
}
|
|
433
|
-
const req = mockRequest({
|
|
434
|
-
body: {
|
|
435
|
-
emailAddress: "test@test.com",
|
|
436
|
-
password: "password",
|
|
437
|
-
metadata: {}
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
const res = mockResponse();
|
|
441
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
442
|
-
if (handler) {
|
|
443
|
-
await handler(req, res, () => {
|
|
444
|
-
});
|
|
445
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginToken", "abc1234", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
446
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginTokenExpiresAt", "2022-01-31T00:00:00Z", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
447
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
448
|
-
expect(res.send).toHaveBeenCalledWith('{"_id":"abc1234","password":"hashed$password","emailAddress":"test@test.com"}');
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
test("verify that a /_accounts/login request will set a cookie and return a user if passed a valid login request", async () => {
|
|
452
|
-
const instance = await app({});
|
|
453
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
454
|
-
return stackItem?.route?.path === "/api/_accounts/login";
|
|
455
|
-
});
|
|
456
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
457
|
-
instance.server.close();
|
|
458
|
-
}
|
|
459
|
-
const req = mockRequest({
|
|
460
|
-
body: {
|
|
461
|
-
emailAddress: "test@test.com",
|
|
462
|
-
password: "password"
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
const res = mockResponse();
|
|
466
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
467
|
-
if (handler) {
|
|
468
|
-
await handler(req, res, () => {
|
|
469
|
-
});
|
|
470
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginToken", "abc1234", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
471
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginTokenExpiresAt", "2022-01-31T00:00:00Z", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
472
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
473
|
-
expect(res.send).toHaveBeenCalledWith('{"_id":"abc1234","emailAddress":"test@test.com"}');
|
|
474
|
-
}
|
|
475
|
-
});
|
|
476
|
-
test("verify that a /_accounts/logout request deletes the cookie", async () => {
|
|
477
|
-
const instance = await app({});
|
|
478
|
-
const loginRoute = instance?.app?._router?.stack.find((stackItem) => {
|
|
479
|
-
return stackItem?.route?.path === "/api/_accounts/login";
|
|
480
|
-
});
|
|
481
|
-
const logoutRoute = instance?.app?._router?.stack.find((stackItem) => {
|
|
482
|
-
return stackItem?.route?.path === "/api/_accounts/logout";
|
|
483
|
-
});
|
|
484
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
485
|
-
instance.server.close();
|
|
486
|
-
}
|
|
487
|
-
const loginRequest = mockRequest({
|
|
488
|
-
body: {
|
|
489
|
-
emailAddress: "test@test.com",
|
|
490
|
-
password: "password"
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
const loginResponse = mockResponse();
|
|
494
|
-
const loginHandler = loginRoute?.route?.stack[0] && loginRoute?.route?.stack[0].handle;
|
|
495
|
-
const logoutRequest = mockRequest();
|
|
496
|
-
const logoutResponse = mockResponse();
|
|
497
|
-
const logoutHandler = logoutRoute?.route?.stack[0] && logoutRoute?.route?.stack[0].handle;
|
|
498
|
-
if (loginHandler && logoutHandler) {
|
|
499
|
-
await loginHandler(loginRequest, loginResponse, () => {
|
|
500
|
-
});
|
|
501
|
-
await logoutHandler(logoutRequest, logoutResponse, () => {
|
|
502
|
-
});
|
|
503
|
-
expect(loginResponse.cookie).toHaveBeenCalledWith("joystickLoginToken", "abc1234", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
504
|
-
expect(loginResponse.cookie).toHaveBeenCalledWith("joystickLoginTokenExpiresAt", "2022-01-31T00:00:00Z", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
505
|
-
expect(logoutResponse.cookie).toHaveBeenCalledWith("joystickLoginToken", null, { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
506
|
-
expect(logoutResponse.cookie).toHaveBeenCalledWith("joystickLoginTokenExpiresAt", null, { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
test("verify that a /_accounts/recover-password request attempts to send an email", async () => {
|
|
510
|
-
const instance = await app({});
|
|
511
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
512
|
-
return stackItem?.route?.path === "/api/_accounts/recover-password";
|
|
513
|
-
});
|
|
514
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
515
|
-
instance.server.close();
|
|
516
|
-
}
|
|
517
|
-
const req = mockRequest({
|
|
518
|
-
body: {
|
|
519
|
-
emailAddress: "test@test.com"
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
const res = mockResponse();
|
|
523
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
524
|
-
if (handler) {
|
|
525
|
-
await handler(req, res, () => {
|
|
526
|
-
});
|
|
527
|
-
expect(nodemailer.smtp.sendMail).toHaveBeenCalledWith({
|
|
528
|
-
from: "app@test.com",
|
|
529
|
-
to: "test@test.com",
|
|
530
|
-
subject: "Reset Your Password",
|
|
531
|
-
html: `<!doctype html>
|
|
532
|
-
<html class="no-js" lang="en">
|
|
533
|
-
<head>
|
|
534
|
-
<meta charset="utf-8">
|
|
535
|
-
<title>Joystick</title>
|
|
536
|
-
|
|
537
|
-
</head>
|
|
538
|
-
<body style="color: #000; font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; font-size: 16px; line-height: 24px;">
|
|
539
|
-
<div id="email"><div js-c="testComponent1234">
|
|
540
|
-
<p>A password reset was requested for this email address (test@test.com). If you requested this reset, click the link below to reset your password:</p>
|
|
541
|
-
<p><a href="http://localhost:3600/reset-password/abc1234">Reset Password</a></p>
|
|
542
|
-
</div></div>
|
|
543
|
-
</body>
|
|
544
|
-
</html>
|
|
545
|
-
`,
|
|
546
|
-
text: "A password reset was requested for this email address (test@test.com). If you\nrequested this reset, click the link below to reset your password:\n\nReset Password [http://localhost:3600/reset-password/abc1234]"
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
});
|
|
550
|
-
test("verify that a /_accounts/reset-password request sets a cookie and returns the user", async () => {
|
|
551
|
-
const instance = await app({});
|
|
552
|
-
const route = instance?.app?._router?.stack.find((stackItem) => {
|
|
553
|
-
return stackItem?.route?.path === "/api/_accounts/reset-password";
|
|
554
|
-
});
|
|
555
|
-
if (instance?.server?.close && typeof instance.server.close === "function") {
|
|
556
|
-
instance.server.close();
|
|
557
|
-
}
|
|
558
|
-
const req = mockRequest({
|
|
559
|
-
body: {
|
|
560
|
-
token: "abc1234",
|
|
561
|
-
password: "test@test.com"
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
const res = mockResponse();
|
|
565
|
-
const handler = route?.route?.stack[0] && route?.route?.stack[0].handle;
|
|
566
|
-
if (handler) {
|
|
567
|
-
await handler(req, res, () => {
|
|
568
|
-
});
|
|
569
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginToken", "abc1234", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
570
|
-
expect(res.cookie).toHaveBeenCalledWith("joystickLoginTokenExpiresAt", "2022-01-31T00:00:00Z", { secure: true, httpOnly: true, expires: dayjs().toDate() });
|
|
571
|
-
expect(res.status).toHaveBeenCalledWith(200);
|
|
572
|
-
expect(res.send).toHaveBeenCalledWith('{"_id":"abc1234","password":"hashed$password","emailAddress":"test@test.com","sessions":[{"token":"abc1234","tokenExpiresAt":"2022-01-31T00:00:00Z"}],"passwordResetTokens":[]}');
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
var sanitizeQueryParameters_default = (req, res, next) => {
|
|
2
|
-
const queryParameters = Object.entries(req?.query);
|
|
3
|
-
const htmlRegex = new RegExp(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g);
|
|
4
|
-
for (let i = 0; i < queryParameters?.length; i += 1) {
|
|
5
|
-
const [key, value] = queryParameters[i];
|
|
6
|
-
const keyHTMLMatches = key?.match(htmlRegex);
|
|
7
|
-
const valueHTMLMatches = value?.match(htmlRegex);
|
|
8
|
-
if (keyHTMLMatches?.length > 0 || valueHTMLMatches?.length > 0) {
|
|
9
|
-
delete req.query[key];
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
next();
|
|
13
|
-
};
|
|
14
|
-
export {
|
|
15
|
-
sanitizeQueryParameters_default as default
|
|
16
|
-
};
|
package/dist/email/send.test.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { jest } from "@jest/globals";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import send from "./send";
|
|
4
|
-
import setAppSettingsForTest from "../tests/lib/setAppSettingsForTest";
|
|
5
|
-
setAppSettingsForTest({
|
|
6
|
-
"config": {
|
|
7
|
-
"databases": [
|
|
8
|
-
{
|
|
9
|
-
"provider": "mongodb",
|
|
10
|
-
"users": true,
|
|
11
|
-
"options": {}
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"i18n": {
|
|
15
|
-
"defaultLanguage": "en-US"
|
|
16
|
-
},
|
|
17
|
-
"middleware": {},
|
|
18
|
-
"email": {
|
|
19
|
-
"from": "app@test.com",
|
|
20
|
-
"smtp": {}
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"global": {},
|
|
24
|
-
"public": {},
|
|
25
|
-
"private": {}
|
|
26
|
-
});
|
|
27
|
-
console.warn = jest.fn();
|
|
28
|
-
describe("send.js", () => {
|
|
29
|
-
test("console.warns an error when bad smtp settings are passed", async () => {
|
|
30
|
-
const result = await send({ template: "test", props: {} });
|
|
31
|
-
expect(result).toBe(null);
|
|
32
|
-
expect(console.warn.mock.calls).toEqual([
|
|
33
|
-
[chalk.redBright("Invalid SMTP settings: config.smtp not defined in settings.test.js")],
|
|
34
|
-
[chalk.redBright("Cannot send email, invalid SMTP settings.")]
|
|
35
|
-
]);
|
|
36
|
-
});
|
|
37
|
-
});
|