emailengine-app 2.61.2 → 2.61.3

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.61.3](https://github.com/postalsys/emailengine/compare/v2.61.2...v2.61.3) (2026-01-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * prevent 500 error when listing accounts with invalid delegation config ([8651bcc](https://github.com/postalsys/emailengine/commit/8651bcc3c18cd54ee5309b3392915773c355e6c4))
9
+ * update gettext script to include refactored UI route files ([5b2e4a5](https://github.com/postalsys/emailengine/commit/5b2e4a55771f192fb14d030b5e5d08ba860c90ab))
10
+
3
11
  ## [2.61.2](https://github.com/postalsys/emailengine/compare/v2.61.1...v2.61.2) (2026-01-12)
4
12
 
5
13
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "creationTime": "2026-01-09T15:45:52.000000",
2
+ "creationTime": "2026-01-13T15:46:00.000000",
3
3
  "prefixes": [
4
4
  {
5
5
  "ipv6Prefix": "2001:4860:4801:2008::/64"
package/lib/account.js CHANGED
@@ -187,23 +187,34 @@ class Account {
187
187
  }
188
188
  } else if (accountData.oauth2 && accountData.oauth2.auth && accountData.oauth2.auth.delegatedAccount) {
189
189
  accountData.type = 'delegated';
190
- let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
191
- if (delegatedAccount) {
192
- accountData.delegatedAccount = delegatedAccount;
193
- let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
194
- let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
195
- if (delegatedAccountData.oauth2 && delegatedAccountData.oauth2.provider) {
196
- let app;
197
- if (oauthApps.has(delegatedAccountData.oauth2.provider)) {
198
- app = oauthApps.get(delegatedAccountData.oauth2.provider);
199
- } else {
200
- app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
201
- }
202
- oauthApps.set(delegatedAccountData.oauth2.provider, app || null);
203
- if (app && app.baseScopes === 'api') {
204
- accountData.isApi = true;
190
+ try {
191
+ let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
192
+ if (delegatedAccount) {
193
+ accountData.delegatedAccount = delegatedAccount;
194
+ let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
195
+ let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
196
+ if (delegatedAccountData.oauth2 && delegatedAccountData.oauth2.provider) {
197
+ let app;
198
+ if (oauthApps.has(delegatedAccountData.oauth2.provider)) {
199
+ app = oauthApps.get(delegatedAccountData.oauth2.provider);
200
+ } else {
201
+ app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
202
+ }
203
+ oauthApps.set(delegatedAccountData.oauth2.provider, app || null);
204
+ if (app && app.baseScopes === 'api') {
205
+ accountData.isApi = true;
206
+ }
205
207
  }
206
208
  }
209
+ } catch (err) {
210
+ this.logger.warn({
211
+ msg: 'Failed to resolve delegated account',
212
+ account: accountData.account,
213
+ delegatedAccount: accountData.oauth2.auth.delegatedAccount,
214
+ err
215
+ });
216
+ accountData.type = 'invalid';
217
+ accountData.delegationError = err.message;
207
218
  }
208
219
  } else if (accountData.imap && !accountData.imap.disabled) {
209
220
  accountData.type = 'imap';
@@ -240,7 +251,9 @@ class Account {
240
251
 
241
252
  syncTime: accountData.sync,
242
253
 
243
- lastError: formatLastError(accountData)
254
+ lastError: formatLastError(accountData),
255
+
256
+ delegationError: accountData.delegationError || undefined
244
257
  }))
245
258
  };
246
259
 
@@ -26,6 +26,17 @@ const {
26
26
 
27
27
  const { REDIS_PREFIX, MAX_FORM_TTL, NONCE_BYTES } = require('../consts');
28
28
 
29
+ /**
30
+ * Validates that delegation fields are only used with OAuth2 accounts.
31
+ */
32
+ function validateDelegationFields(payload) {
33
+ const auth = payload.oauth2?.auth;
34
+ const hasDelegation = auth?.delegatedUser || auth?.delegatedAccount;
35
+ if (hasDelegation && !payload.oauth2?.provider) {
36
+ throw Boom.badRequest('Delegation fields (delegatedUser, delegatedAccount) require oauth2.provider to be set');
37
+ }
38
+ }
39
+
29
40
  async function init(args) {
30
41
  const {
31
42
  server,
@@ -110,6 +121,9 @@ async function init(args) {
110
121
  };
111
122
  }
112
123
 
124
+ // Validate delegation fields are only used with OAuth2 provider
125
+ validateDelegationFields(request.payload);
126
+
113
127
  let result = await accountObject.create(request.payload);
114
128
  return result;
115
129
  } catch (err) {
@@ -256,6 +270,9 @@ async function init(args) {
256
270
  });
257
271
 
258
272
  try {
273
+ // Validate delegation fields are only used with OAuth2 provider
274
+ validateDelegationFields(request.payload);
275
+
259
276
  return await accountObject.update(request.payload);
260
277
  } catch (err) {
261
278
  request.logger.error({ msg: 'API request failed', err });
@@ -725,7 +725,7 @@ function init(args) {
725
725
  });
726
726
  }
727
727
 
728
- await request.flash({ type: 'danger', message: request.app.gt.gettext(`Couldn't set up account. Try again.`) });
728
+ await request.flash({ type: 'danger', message: request.app.gt.gettext("Couldn't set up account. Try again.") });
729
729
  request.logger.error({ msg: 'Failed to process account', err });
730
730
 
731
731
  return h
@@ -992,7 +992,7 @@ function init(args) {
992
992
  });
993
993
  }
994
994
 
995
- await request.flash({ type: 'danger', message: request.app.gt.gettext(`Couldn't set up account. Try again.`) });
995
+ await request.flash({ type: 'danger', message: request.app.gt.gettext("Couldn't set up account. Try again.") });
996
996
  request.logger.error({ msg: 'Failed to process account', err });
997
997
 
998
998
  return h
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emailengine-app",
3
- "version": "2.61.2",
3
+ "version": "2.61.3",
4
4
  "private": false,
5
5
  "productTitle": "EmailEngine",
6
6
  "description": "Email Sync Engine",
@@ -17,7 +17,7 @@
17
17
  "build-dist": "pkg --compress Brotli package.json && npm install && node winconf.js",
18
18
  "build-dist-fast": "pkg --debug package.json && npm install && node winconf.js",
19
19
  "licenses": "license-checker --excludePackages 'emailengine-app' --json | node list-generate.js > static/licenses.html",
20
- "gettext": "find ./views -name \"*.hbs\" -print0 | xargs -0 xgettext-template -L Handlebars -o translations/messages.pot --force-po && jsxgettext lib/routes-ui.js workers/api.js lib/tools.js lib/autodetect-imap-settings.js -j -o translations/messages.pot",
20
+ "gettext": "find ./views -name \"*.hbs\" -print0 | xargs -0 xgettext-template -L Handlebars -o translations/messages.pot --force-po && jsxgettext lib/routes-ui.js workers/api.js lib/tools.js lib/autodetect-imap-settings.js lib/ui-routes/account-routes.js lib/ui-routes/admin-config-routes.js lib/ui-routes/admin-entities-routes.js -j -o translations/messages.pot",
21
21
  "prepare-docker": "echo \"EE_DOCKER_LEGACY=$EE_DOCKER_LEGACY\" >> system.env && cat system.env",
22
22
  "update": "rm -rf node_modules package-lock.json && ncu -u && npm install && ./copy-static-files.sh && npm run licenses && npm run gettext",
23
23
  "test-gmail-api": "node lib/email-client/gmail-client.js --dbs.redis=redis://127.0.0.1/11",