@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 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
- } else if (req.body.params) {
155
- const token = authJwt.getNewToken(req.headers)
156
- if (token) {
157
- res.status(200).json({
158
- message: 'tokenRefresh',
159
- token: token
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
- } else if (req.userId === 'guest') {
165
- res.status(200).json({
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
- } else {
57
- req.userId = decoded.id;
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
- next();
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
- // if (secureEnabled) {
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 getNewToken(headers) {
125
- const authUser = (headers['x-auth-user']) ? JSON.parse(headers['x-auth-user']) : null;
126
- if (authUser) {
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
- return null;
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
- getNewToken: getNewToken,
154
+ getNewTokenFromRequest: getNewTokenFromRequest,
169
155
  getGuestToken: getGuestToken,
170
156
  get secretCode() { return secretCode },
171
157
  get tokenExpiresIn() { return tokenExpiresIn },
@@ -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
- let destinationDir = path.resolve(runtime.settings.appDir, `_${destination}`);
213
- if (process.versions.electron) {
214
- const userDataDir = process.env.userDir || path.join(os.homedir(), '.fuxa');
215
- destinationDir = path.join(userDataDir, `_${destination}`);
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
+ }
@@ -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.237cd89f3ebaec9c.js" type="module"></script></body>
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>