@saltcorn/server 1.1.1 → 1.1.2-beta.0
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 +5 -1
- package/app.js +10 -5
- package/auth/admin.js +7 -7
- package/auth/roleadmin.js +3 -3
- package/auth/routes.js +27 -27
- package/package.json +37 -37
- package/public/saltcorn-common.js +5 -1
- package/routes/actions.js +7 -7
- package/routes/admin.js +17 -12
- package/routes/api.js +11 -10
- package/routes/config.js +7 -3
- package/routes/crashlog.js +2 -2
- package/routes/eventlog.js +3 -3
- package/routes/fields.js +5 -5
- package/routes/files.js +32 -31
- package/routes/infoarch.js +4 -3
- package/routes/library.js +1 -1
- package/routes/menu.js +1 -1
- package/routes/models.js +4 -4
- package/routes/notifications.js +7 -4
- package/routes/packs.js +4 -4
- package/routes/page_group.js +3 -3
- package/routes/page_groupedit.js +5 -5
- package/routes/pageedit.js +10 -10
- package/routes/plugins.js +12 -9
- package/routes/registry.js +1 -1
- package/routes/search.js +1 -1
- package/routes/sync.js +4 -4
- package/routes/tables.js +20 -22
- package/routes/tag_entries.js +2 -2
- package/routes/tags.js +1 -1
- package/routes/tenant.js +4 -4
- package/routes/utils.js +3 -3
- package/routes/view.js +7 -7
- package/routes/viewedit.js +11 -11
- package/s3storage.js +1 -1
- package/tests/files.test.js +10 -0
- package/tests/plugins.test.js +2 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Notable changes
|
|
2
2
|
|
|
3
|
-
## 1.1.
|
|
3
|
+
## 1.1.2 - In beta
|
|
4
|
+
|
|
5
|
+
* Upgrade a large number of dependencies (express, typescript, oclif, pg, webpack, typescript). Node.js 18+ is require for this release.
|
|
6
|
+
|
|
7
|
+
## 1.1.1 - Released 2 February 2025
|
|
4
8
|
|
|
5
9
|
* Full-text search improvements:
|
|
6
10
|
- An index for full-text search can now be created. When creating an index in
|
package/app.js
CHANGED
|
@@ -139,9 +139,14 @@ const getApp = async (opts = {}) => {
|
|
|
139
139
|
connectSrc: ["'self'", "data:"],
|
|
140
140
|
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
|
|
141
141
|
"script-src-attr": ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
|
|
142
|
-
styleSrc: [
|
|
142
|
+
styleSrc: [
|
|
143
|
+
"'self'",
|
|
144
|
+
"https://fonts.googleapis.com",
|
|
145
|
+
"https://fonts.gstatic.com",
|
|
146
|
+
"'unsafe-inline'",
|
|
147
|
+
],
|
|
143
148
|
imgSrc: ["'self'", "data:"],
|
|
144
|
-
fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"
|
|
149
|
+
fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"],
|
|
145
150
|
"form-action": ["'self'", "javascript:"],
|
|
146
151
|
},
|
|
147
152
|
},
|
|
@@ -155,7 +160,7 @@ const getApp = async (opts = {}) => {
|
|
|
155
160
|
helmetOptions.contentSecurityPolicy = false;
|
|
156
161
|
|
|
157
162
|
if (cross_domain_iframe) helmetOptions.xFrameOptions = false;
|
|
158
|
-
app.use(helmet(helmetOptions));
|
|
163
|
+
// app.use(helmet(helmetOptions));
|
|
159
164
|
|
|
160
165
|
// TODO ch find a better solution
|
|
161
166
|
if (getState().getConfig("cors_enabled", true)) app.use(cors());
|
|
@@ -260,7 +265,7 @@ const getApp = async (opts = {}) => {
|
|
|
260
265
|
new CustomStrategy((req, done) => {
|
|
261
266
|
loginAttempt();
|
|
262
267
|
async function loginAttempt() {
|
|
263
|
-
const { remember, _csrf, dest, ...userobj } = req.body;
|
|
268
|
+
const { remember, _csrf, dest, ...userobj } = req.body || {};
|
|
264
269
|
if (!is.objVals(is.str).check(userobj))
|
|
265
270
|
return done(
|
|
266
271
|
null,
|
|
@@ -455,7 +460,7 @@ Sitemap: ${base}sitemap.xml
|
|
|
455
460
|
// file store ensure
|
|
456
461
|
await File.ensure_file_store();
|
|
457
462
|
// 404 handling
|
|
458
|
-
app.get("*", function (req, res) {
|
|
463
|
+
app.get("*any", function (req, res) {
|
|
459
464
|
res.status(404).sendWrap(req.__("Not found"), h1(req.__("Page not found")));
|
|
460
465
|
});
|
|
461
466
|
|
package/auth/admin.js
CHANGED
|
@@ -465,7 +465,7 @@ router.post(
|
|
|
465
465
|
isAdmin,
|
|
466
466
|
error_catcher(async (req, res) => {
|
|
467
467
|
const form = await auth_settings_form(req);
|
|
468
|
-
form.validate(req.body);
|
|
468
|
+
form.validate(req.body || {});
|
|
469
469
|
if (form.hasErrors) {
|
|
470
470
|
send_users_page({
|
|
471
471
|
res,
|
|
@@ -523,7 +523,7 @@ router.post(
|
|
|
523
523
|
isAdmin,
|
|
524
524
|
error_catcher(async (req, res) => {
|
|
525
525
|
const form = await http_settings_form(req);
|
|
526
|
-
form.validate(req.body);
|
|
526
|
+
form.validate(req.body || {});
|
|
527
527
|
if (form.hasErrors) {
|
|
528
528
|
send_users_page({
|
|
529
529
|
res,
|
|
@@ -594,7 +594,7 @@ router.post(
|
|
|
594
594
|
isAdmin,
|
|
595
595
|
error_catcher(async (req, res) => {
|
|
596
596
|
const form = await permissions_settings_form(req);
|
|
597
|
-
form.validate(req.body);
|
|
597
|
+
form.validate(req.body || {});
|
|
598
598
|
if (form.hasErrors) {
|
|
599
599
|
send_users_page({
|
|
600
600
|
res,
|
|
@@ -794,7 +794,7 @@ router.post(
|
|
|
794
794
|
isAdmin,
|
|
795
795
|
error_catcher(async (req, res) => {
|
|
796
796
|
const form = await ssl_form(req);
|
|
797
|
-
form.validate(req.body);
|
|
797
|
+
form.validate(req.body || {});
|
|
798
798
|
if (form.hasErrors) {
|
|
799
799
|
send_users_page({
|
|
800
800
|
res,
|
|
@@ -998,15 +998,15 @@ router.post(
|
|
|
998
998
|
isAdmin,
|
|
999
999
|
error_catcher(async (req, res) => {
|
|
1000
1000
|
let form, sub2;
|
|
1001
|
-
if (req.body.id) {
|
|
1002
|
-
const user = await User.findOne({ id: req.body.id });
|
|
1001
|
+
if ((req.body || {}).id) {
|
|
1002
|
+
const user = await User.findOne({ id: (req.body || {}).id });
|
|
1003
1003
|
form = await userForm(req, user);
|
|
1004
1004
|
sub2 = user.email;
|
|
1005
1005
|
} else {
|
|
1006
1006
|
form = await userForm(req);
|
|
1007
1007
|
sub2 = "New";
|
|
1008
1008
|
}
|
|
1009
|
-
form.validate(req.body);
|
|
1009
|
+
form.validate(req.body || {});
|
|
1010
1010
|
if (form.hasErrors) {
|
|
1011
1011
|
send_users_page({
|
|
1012
1012
|
res,
|
package/auth/roleadmin.js
CHANGED
|
@@ -227,7 +227,7 @@ router.post(
|
|
|
227
227
|
isAdmin,
|
|
228
228
|
error_catcher(async (req, res) => {
|
|
229
229
|
const form = await roleForm(req);
|
|
230
|
-
form.validate(req.body);
|
|
230
|
+
form.validate(req.body || {});
|
|
231
231
|
if (form.hasErrors) {
|
|
232
232
|
send_users_page({
|
|
233
233
|
res,
|
|
@@ -265,7 +265,7 @@ router.post(
|
|
|
265
265
|
error_catcher(async (req, res) => {
|
|
266
266
|
const { id } = req.params;
|
|
267
267
|
const layout_by_role = getState().getConfigCopy("layout_by_role");
|
|
268
|
-
layout_by_role[+id] = req.body.layout;
|
|
268
|
+
layout_by_role[+id] = (req.body || {}).layout;
|
|
269
269
|
await getState().setConfig("layout_by_role", layout_by_role);
|
|
270
270
|
req.flash("success", req.__(`Saved layout for role`));
|
|
271
271
|
|
|
@@ -286,7 +286,7 @@ router.post(
|
|
|
286
286
|
const twofa_policy_by_role = getState().getConfigCopy(
|
|
287
287
|
"twofa_policy_by_role"
|
|
288
288
|
);
|
|
289
|
-
twofa_policy_by_role[+id] = req.body.policy;
|
|
289
|
+
twofa_policy_by_role[+id] = (req.body || {}).policy;
|
|
290
290
|
await getState().setConfig("twofa_policy_by_role", twofa_policy_by_role);
|
|
291
291
|
req.flash("success", req.__(`Saved 2FA policy for role`));
|
|
292
292
|
|
package/auth/routes.js
CHANGED
|
@@ -432,9 +432,9 @@ router.post(
|
|
|
432
432
|
"/reset",
|
|
433
433
|
error_catcher(async (req, res) => {
|
|
434
434
|
const result = await User.resetPasswordWithToken({
|
|
435
|
-
email: req.body.email,
|
|
436
|
-
reset_password_token: req.body.token,
|
|
437
|
-
password: req.body.password,
|
|
435
|
+
email: (req.body || {}).email,
|
|
436
|
+
reset_password_token: (req.body || {}).token,
|
|
437
|
+
password: (req.body || {}).password,
|
|
438
438
|
});
|
|
439
439
|
if (result.success) {
|
|
440
440
|
req.flash(
|
|
@@ -457,7 +457,7 @@ router.post(
|
|
|
457
457
|
"/forgot",
|
|
458
458
|
error_catcher(async (req, res) => {
|
|
459
459
|
if (getState().getConfig("allow_forgot")) {
|
|
460
|
-
const { email } = req.body;
|
|
460
|
+
const { email } = req.body || {};
|
|
461
461
|
const u = await User.findOne({ email });
|
|
462
462
|
const respond = () => {
|
|
463
463
|
req.flash("success", req.__("Email with password reset link sent"));
|
|
@@ -614,7 +614,7 @@ router.post(
|
|
|
614
614
|
const hasUsers = await User.nonEmpty();
|
|
615
615
|
if (!hasUsers) {
|
|
616
616
|
const form = loginForm(req, true);
|
|
617
|
-
form.validate(req.body);
|
|
617
|
+
form.validate(req.body || {});
|
|
618
618
|
|
|
619
619
|
if (form.hasErrors) {
|
|
620
620
|
form.action = "/auth/create_first_user";
|
|
@@ -784,7 +784,7 @@ router.post(
|
|
|
784
784
|
const form = await getNewUserForm(new_user_form, req, !req.user.email);
|
|
785
785
|
form.action = "/auth/signup_final_ext";
|
|
786
786
|
|
|
787
|
-
await form.asyncValidate(req.body);
|
|
787
|
+
await form.asyncValidate(req.body || {});
|
|
788
788
|
if (form.hasErrors) {
|
|
789
789
|
res.sendAuthWrap(new_user_form, form, getAuthLinks("signup", true));
|
|
790
790
|
return;
|
|
@@ -846,7 +846,7 @@ router.post(
|
|
|
846
846
|
});
|
|
847
847
|
}
|
|
848
848
|
}
|
|
849
|
-
await form.asyncValidate(req.body);
|
|
849
|
+
await form.asyncValidate(req.body || {});
|
|
850
850
|
if (form.hasErrors) {
|
|
851
851
|
res.sendAuthWrap(new_user_form, form, getAuthLinks("signup", true));
|
|
852
852
|
} else if (form.values.email && !check_email_mask(form.values.email)) {
|
|
@@ -961,7 +961,7 @@ router.post(
|
|
|
961
961
|
req,
|
|
962
962
|
false
|
|
963
963
|
);
|
|
964
|
-
await signup_form.asyncValidate(req.body);
|
|
964
|
+
await signup_form.asyncValidate(req.body || {});
|
|
965
965
|
if (signup_form.hasErrors) {
|
|
966
966
|
signup_form.action = "/auth/signup";
|
|
967
967
|
res.sendAuthWrap(
|
|
@@ -1010,7 +1010,7 @@ router.post(
|
|
|
1010
1010
|
}
|
|
1011
1011
|
|
|
1012
1012
|
const form = await default_signup_form(req);
|
|
1013
|
-
await form.asyncValidate(req.body);
|
|
1013
|
+
await form.asyncValidate(req.body || {});
|
|
1014
1014
|
|
|
1015
1015
|
if (form.hasErrors) {
|
|
1016
1016
|
form.action = "/auth/signup";
|
|
@@ -1049,9 +1049,9 @@ router.post(
|
|
|
1049
1049
|
*/
|
|
1050
1050
|
function handler(req, res) {
|
|
1051
1051
|
console.log(
|
|
1052
|
-
`Failed login attempt for: ${req.body
|
|
1053
|
-
|
|
1054
|
-
)}`
|
|
1052
|
+
`Failed login attempt for: ${(req.body || {}).email} from ${
|
|
1053
|
+
req.ip
|
|
1054
|
+
} UA ${req.get("User-Agent")}`
|
|
1055
1055
|
);
|
|
1056
1056
|
req.flash(
|
|
1057
1057
|
"error",
|
|
@@ -1084,7 +1084,7 @@ const userLimiter = rateLimit({
|
|
|
1084
1084
|
// TBD create config parameter
|
|
1085
1085
|
windowMs: 5 * 60 * 1000, // 5 minutes
|
|
1086
1086
|
max: 3, // limit each IP to 100 requests per windowMs
|
|
1087
|
-
keyGenerator: (req) => userIdKey(req.body),
|
|
1087
|
+
keyGenerator: (req) => userIdKey(req.body || {}),
|
|
1088
1088
|
handler,
|
|
1089
1089
|
});
|
|
1090
1090
|
|
|
@@ -1111,14 +1111,14 @@ router.post(
|
|
|
1111
1111
|
}),
|
|
1112
1112
|
error_catcher(async (req, res) => {
|
|
1113
1113
|
ipLimiter.resetKey(req.ip);
|
|
1114
|
-
userLimiter.resetKey(userIdKey(req.body));
|
|
1114
|
+
userLimiter.resetKey(userIdKey(req.body || {}));
|
|
1115
1115
|
if (req.user.pending_user) {
|
|
1116
1116
|
res.redirect("/auth/twofa/login/totp");
|
|
1117
1117
|
return;
|
|
1118
1118
|
}
|
|
1119
1119
|
let maxAge = null;
|
|
1120
1120
|
if (req.session.cookie)
|
|
1121
|
-
if (req.body.remember) {
|
|
1121
|
+
if ((req.body || {}).remember) {
|
|
1122
1122
|
const setDur = +getState().getConfig("cookie_duration_remember", 720);
|
|
1123
1123
|
if (setDur) {
|
|
1124
1124
|
maxAge = setDur * 60 * 60 * 1000;
|
|
@@ -1147,10 +1147,10 @@ router.post(
|
|
|
1147
1147
|
if (getState().get2FApolicy(req.user) === "Mandatory") {
|
|
1148
1148
|
res.redirect("/auth/twofa/setup/totp");
|
|
1149
1149
|
} else if (
|
|
1150
|
-
req.body.dest &&
|
|
1151
|
-
is_relative_url(decodeURIComponent(req.body.dest))
|
|
1150
|
+
(req.body || {}).dest &&
|
|
1151
|
+
is_relative_url(decodeURIComponent((req.body || {}).dest))
|
|
1152
1152
|
) {
|
|
1153
|
-
res.redirect(decodeURIComponent(req.body.dest));
|
|
1153
|
+
res.redirect(decodeURIComponent((req.body || {}).dest));
|
|
1154
1154
|
} else res.redirect("/");
|
|
1155
1155
|
})
|
|
1156
1156
|
);
|
|
@@ -1566,9 +1566,9 @@ router.post(
|
|
|
1566
1566
|
loggedIn,
|
|
1567
1567
|
error_catcher(async (req, res) => {
|
|
1568
1568
|
const u = await User.findForSession({ id: req.user.id });
|
|
1569
|
-
const newlang = available_languages[req.body.locale];
|
|
1569
|
+
const newlang = available_languages[(req.body || {}).locale];
|
|
1570
1570
|
if (newlang && u) {
|
|
1571
|
-
await u.set_language(req.body.locale);
|
|
1571
|
+
await u.set_language((req.body || {}).locale);
|
|
1572
1572
|
req.login(u.session_object, function (err) {
|
|
1573
1573
|
if (!err) {
|
|
1574
1574
|
req.flash("success", req.__("Language changed to %s", newlang));
|
|
@@ -1656,7 +1656,7 @@ router.post(
|
|
|
1656
1656
|
"/set-email",
|
|
1657
1657
|
error_catcher(async (req, res) => {
|
|
1658
1658
|
const form = setEmailForm(req);
|
|
1659
|
-
form.validate(req.body);
|
|
1659
|
+
form.validate(req.body || {});
|
|
1660
1660
|
if (form.hasErrors || !req.user || !req.user.id) {
|
|
1661
1661
|
res.sendWrap(req.__("Set Email"), renderForm(form, req.csrfToken()));
|
|
1662
1662
|
return;
|
|
@@ -1706,7 +1706,7 @@ router.post(
|
|
|
1706
1706
|
);
|
|
1707
1707
|
return;
|
|
1708
1708
|
}
|
|
1709
|
-
if (req.body.new_password && user.password) {
|
|
1709
|
+
if ((req.body || {}).new_password && user.password) {
|
|
1710
1710
|
const pwform = changPwForm(req);
|
|
1711
1711
|
|
|
1712
1712
|
pwform.fields[0].validator = (oldpw) => {
|
|
@@ -1715,7 +1715,7 @@ router.post(
|
|
|
1715
1715
|
else return req.__("Password does not match");
|
|
1716
1716
|
};
|
|
1717
1717
|
|
|
1718
|
-
pwform.validate(req.body);
|
|
1718
|
+
pwform.validate(req.body || {});
|
|
1719
1719
|
|
|
1720
1720
|
if (pwform.hasErrors) {
|
|
1721
1721
|
res.sendWrap(
|
|
@@ -1738,7 +1738,7 @@ router.post(
|
|
|
1738
1738
|
json() {},
|
|
1739
1739
|
redirect() {},
|
|
1740
1740
|
};
|
|
1741
|
-
await view.runPost({ id: user.id }, req.body, {
|
|
1741
|
+
await view.runPost({ id: user.id }, req.body || {}, {
|
|
1742
1742
|
req,
|
|
1743
1743
|
res: fakeRes,
|
|
1744
1744
|
redirect: "/auth/settings",
|
|
@@ -1773,7 +1773,7 @@ router.all(
|
|
|
1773
1773
|
return;
|
|
1774
1774
|
}
|
|
1775
1775
|
verifier.action = "/auth/verification-flow";
|
|
1776
|
-
const wfres = await verifier.run(req.body || {}, req);
|
|
1776
|
+
const wfres = await verifier.run(req.body || {} || {}, req);
|
|
1777
1777
|
if (wfres.flash) req.flash(wfres.flash[0], wfres.flash[1]);
|
|
1778
1778
|
if (wfres.renderForm) {
|
|
1779
1779
|
res.sendWrap(
|
|
@@ -1860,7 +1860,7 @@ router.post(
|
|
|
1860
1860
|
}
|
|
1861
1861
|
|
|
1862
1862
|
const form = totpForm(req);
|
|
1863
|
-
form.validate(req.body);
|
|
1863
|
+
form.validate(req.body || {});
|
|
1864
1864
|
if (form.hasErrors) {
|
|
1865
1865
|
req.flash("danger", req.__("Error processing form"));
|
|
1866
1866
|
console.log("Error processing form");
|
|
@@ -1918,7 +1918,7 @@ router.post(
|
|
|
1918
1918
|
error_catcher(async (req, res) => {
|
|
1919
1919
|
const user = await User.findOne({ id: req.user.id });
|
|
1920
1920
|
const form = totpForm(req, "/auth/twofa/disable/totp");
|
|
1921
|
-
form.validate(req.body);
|
|
1921
|
+
form.validate(req.body || {});
|
|
1922
1922
|
if (form.hasErrors) {
|
|
1923
1923
|
req.flash("danger", req.__("Error processing form"));
|
|
1924
1924
|
res.redirect("/auth/twofa/disable/totp");
|
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2-beta.0",
|
|
4
4
|
"description": "Server app for Saltcorn, open-source no-code platform",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@aws-sdk/client-s3": "^3.
|
|
10
|
-
"@saltcorn/base-plugin": "1.1.
|
|
11
|
-
"@saltcorn/builder": "1.1.
|
|
12
|
-
"@saltcorn/data": "1.1.
|
|
13
|
-
"@saltcorn/admin-models": "1.1.
|
|
14
|
-
"@saltcorn/filemanager": "1.1.
|
|
15
|
-
"@saltcorn/markup": "1.1.
|
|
16
|
-
"@saltcorn/plugins-loader": "1.1.
|
|
17
|
-
"@saltcorn/sbadmin2": "1.1.
|
|
9
|
+
"@aws-sdk/client-s3": "^3.735.0",
|
|
10
|
+
"@saltcorn/base-plugin": "1.1.2-beta.0",
|
|
11
|
+
"@saltcorn/builder": "1.1.2-beta.0",
|
|
12
|
+
"@saltcorn/data": "1.1.2-beta.0",
|
|
13
|
+
"@saltcorn/admin-models": "1.1.2-beta.0",
|
|
14
|
+
"@saltcorn/filemanager": "1.1.2-beta.0",
|
|
15
|
+
"@saltcorn/markup": "1.1.2-beta.0",
|
|
16
|
+
"@saltcorn/plugins-loader": "1.1.2-beta.0",
|
|
17
|
+
"@saltcorn/sbadmin2": "1.1.2-beta.0",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
|
-
"adm-zip": "0.5.
|
|
20
|
+
"adm-zip": "0.5.16",
|
|
21
21
|
"connect-flash": "^0.1.1",
|
|
22
|
-
"connect-pg-simple": "^
|
|
23
|
-
"content-disposition": "^0.5.
|
|
22
|
+
"connect-pg-simple": "^9.0.1",
|
|
23
|
+
"content-disposition": "^0.5.4",
|
|
24
24
|
"contractis": "^0.1.0",
|
|
25
|
-
"cookie-parser": "^1.4.
|
|
26
|
-
"cookie-session": "^1.
|
|
25
|
+
"cookie-parser": "^1.4.7",
|
|
26
|
+
"cookie-session": "^2.1.0",
|
|
27
27
|
"cors": "2.8.5",
|
|
28
28
|
"csurf": "^1.11.0",
|
|
29
|
-
"csv-stringify": "^
|
|
30
|
-
"dockerode": "~4.0.
|
|
31
|
-
"express": "^
|
|
32
|
-
"express-fileupload": "^1.1
|
|
29
|
+
"csv-stringify": "^6.5.2",
|
|
30
|
+
"dockerode": "~4.0.4",
|
|
31
|
+
"express": "^5.0.1",
|
|
32
|
+
"express-fileupload": "^1.5.1",
|
|
33
33
|
"express-promise-router": "^3.0.3",
|
|
34
|
-
"express-rate-limit": "^5.
|
|
35
|
-
"express-session": "^1.
|
|
34
|
+
"express-rate-limit": "^7.5.0",
|
|
35
|
+
"express-session": "^1.18.1",
|
|
36
36
|
"greenlock": "^4.0.4",
|
|
37
37
|
"greenlock-express": "^4.0.3",
|
|
38
|
-
"helmet": "^
|
|
38
|
+
"helmet": "^8.0.0",
|
|
39
39
|
"i18n": "^0.15.1",
|
|
40
|
-
"imapflow": "1.0.
|
|
41
|
-
"jsonwebtoken": "^9.0.
|
|
42
|
-
"markdown-it": "^
|
|
43
|
-
"moment": "^2.
|
|
40
|
+
"imapflow": "1.0.178",
|
|
41
|
+
"jsonwebtoken": "^9.0.2",
|
|
42
|
+
"markdown-it": "^14.1.0",
|
|
43
|
+
"moment": "^2.30.1",
|
|
44
44
|
"multer": "1.4.5-lts.1",
|
|
45
45
|
"multer-s3": "^3.0.1",
|
|
46
46
|
"node-fetch": "2.6.9",
|
|
47
|
-
"node-watch": "^0.7.
|
|
47
|
+
"node-watch": "^0.7.4",
|
|
48
48
|
"notp": "2.0.3",
|
|
49
49
|
"npm-registry-fetch": "17.1.0",
|
|
50
|
-
"passport": "^0.
|
|
50
|
+
"passport": "^0.7.0",
|
|
51
51
|
"passport-custom": "^1.1.1",
|
|
52
52
|
"passport-http-bearer": "^1.0.1",
|
|
53
53
|
"passport-jwt": "4.0.1",
|
|
54
54
|
"passport-totp": "0.0.2",
|
|
55
|
-
"pg": "^8.
|
|
55
|
+
"pg": "^8.13.1",
|
|
56
56
|
"pluralize": "^8.0.0",
|
|
57
57
|
"qrcode": "1.5.1",
|
|
58
58
|
"resize-with-sharp-or-jimp": "0.1.8",
|
|
59
|
-
"semver": "^7.6.
|
|
60
|
-
"socket.io": "4.
|
|
61
|
-
"systeminformation": "^5.
|
|
59
|
+
"semver": "^7.6.3",
|
|
60
|
+
"socket.io": "4.8.1",
|
|
61
|
+
"systeminformation": "^5.25.11",
|
|
62
62
|
"thirty-two": "1.0.2",
|
|
63
|
-
"tmp-promise": "^3.0.
|
|
64
|
-
"ua-parser-js": "^
|
|
65
|
-
"underscore": "1.13.
|
|
66
|
-
"uuid": "^
|
|
63
|
+
"tmp-promise": "^3.0.3",
|
|
64
|
+
"ua-parser-js": "^2.0.0",
|
|
65
|
+
"underscore": "1.13.7",
|
|
66
|
+
"uuid": "^11.0.5"
|
|
67
67
|
},
|
|
68
68
|
"optionalDependencies": {
|
|
69
|
-
"connect-sqlite3": "^0.9.
|
|
69
|
+
"connect-sqlite3": "^0.9.15",
|
|
70
70
|
"sd-notify": "^2.8.0"
|
|
71
71
|
},
|
|
72
72
|
"repository": "github:saltcorn/saltcorn",
|
|
@@ -1120,7 +1120,11 @@ function initialize_page() {
|
|
|
1120
1120
|
decodeURIComponent($(that).attr("data-explainers"))
|
|
1121
1121
|
);
|
|
1122
1122
|
var currentVal = explainers[$(that).val()];
|
|
1123
|
-
$("#" + id).html(
|
|
1123
|
+
$("#" + id).html(
|
|
1124
|
+
`<strong>${
|
|
1125
|
+
$(that).find("option:selected").text() || $(that).val()
|
|
1126
|
+
}</strong>: ${currentVal}`
|
|
1127
|
+
);
|
|
1124
1128
|
if (currentVal) $("#" + id).show();
|
|
1125
1129
|
else $("#" + id).hide();
|
|
1126
1130
|
}
|
package/routes/actions.js
CHANGED
|
@@ -424,7 +424,7 @@ router.post(
|
|
|
424
424
|
error_catcher(async (req, res) => {
|
|
425
425
|
const form = await triggerForm(req);
|
|
426
426
|
|
|
427
|
-
form.validate(req.body);
|
|
427
|
+
form.validate(req.body || {});
|
|
428
428
|
if (form.hasErrors) {
|
|
429
429
|
send_events_page({
|
|
430
430
|
res,
|
|
@@ -471,7 +471,7 @@ router.post(
|
|
|
471
471
|
|
|
472
472
|
const form = await triggerForm(req, trigger);
|
|
473
473
|
|
|
474
|
-
form.validate(req.body);
|
|
474
|
+
form.validate(req.body || {});
|
|
475
475
|
if (form.hasErrors) {
|
|
476
476
|
send_events_page({
|
|
477
477
|
res,
|
|
@@ -1097,7 +1097,7 @@ router.post(
|
|
|
1097
1097
|
fields: cfgFields,
|
|
1098
1098
|
});
|
|
1099
1099
|
}
|
|
1100
|
-
form.validate(req.body);
|
|
1100
|
+
form.validate(req.body || {});
|
|
1101
1101
|
if (form.hasErrors) {
|
|
1102
1102
|
if (req.xhr) {
|
|
1103
1103
|
res.status(400).json({ error: form.errorSummary });
|
|
@@ -1304,7 +1304,7 @@ router.post(
|
|
|
1304
1304
|
* @function
|
|
1305
1305
|
*/
|
|
1306
1306
|
router.get(
|
|
1307
|
-
"/stepedit/:trigger_id/:step_id
|
|
1307
|
+
"/stepedit/:trigger_id{/:step_id}",
|
|
1308
1308
|
isAdminOrHasConfigMinRole("min_role_edit_triggers"),
|
|
1309
1309
|
error_catcher(async (req, res) => {
|
|
1310
1310
|
const { trigger_id, step_id } = req.params;
|
|
@@ -1352,7 +1352,7 @@ router.post(
|
|
|
1352
1352
|
const { trigger_id } = req.params;
|
|
1353
1353
|
const trigger = await Trigger.findOne({ id: trigger_id });
|
|
1354
1354
|
const form = await getWorkflowStepForm(trigger, req);
|
|
1355
|
-
form.validate(req.body);
|
|
1355
|
+
form.validate(req.body || {});
|
|
1356
1356
|
if (form.hasErrors) {
|
|
1357
1357
|
if (req.xhr) {
|
|
1358
1358
|
res.json({ error: form.errorSummary });
|
|
@@ -1451,7 +1451,7 @@ router.post(
|
|
|
1451
1451
|
const { trigger_id } = req.params;
|
|
1452
1452
|
const trigger = await Trigger.findOne({ id: trigger_id });
|
|
1453
1453
|
await WorkflowStep.deleteForTrigger(trigger.id);
|
|
1454
|
-
const description = req.body.description;
|
|
1454
|
+
const description = (req.body || {}).description;
|
|
1455
1455
|
await Trigger.update(trigger.id, { description });
|
|
1456
1456
|
const steps = await getState().functions.copilot_generate_workflow.run(
|
|
1457
1457
|
description,
|
|
@@ -1774,7 +1774,7 @@ router.post(
|
|
|
1774
1774
|
});
|
|
1775
1775
|
|
|
1776
1776
|
const form = await getWorkflowStepUserForm(run, trigger, step, req);
|
|
1777
|
-
form.validate(req.body);
|
|
1777
|
+
form.validate(req.body || {});
|
|
1778
1778
|
if (form.hasErrors) {
|
|
1779
1779
|
const title = "Fill form";
|
|
1780
1780
|
res.sendWrap(title, renderForm(form, req.csrfToken()));
|
package/routes/admin.js
CHANGED
|
@@ -757,7 +757,9 @@ router.get(
|
|
|
757
757
|
return;
|
|
758
758
|
}
|
|
759
759
|
const auto_backup_directory = getState().getConfig("auto_backup_directory");
|
|
760
|
-
res.download(path.join(auto_backup_directory, filename), filename
|
|
760
|
+
res.download(path.join(auto_backup_directory, filename), filename, {
|
|
761
|
+
dotfiles: "allow",
|
|
762
|
+
});
|
|
761
763
|
})
|
|
762
764
|
);
|
|
763
765
|
|
|
@@ -982,7 +984,7 @@ router.post(
|
|
|
982
984
|
isAdmin,
|
|
983
985
|
error_catcher(async (req, res) => {
|
|
984
986
|
const form = await snapshotForm(req);
|
|
985
|
-
form.validate(req.body);
|
|
987
|
+
form.validate(req.body || {});
|
|
986
988
|
|
|
987
989
|
await save_config_from_form(form);
|
|
988
990
|
|
|
@@ -1000,7 +1002,7 @@ router.post(
|
|
|
1000
1002
|
isAdmin,
|
|
1001
1003
|
error_catcher(async (req, res) => {
|
|
1002
1004
|
const form = await backupFilePrefixForm(req);
|
|
1003
|
-
form.validate(req.body);
|
|
1005
|
+
form.validate(req.body || {});
|
|
1004
1006
|
if (form.hasErrors) {
|
|
1005
1007
|
send_admin_page({
|
|
1006
1008
|
res,
|
|
@@ -1029,7 +1031,7 @@ router.post(
|
|
|
1029
1031
|
isAdmin,
|
|
1030
1032
|
error_catcher(async (req, res) => {
|
|
1031
1033
|
const form = await autoBackupForm(req);
|
|
1032
|
-
form.validate(req.body);
|
|
1034
|
+
form.validate(req.body || {});
|
|
1033
1035
|
if (form.hasErrors) {
|
|
1034
1036
|
send_admin_page({
|
|
1035
1037
|
res,
|
|
@@ -1072,7 +1074,7 @@ router.post(
|
|
|
1072
1074
|
* Do Snapshot now
|
|
1073
1075
|
*/
|
|
1074
1076
|
router.post(
|
|
1075
|
-
"/snapshot-now/:snapshotname
|
|
1077
|
+
"/snapshot-now{/:snapshotname}",
|
|
1076
1078
|
isAdmin,
|
|
1077
1079
|
error_catcher(async (req, res) => {
|
|
1078
1080
|
const { snapshotname } = req.params;
|
|
@@ -1629,7 +1631,7 @@ const doInstall = async (req, res, version, deepClean, runPull) => {
|
|
|
1629
1631
|
};
|
|
1630
1632
|
|
|
1631
1633
|
router.post("/install", isAdmin, async (req, res) => {
|
|
1632
|
-
const { version, deep_clean } = req.body;
|
|
1634
|
+
const { version, deep_clean } = req.body || {};
|
|
1633
1635
|
await doInstall(req, res, version, deep_clean === "on", false);
|
|
1634
1636
|
});
|
|
1635
1637
|
|
|
@@ -3349,7 +3351,7 @@ router.post(
|
|
|
3349
3351
|
"/build-mobile-app/finish",
|
|
3350
3352
|
isAdmin,
|
|
3351
3353
|
error_catcher(async (req, res) => {
|
|
3352
|
-
const { out_dir_name, build_dir } = req.body;
|
|
3354
|
+
const { out_dir_name, build_dir } = req.body || {};
|
|
3353
3355
|
const content = await fs.promises.readFile(
|
|
3354
3356
|
path.join(build_dir, "spawnParams.json")
|
|
3355
3357
|
);
|
|
@@ -3435,7 +3437,10 @@ router.post(
|
|
|
3435
3437
|
"/build-mobile-app",
|
|
3436
3438
|
isAdmin,
|
|
3437
3439
|
error_catcher(async (req, res) => {
|
|
3438
|
-
getState().log(
|
|
3440
|
+
getState().log(
|
|
3441
|
+
2,
|
|
3442
|
+
`starting mobile build: ${JSON.stringify(req.body || {})}`
|
|
3443
|
+
);
|
|
3439
3444
|
const msgs = [];
|
|
3440
3445
|
let mode = "full";
|
|
3441
3446
|
let {
|
|
@@ -3460,7 +3465,7 @@ router.post(
|
|
|
3460
3465
|
keystoreFile,
|
|
3461
3466
|
keystoreAlias,
|
|
3462
3467
|
keystorePassword,
|
|
3463
|
-
} = req.body;
|
|
3468
|
+
} = req.body || {};
|
|
3464
3469
|
const receiveShareTriggers = Trigger.find({
|
|
3465
3470
|
when_trigger: "ReceiveMobileShareData",
|
|
3466
3471
|
});
|
|
@@ -3725,7 +3730,7 @@ router.post(
|
|
|
3725
3730
|
isAdmin,
|
|
3726
3731
|
error_catcher(async (req, res) => {
|
|
3727
3732
|
try {
|
|
3728
|
-
const newCfg = { ...req.body };
|
|
3733
|
+
const newCfg = { ...(req.body || {}) };
|
|
3729
3734
|
const excludedPlugins = (await Plugin.find())
|
|
3730
3735
|
.filter(
|
|
3731
3736
|
(plugin) =>
|
|
@@ -3753,7 +3758,7 @@ router.post(
|
|
|
3753
3758
|
isAdmin,
|
|
3754
3759
|
error_catcher(async (req, res) => {
|
|
3755
3760
|
const form = clearAllForm(req);
|
|
3756
|
-
form.validate(req.body);
|
|
3761
|
+
form.validate(req.body || {});
|
|
3757
3762
|
//order: page_groups, pages, views, user fields, tableconstraints, fields, table triggers, table history, tables, plugins, config+crashes+nontable triggers, users
|
|
3758
3763
|
if (form.values.page_groups) {
|
|
3759
3764
|
await PageGroup.delete({});
|
|
@@ -4147,7 +4152,7 @@ router.post(
|
|
|
4147
4152
|
const { name } = req.params;
|
|
4148
4153
|
const code_pages = getState().getConfigCopy("function_code_pages", {});
|
|
4149
4154
|
|
|
4150
|
-
const code = req.body.code;
|
|
4155
|
+
const code = (req.body || {}).code;
|
|
4151
4156
|
await getState().setConfig("function_code_pages", {
|
|
4152
4157
|
...code_pages,
|
|
4153
4158
|
[name]: code,
|