@agenticmail/core 0.5.32 → 0.5.34
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/dist/index.d.ts +3 -0
- package/dist/index.js +133 -66
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1068,6 +1068,8 @@ interface GatewayManagerOptions {
|
|
|
1068
1068
|
accountManager?: AccountManager;
|
|
1069
1069
|
localSmtp?: LocalSmtpConfig;
|
|
1070
1070
|
onInboundMail?: (agentName: string, mail: InboundEmail) => void | Promise<void>;
|
|
1071
|
+
/** Master key used to encrypt credentials at rest in SQLite. */
|
|
1072
|
+
encryptionKey?: string;
|
|
1071
1073
|
}
|
|
1072
1074
|
/**
|
|
1073
1075
|
* GatewayManager orchestrates relay and domain modes for sending/receiving
|
|
@@ -1087,6 +1089,7 @@ declare class GatewayManager {
|
|
|
1087
1089
|
private domainPurchaser;
|
|
1088
1090
|
private smsManager;
|
|
1089
1091
|
private smsPollers;
|
|
1092
|
+
private encryptionKey;
|
|
1090
1093
|
constructor(options: GatewayManagerOptions);
|
|
1091
1094
|
/**
|
|
1092
1095
|
* Check if a message has already been delivered to an agent (deduplication).
|
package/dist/index.js
CHANGED
|
@@ -703,6 +703,12 @@ function saveConfig(config) {
|
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
// src/stalwart/admin.ts
|
|
706
|
+
function escapeTomlString(value) {
|
|
707
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
708
|
+
}
|
|
709
|
+
function isValidDomain(domain) {
|
|
710
|
+
return /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(domain);
|
|
711
|
+
}
|
|
706
712
|
var StalwartAdmin = class {
|
|
707
713
|
constructor(options) {
|
|
708
714
|
this.options = options;
|
|
@@ -850,13 +856,16 @@ var StalwartAdmin = class {
|
|
|
850
856
|
* Critical for email deliverability — must match the sending domain.
|
|
851
857
|
*/
|
|
852
858
|
async setHostname(domain) {
|
|
859
|
+
if (!isValidDomain(domain)) {
|
|
860
|
+
throw new Error(`Invalid domain format: "${domain}"`);
|
|
861
|
+
}
|
|
853
862
|
const { readFileSync: readFileSync4, writeFileSync: writeFileSync5 } = await import("fs");
|
|
854
863
|
const { homedir: homedir8 } = await import("os");
|
|
855
864
|
const { join: join9 } = await import("path");
|
|
856
865
|
const configPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
|
|
857
866
|
try {
|
|
858
867
|
let config = readFileSync4(configPath, "utf-8");
|
|
859
|
-
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${domain}"`);
|
|
868
|
+
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
|
|
860
869
|
writeFileSync5(configPath, config);
|
|
861
870
|
console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
|
|
862
871
|
} catch (err) {
|
|
@@ -983,21 +992,22 @@ var StalwartAdmin = class {
|
|
|
983
992
|
let toml = readFileSync4(tomlPath, "utf-8");
|
|
984
993
|
toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
|
|
985
994
|
toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
|
|
995
|
+
const safeRouteName = routeName.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
986
996
|
toml += `
|
|
987
997
|
|
|
988
|
-
[queue.route.${
|
|
998
|
+
[queue.route.${safeRouteName}]
|
|
989
999
|
description = "Gmail SMTP relay for outbound delivery"
|
|
990
1000
|
type = "relay"
|
|
991
|
-
address = "${config.smtpHost}"
|
|
992
|
-
port = ${config.smtpPort}
|
|
1001
|
+
address = "${escapeTomlString(config.smtpHost)}"
|
|
1002
|
+
port = ${Number(config.smtpPort) || 465}
|
|
993
1003
|
protocol = "smtp"
|
|
994
1004
|
tls.implicit = true
|
|
995
|
-
auth.username = "${config.username}"
|
|
996
|
-
auth.secret = "${config.password}"
|
|
1005
|
+
auth.username = "${escapeTomlString(config.username)}"
|
|
1006
|
+
auth.secret = "${escapeTomlString(config.password)}"
|
|
997
1007
|
|
|
998
1008
|
[queue.strategy]
|
|
999
1009
|
route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
|
|
1000
|
-
{ else = "'${
|
|
1010
|
+
{ else = "'${safeRouteName}'" } ]
|
|
1001
1011
|
`;
|
|
1002
1012
|
writeFileSync5(tomlPath, toml, "utf-8");
|
|
1003
1013
|
await this.restartContainer();
|
|
@@ -3193,6 +3203,7 @@ var DomainManager = class {
|
|
|
3193
3203
|
|
|
3194
3204
|
// src/gateway/manager.ts
|
|
3195
3205
|
import { join as join4 } from "path";
|
|
3206
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2, createHash } from "crypto";
|
|
3196
3207
|
import nodemailer3 from "nodemailer";
|
|
3197
3208
|
|
|
3198
3209
|
// src/debug.ts
|
|
@@ -4833,12 +4844,31 @@ var SmsPoller = class {
|
|
|
4833
4844
|
};
|
|
4834
4845
|
|
|
4835
4846
|
// src/gateway/manager.ts
|
|
4847
|
+
function encryptSecret(plaintext, key) {
|
|
4848
|
+
const keyHash = createHash("sha256").update(key).digest();
|
|
4849
|
+
const iv = randomBytes2(12);
|
|
4850
|
+
const cipher = createCipheriv("aes-256-gcm", keyHash, iv);
|
|
4851
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
4852
|
+
const authTag = cipher.getAuthTag();
|
|
4853
|
+
return `enc:${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
|
|
4854
|
+
}
|
|
4855
|
+
function decryptSecret(value, key) {
|
|
4856
|
+
if (!value.startsWith("enc:")) return value;
|
|
4857
|
+
const parts = value.split(":");
|
|
4858
|
+
if (parts.length !== 4) return value;
|
|
4859
|
+
const [, ivHex, authTagHex, ciphertextHex] = parts;
|
|
4860
|
+
const keyHash = createHash("sha256").update(key).digest();
|
|
4861
|
+
const decipher = createDecipheriv("aes-256-gcm", keyHash, Buffer.from(ivHex, "hex"));
|
|
4862
|
+
decipher.setAuthTag(Buffer.from(authTagHex, "hex"));
|
|
4863
|
+
return Buffer.concat([decipher.update(Buffer.from(ciphertextHex, "hex")), decipher.final()]).toString("utf8");
|
|
4864
|
+
}
|
|
4836
4865
|
var GatewayManager = class {
|
|
4837
4866
|
constructor(options) {
|
|
4838
4867
|
this.options = options;
|
|
4839
4868
|
this.db = options.db;
|
|
4840
4869
|
this.stalwart = options.stalwart;
|
|
4841
4870
|
this.accountManager = options.accountManager ?? null;
|
|
4871
|
+
this.encryptionKey = options.encryptionKey ?? process.env.AGENTICMAIL_MASTER_KEY ?? null;
|
|
4842
4872
|
const inboundHandler = options.onInboundMail ?? (this.accountManager && options.localSmtp ? this.deliverInboundLocally.bind(this) : void 0);
|
|
4843
4873
|
this.relay = new RelayGateway({
|
|
4844
4874
|
onInboundMail: inboundHandler,
|
|
@@ -4865,6 +4895,7 @@ var GatewayManager = class {
|
|
|
4865
4895
|
domainPurchaser = null;
|
|
4866
4896
|
smsManager = null;
|
|
4867
4897
|
smsPollers = /* @__PURE__ */ new Map();
|
|
4898
|
+
encryptionKey = null;
|
|
4868
4899
|
/**
|
|
4869
4900
|
* Check if a message has already been delivered to an agent (deduplication).
|
|
4870
4901
|
*/
|
|
@@ -5180,8 +5211,8 @@ var GatewayManager = class {
|
|
|
5180
5211
|
const { homedir: homedir8 } = await import("os");
|
|
5181
5212
|
const backupDir = join4(homedir8(), ".agenticmail");
|
|
5182
5213
|
const backupPath = join4(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
|
|
5183
|
-
const { writeFileSync: writeFileSync5, mkdirSync:
|
|
5184
|
-
|
|
5214
|
+
const { writeFileSync: writeFileSync5, mkdirSync: mkdirSync6 } = await import("fs");
|
|
5215
|
+
mkdirSync6(backupDir, { recursive: true });
|
|
5185
5216
|
writeFileSync5(backupPath, JSON.stringify({
|
|
5186
5217
|
domain,
|
|
5187
5218
|
zoneId: zone.id,
|
|
@@ -5646,6 +5677,44 @@ var GatewayManager = class {
|
|
|
5646
5677
|
if (row) {
|
|
5647
5678
|
try {
|
|
5648
5679
|
const parsed = JSON.parse(row.config);
|
|
5680
|
+
if (this.encryptionKey) {
|
|
5681
|
+
if (parsed.relay?.password) {
|
|
5682
|
+
try {
|
|
5683
|
+
parsed.relay.password = decryptSecret(parsed.relay.password, this.encryptionKey);
|
|
5684
|
+
} catch {
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5687
|
+
if (parsed.relay?.appPassword) {
|
|
5688
|
+
try {
|
|
5689
|
+
parsed.relay.appPassword = decryptSecret(parsed.relay.appPassword, this.encryptionKey);
|
|
5690
|
+
} catch {
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
if (parsed.domain?.cloudflareApiToken) {
|
|
5694
|
+
try {
|
|
5695
|
+
parsed.domain.cloudflareApiToken = decryptSecret(parsed.domain.cloudflareApiToken, this.encryptionKey);
|
|
5696
|
+
} catch {
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
if (parsed.domain?.tunnelToken) {
|
|
5700
|
+
try {
|
|
5701
|
+
parsed.domain.tunnelToken = decryptSecret(parsed.domain.tunnelToken, this.encryptionKey);
|
|
5702
|
+
} catch {
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
if (parsed.domain?.inboundSecret) {
|
|
5706
|
+
try {
|
|
5707
|
+
parsed.domain.inboundSecret = decryptSecret(parsed.domain.inboundSecret, this.encryptionKey);
|
|
5708
|
+
} catch {
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
if (parsed.domain?.outboundSecret) {
|
|
5712
|
+
try {
|
|
5713
|
+
parsed.domain.outboundSecret = decryptSecret(parsed.domain.outboundSecret, this.encryptionKey);
|
|
5714
|
+
} catch {
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5649
5718
|
this.config = {
|
|
5650
5719
|
mode: row.mode,
|
|
5651
5720
|
...parsed
|
|
@@ -5657,10 +5726,31 @@ var GatewayManager = class {
|
|
|
5657
5726
|
}
|
|
5658
5727
|
saveConfig() {
|
|
5659
5728
|
const { mode, ...rest } = this.config;
|
|
5729
|
+
const toStore = JSON.parse(JSON.stringify(rest));
|
|
5730
|
+
if (this.encryptionKey) {
|
|
5731
|
+
if (toStore.relay?.password) {
|
|
5732
|
+
toStore.relay.password = encryptSecret(toStore.relay.password, this.encryptionKey);
|
|
5733
|
+
}
|
|
5734
|
+
if (toStore.relay?.appPassword) {
|
|
5735
|
+
toStore.relay.appPassword = encryptSecret(toStore.relay.appPassword, this.encryptionKey);
|
|
5736
|
+
}
|
|
5737
|
+
if (toStore.domain?.cloudflareApiToken) {
|
|
5738
|
+
toStore.domain.cloudflareApiToken = encryptSecret(toStore.domain.cloudflareApiToken, this.encryptionKey);
|
|
5739
|
+
}
|
|
5740
|
+
if (toStore.domain?.tunnelToken) {
|
|
5741
|
+
toStore.domain.tunnelToken = encryptSecret(toStore.domain.tunnelToken, this.encryptionKey);
|
|
5742
|
+
}
|
|
5743
|
+
if (toStore.domain?.inboundSecret) {
|
|
5744
|
+
toStore.domain.inboundSecret = encryptSecret(toStore.domain.inboundSecret, this.encryptionKey);
|
|
5745
|
+
}
|
|
5746
|
+
if (toStore.domain?.outboundSecret) {
|
|
5747
|
+
toStore.domain.outboundSecret = encryptSecret(toStore.domain.outboundSecret, this.encryptionKey);
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5660
5750
|
this.db.prepare(`
|
|
5661
5751
|
INSERT OR REPLACE INTO gateway_config (id, mode, config)
|
|
5662
5752
|
VALUES ('default', ?, ?)
|
|
5663
|
-
`).run(mode, JSON.stringify(
|
|
5753
|
+
`).run(mode, JSON.stringify(toStore));
|
|
5664
5754
|
}
|
|
5665
5755
|
saveLastSeenUid(uid) {
|
|
5666
5756
|
this.db.prepare(`
|
|
@@ -5812,8 +5902,8 @@ var RELAY_PRESETS = {
|
|
|
5812
5902
|
};
|
|
5813
5903
|
|
|
5814
5904
|
// src/setup/index.ts
|
|
5815
|
-
import { randomBytes as
|
|
5816
|
-
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as
|
|
5905
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
5906
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, chmodSync as chmodSync2 } from "fs";
|
|
5817
5907
|
import { join as join8 } from "path";
|
|
5818
5908
|
import { homedir as homedir7 } from "os";
|
|
5819
5909
|
|
|
@@ -5894,7 +5984,7 @@ var DependencyChecker = class {
|
|
|
5894
5984
|
|
|
5895
5985
|
// src/setup/installer.ts
|
|
5896
5986
|
import { execFileSync as execFileSync2, execSync, spawn as spawnChild } from "child_process";
|
|
5897
|
-
import { existsSync as existsSync4 } from "fs";
|
|
5987
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, symlinkSync } from "fs";
|
|
5898
5988
|
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
5899
5989
|
import { join as join6 } from "path";
|
|
5900
5990
|
import { homedir as homedir5, platform as platform2, arch as arch2 } from "os";
|
|
@@ -6077,11 +6167,11 @@ var DependencyInstaller = class {
|
|
|
6077
6167
|
const pluginPath = join6(pluginDir, "docker-compose");
|
|
6078
6168
|
if (existsSync4(pluginPath)) return;
|
|
6079
6169
|
try {
|
|
6080
|
-
|
|
6170
|
+
mkdirSync3(pluginDir, { recursive: true });
|
|
6081
6171
|
} catch {
|
|
6082
6172
|
}
|
|
6083
6173
|
try {
|
|
6084
|
-
|
|
6174
|
+
symlinkSync(composeBin, pluginPath);
|
|
6085
6175
|
} catch {
|
|
6086
6176
|
}
|
|
6087
6177
|
} catch {
|
|
@@ -6140,8 +6230,11 @@ var DependencyInstaller = class {
|
|
|
6140
6230
|
return;
|
|
6141
6231
|
}
|
|
6142
6232
|
this.onProgress("__progress__:5:Installing Docker Engine...");
|
|
6233
|
+
const tmpDir = join6(homedir5(), ".agenticmail", "tmp");
|
|
6234
|
+
await mkdir2(tmpDir, { recursive: true });
|
|
6235
|
+
const scriptPath = join6(tmpDir, "install-docker.sh");
|
|
6143
6236
|
const dlResult = await runShellWithRollingOutput(
|
|
6144
|
-
|
|
6237
|
+
`curl -fsSL https://get.docker.com -o "${scriptPath}" && sudo sh "${scriptPath}"`,
|
|
6145
6238
|
{ timeout: 3e5 }
|
|
6146
6239
|
);
|
|
6147
6240
|
if (dlResult.exitCode !== 0) {
|
|
@@ -6150,15 +6243,15 @@ var DependencyInstaller = class {
|
|
|
6150
6243
|
);
|
|
6151
6244
|
}
|
|
6152
6245
|
const user = process.env.USER || process.env.LOGNAME || "";
|
|
6153
|
-
if (user && user !== "root") {
|
|
6246
|
+
if (user && user !== "root" && /^[a-zA-Z0-9._-]+$/.test(user)) {
|
|
6154
6247
|
this.onProgress("__progress__:80:Adding user to docker group...");
|
|
6155
6248
|
try {
|
|
6156
|
-
|
|
6249
|
+
execFileSync2("sudo", ["usermod", "-aG", "docker", user], { timeout: 1e4, stdio: "ignore" });
|
|
6157
6250
|
} catch {
|
|
6158
6251
|
}
|
|
6159
6252
|
}
|
|
6160
6253
|
try {
|
|
6161
|
-
await unlink(
|
|
6254
|
+
await unlink(scriptPath);
|
|
6162
6255
|
} catch {
|
|
6163
6256
|
}
|
|
6164
6257
|
this.onProgress("__progress__:85:Starting Docker service...");
|
|
@@ -6422,7 +6515,7 @@ var DependencyInstaller = class {
|
|
|
6422
6515
|
|
|
6423
6516
|
// src/setup/service.ts
|
|
6424
6517
|
import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
|
|
6425
|
-
import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as
|
|
6518
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync4, chmodSync } from "fs";
|
|
6426
6519
|
import { join as join7 } from "path";
|
|
6427
6520
|
import { homedir as homedir6, platform as platform3 } from "os";
|
|
6428
6521
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
@@ -6495,7 +6588,7 @@ var ServiceManager = class {
|
|
|
6495
6588
|
*/
|
|
6496
6589
|
cacheApiEntryPath(entryPath) {
|
|
6497
6590
|
const dataDir = join7(homedir6(), ".agenticmail");
|
|
6498
|
-
if (!existsSync5(dataDir))
|
|
6591
|
+
if (!existsSync5(dataDir)) mkdirSync4(dataDir, { recursive: true });
|
|
6499
6592
|
writeFileSync3(join7(dataDir, "api-entry.path"), entryPath);
|
|
6500
6593
|
}
|
|
6501
6594
|
/**
|
|
@@ -6529,7 +6622,7 @@ var ServiceManager = class {
|
|
|
6529
6622
|
generateStartScript(nodePath, apiEntry) {
|
|
6530
6623
|
const scriptPath = join7(homedir6(), ".agenticmail", "bin", "start-server.sh");
|
|
6531
6624
|
const scriptDir = join7(homedir6(), ".agenticmail", "bin");
|
|
6532
|
-
if (!existsSync5(scriptDir))
|
|
6625
|
+
if (!existsSync5(scriptDir)) mkdirSync4(scriptDir, { recursive: true });
|
|
6533
6626
|
const script = [
|
|
6534
6627
|
"#!/bin/bash",
|
|
6535
6628
|
"# AgenticMail auto-start script",
|
|
@@ -6595,7 +6688,7 @@ var ServiceManager = class {
|
|
|
6595
6688
|
generatePlist(nodePath, apiEntry, configPath) {
|
|
6596
6689
|
const config = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
6597
6690
|
const logDir = join7(homedir6(), ".agenticmail", "logs");
|
|
6598
|
-
if (!existsSync5(logDir))
|
|
6691
|
+
if (!existsSync5(logDir)) mkdirSync4(logDir, { recursive: true });
|
|
6599
6692
|
const version = this.getVersion();
|
|
6600
6693
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
6601
6694
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -6619,26 +6712,6 @@ var ServiceManager = class {
|
|
|
6619
6712
|
<string>${homedir6()}</string>
|
|
6620
6713
|
<key>AGENTICMAIL_DATA_DIR</key>
|
|
6621
6714
|
<string>${config.dataDir || join7(homedir6(), ".agenticmail")}</string>
|
|
6622
|
-
<key>AGENTICMAIL_MASTER_KEY</key>
|
|
6623
|
-
<string>${config.masterKey}</string>
|
|
6624
|
-
<key>STALWART_ADMIN_USER</key>
|
|
6625
|
-
<string>${config.stalwart.adminUser}</string>
|
|
6626
|
-
<key>STALWART_ADMIN_PASSWORD</key>
|
|
6627
|
-
<string>${config.stalwart.adminPassword}</string>
|
|
6628
|
-
<key>STALWART_URL</key>
|
|
6629
|
-
<string>${config.stalwart.url}</string>
|
|
6630
|
-
<key>AGENTICMAIL_API_PORT</key>
|
|
6631
|
-
<string>${String(config.api.port)}</string>
|
|
6632
|
-
<key>AGENTICMAIL_API_HOST</key>
|
|
6633
|
-
<string>${config.api.host}</string>
|
|
6634
|
-
<key>SMTP_HOST</key>
|
|
6635
|
-
<string>${config.smtp.host}</string>
|
|
6636
|
-
<key>SMTP_PORT</key>
|
|
6637
|
-
<string>${String(config.smtp.port)}</string>
|
|
6638
|
-
<key>IMAP_HOST</key>
|
|
6639
|
-
<string>${config.imap.host}</string>
|
|
6640
|
-
<key>IMAP_PORT</key>
|
|
6641
|
-
<string>${String(config.imap.port)}</string>
|
|
6642
6715
|
<key>PATH</key>
|
|
6643
6716
|
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
6644
6717
|
<key>AGENTICMAIL_SERVICE_VERSION</key>
|
|
@@ -6711,16 +6784,6 @@ TimeoutStartSec=660
|
|
|
6711
6784
|
LimitNOFILE=8192
|
|
6712
6785
|
Environment=HOME=${homedir6()}
|
|
6713
6786
|
Environment=AGENTICMAIL_DATA_DIR=${dataDir}
|
|
6714
|
-
Environment=AGENTICMAIL_MASTER_KEY=${config.masterKey}
|
|
6715
|
-
Environment=STALWART_ADMIN_USER=${config.stalwart.adminUser}
|
|
6716
|
-
Environment=STALWART_ADMIN_PASSWORD=${config.stalwart.adminPassword}
|
|
6717
|
-
Environment=STALWART_URL=${config.stalwart.url}
|
|
6718
|
-
Environment=AGENTICMAIL_API_PORT=${config.api.port}
|
|
6719
|
-
Environment=AGENTICMAIL_API_HOST=${config.api.host}
|
|
6720
|
-
Environment=SMTP_HOST=${config.smtp.host}
|
|
6721
|
-
Environment=SMTP_PORT=${config.smtp.port}
|
|
6722
|
-
Environment=IMAP_HOST=${config.imap.host}
|
|
6723
|
-
Environment=IMAP_PORT=${config.imap.port}
|
|
6724
6787
|
Environment=PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
|
|
6725
6788
|
Environment=AGENTICMAIL_SERVICE_VERSION=${version}
|
|
6726
6789
|
|
|
@@ -6746,7 +6809,7 @@ WantedBy=default.target
|
|
|
6746
6809
|
const servicePath = this.getServicePath();
|
|
6747
6810
|
if (this.os === "darwin") {
|
|
6748
6811
|
const dir = join7(homedir6(), "Library", "LaunchAgents");
|
|
6749
|
-
if (!existsSync5(dir))
|
|
6812
|
+
if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
|
|
6750
6813
|
if (existsSync5(servicePath)) {
|
|
6751
6814
|
try {
|
|
6752
6815
|
execFileSync3("launchctl", ["unload", servicePath], { timeout: 1e4, stdio: "ignore" });
|
|
@@ -6755,6 +6818,7 @@ WantedBy=default.target
|
|
|
6755
6818
|
}
|
|
6756
6819
|
const plist = this.generatePlist(nodePath, apiEntry, configPath);
|
|
6757
6820
|
writeFileSync3(servicePath, plist);
|
|
6821
|
+
chmodSync(servicePath, 384);
|
|
6758
6822
|
try {
|
|
6759
6823
|
execFileSync3("launchctl", ["load", servicePath], { timeout: 1e4, stdio: "ignore" });
|
|
6760
6824
|
} catch (err) {
|
|
@@ -6763,9 +6827,10 @@ WantedBy=default.target
|
|
|
6763
6827
|
return { installed: true, message: `Service installed at ${servicePath}` };
|
|
6764
6828
|
} else if (this.os === "linux") {
|
|
6765
6829
|
const dir = join7(homedir6(), ".config", "systemd", "user");
|
|
6766
|
-
if (!existsSync5(dir))
|
|
6830
|
+
if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
|
|
6767
6831
|
const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
|
|
6768
6832
|
writeFileSync3(servicePath, unit);
|
|
6833
|
+
chmodSync(servicePath, 384);
|
|
6769
6834
|
try {
|
|
6770
6835
|
execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
|
|
6771
6836
|
execFileSync3("systemctl", ["--user", "enable", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
|
|
@@ -6923,10 +6988,10 @@ var SetupManager = class {
|
|
|
6923
6988
|
}
|
|
6924
6989
|
}
|
|
6925
6990
|
if (!existsSync6(dataDir)) {
|
|
6926
|
-
|
|
6991
|
+
mkdirSync5(dataDir, { recursive: true });
|
|
6927
6992
|
}
|
|
6928
|
-
const masterKey = `mk_${
|
|
6929
|
-
const stalwartPassword =
|
|
6993
|
+
const masterKey = `mk_${randomBytes3(24).toString("hex")}`;
|
|
6994
|
+
const stalwartPassword = randomBytes3(16).toString("hex");
|
|
6930
6995
|
const config = {
|
|
6931
6996
|
masterKey,
|
|
6932
6997
|
stalwart: {
|
|
@@ -6940,7 +7005,7 @@ var SetupManager = class {
|
|
|
6940
7005
|
dataDir
|
|
6941
7006
|
};
|
|
6942
7007
|
writeFileSync4(configPath, JSON.stringify(config, null, 2));
|
|
6943
|
-
|
|
7008
|
+
chmodSync2(configPath, 384);
|
|
6944
7009
|
const envContent = `# Auto-generated by agenticmail setup
|
|
6945
7010
|
STALWART_ADMIN_USER=admin
|
|
6946
7011
|
STALWART_ADMIN_PASSWORD=${stalwartPassword}
|
|
@@ -6956,7 +7021,7 @@ IMAP_HOST=localhost
|
|
|
6956
7021
|
IMAP_PORT=143
|
|
6957
7022
|
`;
|
|
6958
7023
|
writeFileSync4(envPath, envContent);
|
|
6959
|
-
|
|
7024
|
+
chmodSync2(envPath, 384);
|
|
6960
7025
|
this.generateDockerFiles(config);
|
|
6961
7026
|
return { configPath, envPath, config, isNew: true };
|
|
6962
7027
|
}
|
|
@@ -6967,7 +7032,7 @@ IMAP_PORT=143
|
|
|
6967
7032
|
generateDockerFiles(config) {
|
|
6968
7033
|
const dataDir = config.dataDir || join8(homedir7(), ".agenticmail");
|
|
6969
7034
|
if (!existsSync6(dataDir)) {
|
|
6970
|
-
|
|
7035
|
+
mkdirSync5(dataDir, { recursive: true });
|
|
6971
7036
|
}
|
|
6972
7037
|
const password = config.stalwart?.adminPassword || "changeme";
|
|
6973
7038
|
const composePath = join8(dataDir, "docker-compose.yml");
|
|
@@ -6976,16 +7041,16 @@ IMAP_PORT=143
|
|
|
6976
7041
|
image: stalwartlabs/stalwart:latest
|
|
6977
7042
|
container_name: agenticmail-stalwart
|
|
6978
7043
|
ports:
|
|
6979
|
-
- "8080:8080" # HTTP Admin + JMAP
|
|
6980
|
-
- "587:587" # SMTP Submission
|
|
6981
|
-
- "143:143" # IMAP
|
|
6982
|
-
- "25:25" # SMTP
|
|
7044
|
+
- "127.0.0.1:8080:8080" # HTTP Admin + JMAP (localhost only)
|
|
7045
|
+
- "127.0.0.1:587:587" # SMTP Submission (localhost only)
|
|
7046
|
+
- "127.0.0.1:143:143" # IMAP (localhost only)
|
|
7047
|
+
- "127.0.0.1:25:25" # SMTP (localhost only)
|
|
6983
7048
|
volumes:
|
|
6984
7049
|
- stalwart-data:/opt/stalwart
|
|
6985
7050
|
- ./stalwart.toml:/opt/stalwart/etc/config.toml:ro
|
|
6986
7051
|
restart: unless-stopped
|
|
6987
7052
|
healthcheck:
|
|
6988
|
-
test: ["CMD-SHELL", "
|
|
7053
|
+
test: ["CMD-SHELL", "curl -sf http://localhost:8080/health || true"]
|
|
6989
7054
|
interval: 10s
|
|
6990
7055
|
timeout: 5s
|
|
6991
7056
|
retries: 5
|
|
@@ -6993,6 +7058,7 @@ IMAP_PORT=143
|
|
|
6993
7058
|
volumes:
|
|
6994
7059
|
stalwart-data:
|
|
6995
7060
|
`);
|
|
7061
|
+
chmodSync2(composePath, 384);
|
|
6996
7062
|
const tomlPath = join8(dataDir, "stalwart.toml");
|
|
6997
7063
|
writeFileSync4(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
|
|
6998
7064
|
|
|
@@ -7044,6 +7110,7 @@ enable = true
|
|
|
7044
7110
|
user = "admin"
|
|
7045
7111
|
secret = "${password}"
|
|
7046
7112
|
`);
|
|
7113
|
+
chmodSync2(tomlPath, 384);
|
|
7047
7114
|
}
|
|
7048
7115
|
/**
|
|
7049
7116
|
* Check if config has already been initialized.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/core",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Core SDK for AgenticMail
|
|
3
|
+
"version": "0.5.34",
|
|
4
|
+
"description": "Core SDK for AgenticMail — email, SMS, and phone number access for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"better-sqlite3": "^11.8.0",
|
|
29
29
|
"imapflow": "^1.0.170",
|
|
30
30
|
"mailparser": "^3.7.2",
|
|
31
|
-
"nodemailer": "^
|
|
31
|
+
"nodemailer": "^8.0.1",
|
|
32
32
|
"uuid": "^11.1.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|