emailengine-app 2.61.1 → 2.61.2
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 +9 -0
- package/data/google-crawlers.json +1 -1
- package/lib/account/account-state.js +248 -0
- package/lib/account.js +17 -178
- package/lib/api-routes/account-routes.js +1006 -0
- package/lib/api-routes/message-routes.js +1377 -0
- package/lib/consts.js +12 -2
- package/lib/email-client/base-client.js +282 -771
- package/lib/email-client/gmail/gmail-api.js +243 -0
- package/lib/email-client/gmail-client.js +145 -53
- package/lib/email-client/imap/mailbox.js +24 -698
- package/lib/email-client/imap/sync-operations.js +812 -0
- package/lib/email-client/imap-client.js +1 -1
- package/lib/email-client/message-builder.js +566 -0
- package/lib/email-client/notification-handler.js +314 -0
- package/lib/email-client/outlook/graph-api.js +326 -0
- package/lib/email-client/outlook-client.js +159 -113
- package/lib/email-client/smtp-pool-manager.js +196 -0
- package/lib/imapproxy/imap-server.js +3 -12
- package/lib/oauth/gmail.js +4 -4
- package/lib/oauth/mail-ru.js +30 -5
- package/lib/oauth/outlook.js +57 -3
- package/lib/oauth/pubsub/google.js +30 -11
- package/lib/oauth/scope-checker.js +202 -0
- package/lib/oauth2-apps.js +8 -4
- package/lib/redis-operations.js +484 -0
- package/lib/routes-ui.js +283 -2582
- package/lib/tools.js +4 -196
- package/lib/ui-routes/account-routes.js +1931 -0
- package/lib/ui-routes/admin-config-routes.js +1233 -0
- package/lib/ui-routes/admin-entities-routes.js +2367 -0
- package/lib/ui-routes/oauth-routes.js +992 -0
- package/lib/utils/network.js +237 -0
- package/package.json +9 -9
- package/sbom.json +1 -1
- package/static/js/app.js +5 -5
- package/static/licenses.html +78 -18
- package/translations/de.mo +0 -0
- package/translations/de.po +85 -82
- package/translations/en.mo +0 -0
- package/translations/en.po +63 -71
- package/translations/et.mo +0 -0
- package/translations/et.po +84 -82
- package/translations/fr.mo +0 -0
- package/translations/fr.po +85 -82
- package/translations/ja.mo +0 -0
- package/translations/ja.po +84 -82
- package/translations/messages.pot +74 -87
- package/translations/nl.mo +0 -0
- package/translations/nl.po +86 -82
- package/translations/pl.mo +0 -0
- package/translations/pl.po +84 -82
- package/views/account/security.hbs +4 -4
- package/views/accounts/account.hbs +13 -13
- package/views/accounts/register/imap-server.hbs +12 -12
- package/views/config/document-store/pre-processing/index.hbs +4 -2
- package/views/config/oauth/app.hbs +6 -7
- package/views/config/oauth/index.hbs +2 -2
- package/views/config/service.hbs +3 -4
- package/views/dashboard.hbs +5 -7
- package/views/error.hbs +22 -7
- package/views/gateways/gateway.hbs +2 -2
- package/views/partials/add_account_modal.hbs +7 -10
- package/views/partials/document_store_header.hbs +1 -1
- package/views/partials/editor_scope_info.hbs +0 -1
- package/views/partials/oauth_config_header.hbs +1 -1
- package/views/partials/side_menu.hbs +3 -3
- package/views/partials/webhook_form.hbs +2 -2
- package/views/templates/index.hbs +1 -1
- package/views/templates/template.hbs +8 -8
- package/views/tokens/index.hbs +6 -6
- package/views/tokens/new.hbs +1 -1
- package/views/webhooks/index.hbs +4 -4
- package/views/webhooks/webhook.hbs +7 -7
- package/workers/api.js +148 -2436
- package/workers/smtp.js +2 -1
- package/lib/imapproxy/imap-core/test/client.js +0 -46
- package/lib/imapproxy/imap-core/test/fixtures/append.eml +0 -1196
- package/lib/imapproxy/imap-core/test/fixtures/chunks.js +0 -44
- package/lib/imapproxy/imap-core/test/fixtures/fix1.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/fix2.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/fix3.eml +0 -32
- package/lib/imapproxy/imap-core/test/fixtures/fix4.eml +0 -6
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.js +0 -2740
- package/lib/imapproxy/imap-core/test/fixtures/mimetorture.json +0 -1411
- package/lib/imapproxy/imap-core/test/fixtures/mimetree.js +0 -85
- package/lib/imapproxy/imap-core/test/fixtures/nodemailer.eml +0 -582
- package/lib/imapproxy/imap-core/test/fixtures/ryan_finnie_mime_torture.eml +0 -599
- package/lib/imapproxy/imap-core/test/fixtures/simple.eml +0 -42
- package/lib/imapproxy/imap-core/test/fixtures/simple.json +0 -164
- package/lib/imapproxy/imap-core/test/imap-compile-stream-test.js +0 -671
- package/lib/imapproxy/imap-core/test/imap-compiler-test.js +0 -272
- package/lib/imapproxy/imap-core/test/imap-indexer-test.js +0 -236
- package/lib/imapproxy/imap-core/test/imap-parser-test.js +0 -922
- package/lib/imapproxy/imap-core/test/memory-notifier.js +0 -129
- package/lib/imapproxy/imap-core/test/prepare.sh +0 -74
- package/lib/imapproxy/imap-core/test/protocol-test.js +0 -1756
- package/lib/imapproxy/imap-core/test/search-test.js +0 -1356
- package/lib/imapproxy/imap-core/test/test-client.js +0 -152
- package/lib/imapproxy/imap-core/test/test-server.js +0 -623
- package/lib/imapproxy/imap-core/test/tools-test.js +0 -22
- package/test/api-test.js +0 -899
- package/test/autoreply-test.js +0 -327
- package/test/bounce-test.js +0 -151
- package/test/complaint-test.js +0 -256
- package/test/fixtures/autoreply/LICENSE +0 -27
- package/test/fixtures/autoreply/rfc3834-01.eml +0 -23
- package/test/fixtures/autoreply/rfc3834-02.eml +0 -24
- package/test/fixtures/autoreply/rfc3834-03.eml +0 -26
- package/test/fixtures/autoreply/rfc3834-04.eml +0 -48
- package/test/fixtures/autoreply/rfc3834-05.eml +0 -19
- package/test/fixtures/autoreply/rfc3834-06.eml +0 -59
- package/test/fixtures/bounces/163.eml +0 -2521
- package/test/fixtures/bounces/fastmail.eml +0 -242
- package/test/fixtures/bounces/gmail.eml +0 -252
- package/test/fixtures/bounces/hotmail.eml +0 -655
- package/test/fixtures/bounces/mailru.eml +0 -121
- package/test/fixtures/bounces/outlook.eml +0 -1107
- package/test/fixtures/bounces/postfix.eml +0 -101
- package/test/fixtures/bounces/rambler.eml +0 -116
- package/test/fixtures/bounces/workmail.eml +0 -142
- package/test/fixtures/bounces/yahoo.eml +0 -139
- package/test/fixtures/bounces/zoho.eml +0 -83
- package/test/fixtures/bounces/zonemta.eml +0 -100
- package/test/fixtures/complaints/LICENSE +0 -27
- package/test/fixtures/complaints/amazonses.eml +0 -72
- package/test/fixtures/complaints/dmarc.eml +0 -59
- package/test/fixtures/complaints/hotmail.eml +0 -49
- package/test/fixtures/complaints/optout.eml +0 -40
- package/test/fixtures/complaints/standard-arf.eml +0 -68
- package/test/fixtures/complaints/yahoo.eml +0 -68
- package/test/oauth2-apps-test.js +0 -301
- package/test/sendonly-test.js +0 -160
- package/test/test-config.js +0 -34
- package/test/webhooks-server.js +0 -39
package/lib/tools.js
CHANGED
|
@@ -24,7 +24,6 @@ const { PassThrough } = require('stream');
|
|
|
24
24
|
const socks = require('socks');
|
|
25
25
|
const os = require('os');
|
|
26
26
|
const Fs = require('fs');
|
|
27
|
-
const net = require('net');
|
|
28
27
|
const fs = Fs.promises;
|
|
29
28
|
const pathlib = require('path');
|
|
30
29
|
const { randomUUID: uuid } = require('crypto');
|
|
@@ -41,11 +40,10 @@ const {
|
|
|
41
40
|
FETCH_RETRY_MAX,
|
|
42
41
|
URL_FETCH_RETRY_MAX
|
|
43
42
|
} = require('./consts');
|
|
44
|
-
const ipaddr = require('ipaddr.js');
|
|
45
43
|
const bullmqPackage = require('bullmq/package.json');
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const {
|
|
44
|
+
|
|
45
|
+
// Network utilities - imported for internal use only
|
|
46
|
+
const { getLocalAddress } = require('./utils/network');
|
|
49
47
|
|
|
50
48
|
const { fetch: fetchCmd, Agent, RetryAgent } = require('undici');
|
|
51
49
|
|
|
@@ -62,20 +60,6 @@ const retryAgent = new RetryAgent(fetchAgent, {
|
|
|
62
60
|
statusCodes: [429] // do not retry 5xx errors
|
|
63
61
|
});
|
|
64
62
|
|
|
65
|
-
const googleCrawlerMap = new Map();
|
|
66
|
-
for (let prefixEntry of googleCrawlerRanges.prefixes) {
|
|
67
|
-
for (let prefixKey of ['ipv6Prefix', 'ipv4Prefix']) {
|
|
68
|
-
if (prefixEntry[prefixKey]) {
|
|
69
|
-
// check if remote address is in range
|
|
70
|
-
let parsed = ipaddr.parseCIDR(prefixEntry[prefixKey]);
|
|
71
|
-
if (!googleCrawlerMap.has(prefixKey)) {
|
|
72
|
-
googleCrawlerMap.set(prefixKey, []);
|
|
73
|
-
}
|
|
74
|
-
googleCrawlerMap.get(prefixKey).push(parsed);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
63
|
class LRUCache extends Map {
|
|
80
64
|
constructor(maxSize = 1000) {
|
|
81
65
|
super();
|
|
@@ -911,7 +895,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV3QUiYsp13nD9suD1/ZkEXnuMoSg
|
|
|
911
895
|
verifyPromises.push(
|
|
912
896
|
(async () => {
|
|
913
897
|
try {
|
|
914
|
-
let { localAddress: address, name } = await
|
|
898
|
+
let { localAddress: address, name } = await getLocalAddress(redis, 'smtp', 'test');
|
|
915
899
|
|
|
916
900
|
let smtpLogger = {};
|
|
917
901
|
let smtpConfig = Object.assign(
|
|
@@ -1561,110 +1545,6 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV3QUiYsp13nD9suD1/ZkEXnuMoSg
|
|
|
1561
1545
|
return hostname;
|
|
1562
1546
|
},
|
|
1563
1547
|
|
|
1564
|
-
async updatePublicInterfaces(redis) {
|
|
1565
|
-
let interfaces = await resolvePublicInterfaces();
|
|
1566
|
-
|
|
1567
|
-
for (let iface of interfaces) {
|
|
1568
|
-
if (!iface.localAddress) {
|
|
1569
|
-
continue;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
if (iface.defaultInterface) {
|
|
1573
|
-
await redis.hset(`${REDIS_PREFIX}interfaces`, `default:${iface.family}`, iface.localAddress);
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
let existingEntry = await redis.hget(`${REDIS_PREFIX}interfaces`, iface.localAddress);
|
|
1577
|
-
if (existingEntry) {
|
|
1578
|
-
try {
|
|
1579
|
-
existingEntry = JSON.parse(existingEntry);
|
|
1580
|
-
|
|
1581
|
-
iface.name = iface.name || existingEntry.name;
|
|
1582
|
-
|
|
1583
|
-
if (!iface.localAddress || !iface.ip || !iface.name) {
|
|
1584
|
-
// not much point in updating
|
|
1585
|
-
continue;
|
|
1586
|
-
}
|
|
1587
|
-
} catch (err) {
|
|
1588
|
-
// ignore?
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
delete iface.defaultInterface;
|
|
1593
|
-
await redis.hset(`${REDIS_PREFIX}interfaces`, iface.localAddress, JSON.stringify(iface));
|
|
1594
|
-
}
|
|
1595
|
-
},
|
|
1596
|
-
|
|
1597
|
-
async getLocalAddress(redis, protocol, account, hint) {
|
|
1598
|
-
let existingAddresses = Object.values(os.networkInterfaces())
|
|
1599
|
-
.flatMap(entry => entry)
|
|
1600
|
-
.map(entry => entry.address);
|
|
1601
|
-
|
|
1602
|
-
if (hint) {
|
|
1603
|
-
let parsedHint = ipaddr.parse(hint);
|
|
1604
|
-
let normalizedHint = parsedHint.toNormalizedString();
|
|
1605
|
-
let iface = await redis.hget(`${REDIS_PREFIX}interfaces`, normalizedHint);
|
|
1606
|
-
try {
|
|
1607
|
-
iface = iface ? JSON.parse(iface) : null;
|
|
1608
|
-
} catch (err) {
|
|
1609
|
-
// ignore
|
|
1610
|
-
}
|
|
1611
|
-
if (iface && existingAddresses.includes(iface.localAddress)) {
|
|
1612
|
-
iface.addressSelector = 'hint';
|
|
1613
|
-
return iface;
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
let addressStrategy = await settings.get(`${protocol}Strategy`);
|
|
1618
|
-
let localAddresses = []
|
|
1619
|
-
.concat((await settings.get(`localAddresses`)) || [])
|
|
1620
|
-
.filter(address => existingAddresses.includes(address))
|
|
1621
|
-
.filter(address => net.isIPv4(address));
|
|
1622
|
-
let localAddress;
|
|
1623
|
-
|
|
1624
|
-
let hostname = await module.exports.getServiceHostname(await settings.get('smtpEhloName'));
|
|
1625
|
-
|
|
1626
|
-
let addressSelector;
|
|
1627
|
-
|
|
1628
|
-
if (!localAddresses.length) {
|
|
1629
|
-
addressSelector = 'default';
|
|
1630
|
-
return { address: false, name: hostname, addressSelector };
|
|
1631
|
-
} else if (localAddresses.length === 1) {
|
|
1632
|
-
addressSelector = 'single';
|
|
1633
|
-
localAddress = localAddresses[0];
|
|
1634
|
-
} else {
|
|
1635
|
-
switch (addressStrategy) {
|
|
1636
|
-
case 'random': {
|
|
1637
|
-
addressSelector = 'random';
|
|
1638
|
-
localAddress = localAddresses[Math.floor(Math.random() * localAddresses.length)];
|
|
1639
|
-
break;
|
|
1640
|
-
}
|
|
1641
|
-
case 'dedicated':
|
|
1642
|
-
addressSelector = 'dedicated';
|
|
1643
|
-
localAddress = module.exports.selectRendezvousAddress(account, localAddresses);
|
|
1644
|
-
break;
|
|
1645
|
-
default:
|
|
1646
|
-
addressSelector = 'unknown';
|
|
1647
|
-
return { address: false, name: hostname, addressSelector };
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
if (!localAddress) {
|
|
1652
|
-
addressSelector = 'unset';
|
|
1653
|
-
return { address: false, name: hostname, addressSelector };
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
try {
|
|
1657
|
-
let addressData = JSON.parse(await redis.hget(`${REDIS_PREFIX}interfaces`, localAddress));
|
|
1658
|
-
addressData.name = addressData.name || hostname;
|
|
1659
|
-
addressData.addressSelector = addressSelector;
|
|
1660
|
-
return addressData;
|
|
1661
|
-
} catch (err) {
|
|
1662
|
-
logger.error({ msg: 'Failed to load address data', localAddress, err });
|
|
1663
|
-
addressSelector = 'error';
|
|
1664
|
-
return { address: false, name: hostname, addressSelector };
|
|
1665
|
-
}
|
|
1666
|
-
},
|
|
1667
|
-
|
|
1668
1548
|
unpackUIDRangeForSearch(uid) {
|
|
1669
1549
|
uid = (uid || '').toString();
|
|
1670
1550
|
let parts = uid
|
|
@@ -1764,27 +1644,6 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV3QUiYsp13nD9suD1/ZkEXnuMoSg
|
|
|
1764
1644
|
}
|
|
1765
1645
|
},
|
|
1766
1646
|
|
|
1767
|
-
matchIp(ip, addresses) {
|
|
1768
|
-
let parsed = ipaddr.parse(ip);
|
|
1769
|
-
for (let addr of addresses) {
|
|
1770
|
-
try {
|
|
1771
|
-
let match;
|
|
1772
|
-
if (/\/\d+$/.test(addr)) {
|
|
1773
|
-
match = parsed.match(ipaddr.parseCIDR(addr));
|
|
1774
|
-
} else {
|
|
1775
|
-
match = parsed.toNormalizedString() === ipaddr.parse(addr).toNormalizedString();
|
|
1776
|
-
}
|
|
1777
|
-
if (match) {
|
|
1778
|
-
return true;
|
|
1779
|
-
}
|
|
1780
|
-
} catch (err) {
|
|
1781
|
-
logger.error({ msg: 'Failed to parse IP address', ip, addr, err });
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
return false;
|
|
1786
|
-
},
|
|
1787
|
-
|
|
1788
1647
|
threadStats: {
|
|
1789
1648
|
startTime: Date.now(),
|
|
1790
1649
|
|
|
@@ -1806,57 +1665,6 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEV3QUiYsp13nD9suD1/ZkEXnuMoSg
|
|
|
1806
1665
|
}
|
|
1807
1666
|
},
|
|
1808
1667
|
|
|
1809
|
-
async detectAutomatedRequest(ip) {
|
|
1810
|
-
let prefixKey;
|
|
1811
|
-
if (net.isIPv4(ip)) {
|
|
1812
|
-
prefixKey = 'ipv4Prefix';
|
|
1813
|
-
} else if (net.isIPv6(ip)) {
|
|
1814
|
-
prefixKey = 'ipv6Prefix';
|
|
1815
|
-
} else {
|
|
1816
|
-
return false;
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
const addr = ipaddr.parse(ip);
|
|
1820
|
-
|
|
1821
|
-
// Check if it is a Google security scanner
|
|
1822
|
-
for (let prefixEntry of googleCrawlerMap.get(prefixKey)) {
|
|
1823
|
-
// check if remote address is in range
|
|
1824
|
-
if (addr.match(prefixEntry)) {
|
|
1825
|
-
return true;
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
|
|
1829
|
-
// Check known scanners
|
|
1830
|
-
let hostnames;
|
|
1831
|
-
try {
|
|
1832
|
-
hostnames = await dnsReverse(ip);
|
|
1833
|
-
} catch (err) {
|
|
1834
|
-
logger.trace({
|
|
1835
|
-
msg: 'Failed to reverse resolve IP',
|
|
1836
|
-
ip,
|
|
1837
|
-
err
|
|
1838
|
-
});
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
if (!hostnames || !hostnames.length) {
|
|
1842
|
-
return false;
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
const hostname = []
|
|
1846
|
-
.concat(hostnames || [])
|
|
1847
|
-
.shift()
|
|
1848
|
-
.toString()
|
|
1849
|
-
.trim()
|
|
1850
|
-
.toLowerCase();
|
|
1851
|
-
|
|
1852
|
-
// Barracuda, spfbl
|
|
1853
|
-
if (/\bbarracuda\.com$|\bspfbl\.net$/gi.test(hostname)) {
|
|
1854
|
-
return true;
|
|
1855
|
-
}
|
|
1856
|
-
|
|
1857
|
-
return false;
|
|
1858
|
-
},
|
|
1859
|
-
|
|
1860
1668
|
structuredClone: typeof structuredClone === 'function' ? structuredClone : data => JSON.parse(JSON.stringify(data)),
|
|
1861
1669
|
|
|
1862
1670
|
loadTlsConfig(ref, envPrefix) {
|