emailengine-app 2.70.0 → 2.72.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.
Files changed (60) hide show
  1. package/.github/workflows/codeql.yml +3 -0
  2. package/.github/workflows/e2e.yml +56 -0
  3. package/.github/workflows/test.yml +81 -12
  4. package/.ncurc.js +20 -20
  5. package/CHANGELOG.md +25 -0
  6. package/Gruntfile.js +19 -23
  7. package/bin/emailengine.js +8 -1
  8. package/config/default.toml +5 -0
  9. package/config/e2e.toml +35 -0
  10. package/config/test.toml +5 -0
  11. package/data/google-crawlers.json +1 -1
  12. package/getswagger.sh +4 -0
  13. package/lib/account.js +31 -25
  14. package/lib/api-routes/message-routes.js +125 -121
  15. package/lib/auth-token.js +83 -0
  16. package/lib/delivery-error.js +62 -0
  17. package/lib/document-store.js +22 -1
  18. package/lib/email-client/base-client.js +3 -2
  19. package/lib/email-client/gmail-client.js +33 -1
  20. package/lib/email-client/imap/mailbox.js +2 -2
  21. package/lib/email-client/notification-handler.js +2 -2
  22. package/lib/export.js +12 -0
  23. package/lib/feature-flags.js +6 -0
  24. package/lib/imap-proxy-auth.js +81 -0
  25. package/lib/imapproxy/imap-server.js +8 -103
  26. package/lib/license-beacon.js +367 -0
  27. package/lib/logger.js +11 -1
  28. package/lib/oauth/gmail.js +3 -0
  29. package/lib/oauth/outlook.js +3 -0
  30. package/lib/oauth2-apps.js +100 -11
  31. package/lib/routes-ui.js +2 -1
  32. package/lib/smtp-auth.js +70 -0
  33. package/lib/sub-script.js +8 -2
  34. package/lib/tools.js +26 -2
  35. package/lib/ui-routes/admin-config-routes.js +4 -3
  36. package/lib/ui-routes/document-store-routes.js +7 -1
  37. package/package.json +30 -24
  38. package/playwright.config.js +45 -0
  39. package/sbom.json +1 -1
  40. package/server.js +30 -8
  41. package/static/licenses.html +108 -128
  42. package/test-coverage-plan.md +233 -0
  43. package/translations/de.mo +0 -0
  44. package/translations/de.po +154 -142
  45. package/translations/et.mo +0 -0
  46. package/translations/et.po +129 -131
  47. package/translations/fr.mo +0 -0
  48. package/translations/fr.po +133 -136
  49. package/translations/ja.mo +0 -0
  50. package/translations/ja.po +126 -129
  51. package/translations/messages.pot +37 -37
  52. package/translations/nl.mo +0 -0
  53. package/translations/nl.po +128 -130
  54. package/translations/pl.mo +0 -0
  55. package/translations/pl.po +125 -128
  56. package/views/dashboard.hbs +22 -0
  57. package/workers/api.js +22 -5
  58. package/workers/export.js +58 -43
  59. package/workers/smtp.js +5 -85
  60. package/workers/submit.js +2 -12
package/server.js CHANGED
@@ -121,6 +121,8 @@ const { compare: cv } = require('compare-versions');
121
121
  const Joi = require('joi');
122
122
  const { settingsSchema } = require('./lib/schemas');
123
123
  const settings = require('./lib/settings');
124
+ const { documentStoreFeatureEnabled } = require('./lib/document-store');
125
+ const { attachBeacon, persistBeaconMarkers } = require('./lib/license-beacon');
124
126
  const tokens = require('./lib/tokens');
125
127
 
126
128
  const { checkRateLimit } = require('./lib/rate-limit');
@@ -243,6 +245,9 @@ const API_PROXY = hasEnvValue('EENGINE_API_PROXY') ? getBoolean(readEnvValue('EE
243
245
  // API authentication requirement configuration (default: true)
244
246
  const REQUIRE_API_AUTH = hasEnvValue('EENGINE_REQUIRE_API_AUTH') ? getBoolean(readEnvValue('EENGINE_REQUIRE_API_AUTH')) : null;
245
247
 
248
+ // Opt-out for the license-validation feature beacon (telemetry rides on the existing license call)
249
+ const BEACON_DISABLED = hasEnvValue('EENGINE_BEACON_DISABLED') ? getBoolean(readEnvValue('EENGINE_BEACON_DISABLED')) : false;
250
+
246
251
  // OAuth2 token access configuration
247
252
  const ENABLE_OAUTH_TOKENS_API = hasEnvValue('EENGINE_ENABLE_OAUTH_TOKENS_API') ? getBoolean(readEnvValue('EENGINE_ENABLE_OAUTH_TOKENS_API')) : null;
248
253
 
@@ -1857,6 +1862,21 @@ let licenseCheckHandler = async opts => {
1857
1862
  (await redis.hUpdateBigger(`${REDIS_PREFIX}settings`, 'subcheck', now - subscriptionCheckTimeout, now))
1858
1863
  ) {
1859
1864
  try {
1865
+ let body = {
1866
+ key: licenseInfo.details.key,
1867
+ version: packageData.version,
1868
+ app: '@postalsys/emailengine-app',
1869
+ instance: (await settings.get('serviceId')) || ''
1870
+ };
1871
+
1872
+ // Best-effort feature beacon: enrich the existing call with a compact, anonymized
1873
+ // feature snapshot. Time-boxed and fully isolated (attachBeacon never throws) so it
1874
+ // can never block, delay, or alter license validation. The full snapshot is only sent
1875
+ // when its digest changes or once every 30 days; otherwise just the digest rides along.
1876
+ if (!BEACON_DISABLED) {
1877
+ await attachBeacon(body, { redis, logger, now });
1878
+ }
1879
+
1860
1880
  // Call license validation API
1861
1881
  let res = await fetchCmd(`https://postalsys.com/licenses/validate`, {
1862
1882
  method: 'post',
@@ -1864,12 +1884,7 @@ let licenseCheckHandler = async opts => {
1864
1884
  'User-Agent': `${packageData.name}/${packageData.version} (+${packageData.homepage})`,
1865
1885
  'Content-Type': 'application/json'
1866
1886
  },
1867
- body: JSON.stringify({
1868
- key: licenseInfo.details.key,
1869
- version: packageData.version,
1870
- app: '@postalsys/emailengine-app',
1871
- instance: (await settings.get('serviceId')) || ''
1872
- }),
1887
+ body: JSON.stringify(body),
1873
1888
  dispatcher: httpAgent.retry
1874
1889
  });
1875
1890
 
@@ -1901,6 +1916,11 @@ let licenseCheckHandler = async opts => {
1901
1916
  let nextCheck = Math.min(now + MAX_LICENSE_CHECK_DELAY, validatedUntil.getTime());
1902
1917
  await redis.hset(`${REDIS_PREFIX}settings`, 'ks', new Date(nextCheck).getTime().toString(16));
1903
1918
  }
1919
+
1920
+ // Persist beacon markers so the full snapshot is only resent when it changes.
1921
+ if (!BEACON_DISABLED) {
1922
+ await persistBeaconMarkers({ redis, logger, body, now, needFull: data.needFull });
1923
+ }
1904
1924
  }
1905
1925
  } catch (err) {
1906
1926
  logger.error({ msg: 'License validation error', err });
@@ -3418,8 +3438,10 @@ const startApplication = async () => {
3418
3438
  await spawnWorker('export');
3419
3439
  }
3420
3440
 
3421
- // Start document processing worker
3422
- await spawnWorker('documents');
3441
+ // Start document processing worker (deprecated Document Store feature; only when enabled)
3442
+ if (documentStoreFeatureEnabled) {
3443
+ await spawnWorker('documents');
3444
+ }
3423
3445
 
3424
3446
  // Start SMTP proxy if enabled
3425
3447
  if (await settings.get('smtpServerEnabled')) {