@frangoteam/fuxa-min 1.2.9 → 1.2.10
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/api/index.js +43 -12
- package/api/jwt-helper.js +18 -32
- package/api/projects/index.js +26 -6
- package/dist/assets/i18n/en.json +5 -2
- package/dist/index.html +1 -1
- package/dist/{main.237cd89f3ebaec9c.js → main.020ca34630a3363a.js} +3 -3
- package/main.js +3 -0
- package/package.json +1 -1
- package/runtime/index.js +33 -14
package/api/index.js
CHANGED
|
@@ -24,6 +24,7 @@ var commandApi = require('./command');
|
|
|
24
24
|
const reports = require('../dist/reports.service');
|
|
25
25
|
const reportsApi = new reports.ReportsApiService();
|
|
26
26
|
const verifyApiOrToken = require('./apikeys/verify-api-or-token');
|
|
27
|
+
const utils = require('../runtime/utils');
|
|
27
28
|
|
|
28
29
|
const version = '1.0.0';
|
|
29
30
|
|
|
@@ -107,6 +108,9 @@ function init(_server, _runtime) {
|
|
|
107
108
|
if (tosend.smtp) {
|
|
108
109
|
delete tosend.smtp.password;
|
|
109
110
|
}
|
|
111
|
+
if (tosend.daqstore?.credentials) {
|
|
112
|
+
delete tosend.daqstore.credentials;
|
|
113
|
+
}
|
|
110
114
|
// res.header("Access-Control-Allow-Origin", "*");
|
|
111
115
|
// res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
|
112
116
|
res.json(tosend);
|
|
@@ -131,8 +135,25 @@ function init(_server, _runtime) {
|
|
|
131
135
|
if (req.body.smtp && !req.body.smtp.password && runtime.settings.smtp && runtime.settings.smtp.password) {
|
|
132
136
|
req.body.smtp.password = runtime.settings.smtp.password;
|
|
133
137
|
}
|
|
138
|
+
if (utils.isEmptyObject(req.body.daqstore?.credentials) && runtime.settings.daqstore?.credentials) {
|
|
139
|
+
req.body.daqstore.credentials = runtime.settings.daqstore?.credentials;
|
|
140
|
+
}
|
|
141
|
+
if (!req.body.secretCode && runtime.settings.secretCode) {
|
|
142
|
+
req.body.secretCode = runtime.settings.secretCode;
|
|
143
|
+
}
|
|
144
|
+
const prevAuth = {
|
|
145
|
+
secureEnabled: runtime.settings.secureEnabled,
|
|
146
|
+
tokenExpiresIn: runtime.settings.tokenExpiresIn,
|
|
147
|
+
secretCode: runtime.settings.secretCode
|
|
148
|
+
};
|
|
134
149
|
fs.writeFileSync(runtime.settings.userSettingsFile, JSON.stringify(req.body, null, 4));
|
|
135
150
|
mergeUserSettings(req.body);
|
|
151
|
+
if (prevAuth.secureEnabled !== runtime.settings.secureEnabled ||
|
|
152
|
+
prevAuth.tokenExpiresIn !== runtime.settings.tokenExpiresIn ||
|
|
153
|
+
prevAuth.secretCode !== runtime.settings.secretCode) {
|
|
154
|
+
authJwt.init(runtime.settings.secureEnabled, runtime.settings.secretCode, runtime.settings.tokenExpiresIn);
|
|
155
|
+
authApi.init(runtime, authJwt.secretCode, authJwt.tokenExpiresIn);
|
|
156
|
+
}
|
|
136
157
|
runtime.restart(true).then(function(result) {
|
|
137
158
|
res.end();
|
|
138
159
|
});
|
|
@@ -151,24 +172,31 @@ function init(_server, _runtime) {
|
|
|
151
172
|
res.end();
|
|
152
173
|
} else if (res.statusCode === 403) {
|
|
153
174
|
runtime.logger.error("api post heartbeat: Tocken Expired");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
175
|
+
}
|
|
176
|
+
if (req.body.params) {
|
|
177
|
+
|
|
178
|
+
if (!req.isAuthenticated) {
|
|
179
|
+
// guest → NON puo rinnovare token
|
|
180
|
+
return res.status(200).json({
|
|
181
|
+
message: 'guest'
|
|
160
182
|
});
|
|
161
|
-
} else {
|
|
162
|
-
res.end();
|
|
163
183
|
}
|
|
164
|
-
|
|
165
|
-
|
|
184
|
+
|
|
185
|
+
const token = authJwt.getNewTokenFromRequest(req);
|
|
186
|
+
return res.status(200).json({
|
|
187
|
+
message: 'tokenRefresh',
|
|
188
|
+
token
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Guest heartbeat
|
|
193
|
+
if (req.userId === 'guest') {
|
|
194
|
+
return res.status(200).json({
|
|
166
195
|
message: 'guest',
|
|
167
196
|
token: authJwt.getGuestToken()
|
|
168
197
|
});
|
|
169
|
-
} else {
|
|
170
|
-
res.end();
|
|
171
198
|
}
|
|
199
|
+
return res.end();
|
|
172
200
|
});
|
|
173
201
|
|
|
174
202
|
runtime.logger.info('api: init successful!', true);
|
|
@@ -188,6 +216,9 @@ function mergeUserSettings(settings) {
|
|
|
188
216
|
runtime.settings.userRole = settings.userRole;
|
|
189
217
|
runtime.settings.nodeRedEnabled = settings.nodeRedEnabled;
|
|
190
218
|
runtime.settings.swaggerEnabled = settings.swaggerEnabled;
|
|
219
|
+
if (settings.secretCode) {
|
|
220
|
+
runtime.settings.secretCode = settings.secretCode;
|
|
221
|
+
}
|
|
191
222
|
if (settings.secureEnabled) {
|
|
192
223
|
runtime.settings.tokenExpiresIn = settings.tokenExpiresIn;
|
|
193
224
|
}
|
package/api/jwt-helper.js
CHANGED
|
@@ -53,26 +53,19 @@ function verifyToken (req, res, next) {
|
|
|
53
53
|
if (err) {
|
|
54
54
|
req.userId = "guest";
|
|
55
55
|
req.userGroups = ["guest"];
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
req.userGroups = decoded.groups;
|
|
59
|
-
if (req.headers['x-auth-user']) {
|
|
60
|
-
let user = JSON.parse(req.headers['x-auth-user']);
|
|
61
|
-
if (user && user.groups != req.userGroups) {
|
|
62
|
-
res.status(403).json({ error: "unauthorized_error", message: "User Profile Corrupted!" });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
56
|
+
req.isAuthenticated = false;
|
|
57
|
+
return next();
|
|
65
58
|
}
|
|
66
|
-
|
|
59
|
+
req.userId = decoded.id;
|
|
60
|
+
req.userGroups = decoded.groups;
|
|
61
|
+
req.isAuthenticated = true;
|
|
62
|
+
return next();
|
|
67
63
|
});
|
|
68
64
|
} else {
|
|
69
65
|
// notice that no token was provided...}
|
|
70
66
|
req.userId = null;
|
|
71
67
|
req.userGroups = null;
|
|
72
|
-
|
|
73
|
-
// res.status(401).json({ error: "unauthorized_error", message: "Token missing!" });
|
|
74
|
-
// }
|
|
75
|
-
next();
|
|
68
|
+
return next();
|
|
76
69
|
}
|
|
77
70
|
}
|
|
78
71
|
|
|
@@ -110,29 +103,22 @@ function requireAuth (req, res, next) {
|
|
|
110
103
|
} else {
|
|
111
104
|
req.userId = decoded.id;
|
|
112
105
|
req.userGroups = decoded.groups;
|
|
113
|
-
if (req.headers['x-auth-user']) {
|
|
114
|
-
let user = JSON.parse(req.headers['x-auth-user']);
|
|
115
|
-
if (user && user.groups != req.userGroups) {
|
|
116
|
-
return res.status(403).json({ error: "unauthorized_error", message: "User Profile Corrupted!" });
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
106
|
next();
|
|
120
107
|
}
|
|
121
108
|
});
|
|
122
109
|
}
|
|
123
110
|
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return jwt.sign({
|
|
128
|
-
id: authUser.user,
|
|
129
|
-
groups: authUser.groups
|
|
130
|
-
},
|
|
131
|
-
secretCode, {
|
|
132
|
-
expiresIn: tokenExpiresIn
|
|
133
|
-
});
|
|
111
|
+
function getNewTokenFromRequest(req) {
|
|
112
|
+
if (!req.isAuthenticated) {
|
|
113
|
+
return null;
|
|
134
114
|
}
|
|
135
|
-
|
|
115
|
+
|
|
116
|
+
return jwt.sign({
|
|
117
|
+
id: req.userId,
|
|
118
|
+
groups: req.userGroups
|
|
119
|
+
}, secretCode, {
|
|
120
|
+
expiresIn: tokenExpiresIn
|
|
121
|
+
});
|
|
136
122
|
}
|
|
137
123
|
|
|
138
124
|
function getGuestToken() {
|
|
@@ -165,7 +151,7 @@ module.exports = {
|
|
|
165
151
|
verify: verify,
|
|
166
152
|
verifyToken: verifyToken,
|
|
167
153
|
requireAuth: requireAuth,
|
|
168
|
-
|
|
154
|
+
getNewTokenFromRequest: getNewTokenFromRequest,
|
|
169
155
|
getGuestToken: getGuestToken,
|
|
170
156
|
get secretCode() { return secretCode },
|
|
171
157
|
get tokenExpiresIn() { return tokenExpiresIn },
|
package/api/projects/index.js
CHANGED
|
@@ -190,7 +190,16 @@ module.exports = {
|
|
|
190
190
|
* POST Upload file resource
|
|
191
191
|
* images will be in media file saved
|
|
192
192
|
*/
|
|
193
|
-
prjApp.post('/api/upload', function (req, res) {
|
|
193
|
+
prjApp.post('/api/upload', secureFnc, function (req, res) {
|
|
194
|
+
const permission = checkGroupsFnc(req);
|
|
195
|
+
if (res.statusCode === 403) {
|
|
196
|
+
runtime.logger.error("api get device: Tocken Expired");
|
|
197
|
+
return;
|
|
198
|
+
} else if (!authJwt.haveAdminPermission(permission)) {
|
|
199
|
+
res.status(401).json({error:"unauthorized_error", message: "Unauthorized!"});
|
|
200
|
+
runtime.logger.error("api get device: Unauthorized");
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
194
203
|
const file = req.body.resource;
|
|
195
204
|
const destination = req.body.destination;
|
|
196
205
|
try {
|
|
@@ -209,10 +218,21 @@ module.exports = {
|
|
|
209
218
|
}
|
|
210
219
|
let filePath = path.join(runtime.settings.uploadFileDir, fullPath || fileName);
|
|
211
220
|
if (destination) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
const baseDir = process.versions.electron
|
|
222
|
+
? (process.env.userDir || path.join(os.homedir(), '.fuxa'))
|
|
223
|
+
: runtime.settings.appDir;
|
|
224
|
+
const normalizedDestination = path.normalize(destination).replace(/^([/\\])+/, '');
|
|
225
|
+
const destinationParts = normalizedDestination.split(path.sep);
|
|
226
|
+
const hasTraversal = destinationParts.includes('..');
|
|
227
|
+
if (!normalizedDestination || hasTraversal || path.isAbsolute(destination)) {
|
|
228
|
+
res.status(400).json({error:"invalid_destination", message: "Invalid destination path."});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const destinationDir = path.resolve(baseDir, `_${normalizedDestination}`);
|
|
232
|
+
const resolvedBase = path.resolve(baseDir);
|
|
233
|
+
if (destinationDir !== resolvedBase && !destinationDir.startsWith(resolvedBase + path.sep)) {
|
|
234
|
+
res.status(400).json({error:"invalid_destination", message: "Invalid destination path."});
|
|
235
|
+
return;
|
|
216
236
|
}
|
|
217
237
|
filePath = path.join(destinationDir, fullPath || fileName);
|
|
218
238
|
const dir = path.dirname(filePath);
|
|
@@ -236,4 +256,4 @@ module.exports = {
|
|
|
236
256
|
|
|
237
257
|
return prjApp;
|
|
238
258
|
}
|
|
239
|
-
}
|
|
259
|
+
}
|
package/dist/assets/i18n/en.json
CHANGED
|
@@ -1796,6 +1796,7 @@
|
|
|
1796
1796
|
"dlg.app-settings-logs": "Logs",
|
|
1797
1797
|
"dlg.app-settings-auth-token": "Authentication with Token",
|
|
1798
1798
|
"dlg.app-settings-auth-only-editor": "Only for Editor",
|
|
1799
|
+
"dlg.app-settings-auth-secret": "Secret code",
|
|
1799
1800
|
"dlg.app-auth-disabled": "Disabled",
|
|
1800
1801
|
"dlg.app-auth-expiration-15m": "Enabled with token expiration in 15 min.",
|
|
1801
1802
|
"dlg.app-auth-expiration-1h": "Enabled with token expiration in 1 hour.",
|
|
@@ -1896,7 +1897,8 @@
|
|
|
1896
1897
|
"msg.project-save-error": "Project save failed!",
|
|
1897
1898
|
"msg.project-format-error": "Project wrong format!",
|
|
1898
1899
|
"msg.view-format-error": "View wrong format!",
|
|
1899
|
-
"msg.project-save-unauthorized": "Project save failed! Unauthorized!",
|
|
1900
|
+
"msg.project-save-unauthorized": "Project save failed! Unauthorized! Reload the page and try again.",
|
|
1901
|
+
"msg.settings-save-unauthorized": "Settings save failed! Unauthorized! Reload the page and try again.",
|
|
1900
1902
|
"msg.project-save-ask": "Do you want to leave the project?",
|
|
1901
1903
|
"msg.login-username-required": "Enter a username",
|
|
1902
1904
|
"msg.login-password-required": "Enter a password",
|
|
@@ -1922,5 +1924,6 @@
|
|
|
1922
1924
|
"msg.maps-location-name-exist": "The Maps Location name already exists!",
|
|
1923
1925
|
"msg.text-name-exist": "Text name already exists!",
|
|
1924
1926
|
"msg.texts-text-remove": "Would you like to remove Text '{{value}}'?",
|
|
1925
|
-
"msg.operation-unauthorized": "Operation Unauthorized!"
|
|
1927
|
+
"msg.operation-unauthorized": "Operation Unauthorized!",
|
|
1928
|
+
"msg.secret-code-required": "Secret code required to sign authentication tokens"
|
|
1926
1929
|
}
|
package/dist/index.html
CHANGED
|
@@ -86,6 +86,6 @@
|
|
|
86
86
|
</div>
|
|
87
87
|
</div>
|
|
88
88
|
</app-root>
|
|
89
|
-
<script src="runtime.8ef63094e52a66ba.js" type="module"></script><script src="polyfills.c8e7db9850a3ad8b.js" type="module"></script><script src="scripts.40b60f02658462e4.js" defer></script><script src="main.
|
|
89
|
+
<script src="runtime.8ef63094e52a66ba.js" type="module"></script><script src="polyfills.c8e7db9850a3ad8b.js" type="module"></script><script src="scripts.40b60f02658462e4.js" defer></script><script src="main.020ca34630a3363a.js" type="module"></script></body>
|
|
90
90
|
|
|
91
91
|
</html>
|