apple-mail-mcp 1.6.8 → 1.6.9
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.
|
@@ -36,6 +36,17 @@ export declare function splitSearchDiagnostics(output: string, account: string):
|
|
|
36
36
|
payload: string;
|
|
37
37
|
diagnostics: SearchDiagnostics;
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* True if `resolvedPath` is one of the allowed roots or strictly inside one.
|
|
41
|
+
*
|
|
42
|
+
* Uses a path-segment boundary check rather than a bare `startsWith`, which
|
|
43
|
+
* would let a sibling whose name merely shares the prefix slip through —
|
|
44
|
+
* `/Volumes-evil` startsWith `/Volumes`, `/Users/robother` startsWith
|
|
45
|
+
* `/Users/rob` (audit finding #12). `resolvedPath` must already be absolute
|
|
46
|
+
* (caller passes `resolve(...)` output).
|
|
47
|
+
*/
|
|
48
|
+
export declare function isPathWithinAllowedRoots(resolvedPath: string): boolean;
|
|
49
|
+
export declare function escapeForAppleScript(text: string): string;
|
|
39
50
|
/**
|
|
40
51
|
* Emits AppleScript that builds a date into the variable `varName` from numeric
|
|
41
52
|
* components.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,OAAO,EACP,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,SAAS,EAET,oBAAoB,EACpB,UAAU,EACV,qBAAqB,EACrB,QAAQ,EACR,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACb,MAAM,YAAY,CAAC;AA2DpB;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAK7F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,iBAAiB,CAAA;CAAE,CAsCrD;
|
|
1
|
+
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { spawnSync } from "child_process";
|
|
16
16
|
import { existsSync, writeFileSync } from "fs";
|
|
17
|
-
import { isAbsolute, resolve } from "path";
|
|
17
|
+
import { isAbsolute, resolve, sep } from "path";
|
|
18
18
|
import { homedir } from "os";
|
|
19
19
|
import { executeAppleScript } from "../utils/applescript.js";
|
|
20
20
|
import { parseMimeAttachments, extractMimeAttachment, extractHtmlBody } from "../utils/mimeParse.js";
|
|
@@ -139,10 +139,38 @@ export function splitSearchDiagnostics(output, account) {
|
|
|
139
139
|
* @param text - Raw text to escape
|
|
140
140
|
* @returns Text safe for AppleScript string embedding
|
|
141
141
|
*/
|
|
142
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Roots under which `save-attachment` is permitted to write.
|
|
144
|
+
*/
|
|
145
|
+
const ALLOWED_SAVE_ROOTS = [homedir(), "/tmp", "/private/tmp", "/Volumes"];
|
|
146
|
+
/**
|
|
147
|
+
* True if `resolvedPath` is one of the allowed roots or strictly inside one.
|
|
148
|
+
*
|
|
149
|
+
* Uses a path-segment boundary check rather than a bare `startsWith`, which
|
|
150
|
+
* would let a sibling whose name merely shares the prefix slip through —
|
|
151
|
+
* `/Volumes-evil` startsWith `/Volumes`, `/Users/robother` startsWith
|
|
152
|
+
* `/Users/rob` (audit finding #12). `resolvedPath` must already be absolute
|
|
153
|
+
* (caller passes `resolve(...)` output).
|
|
154
|
+
*/
|
|
155
|
+
export function isPathWithinAllowedRoots(resolvedPath) {
|
|
156
|
+
return ALLOWED_SAVE_ROOTS.some((root) => {
|
|
157
|
+
const base = root.endsWith(sep) ? root.slice(0, -1) : root;
|
|
158
|
+
return resolvedPath === base || resolvedPath.startsWith(base + sep);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export function escapeForAppleScript(text) {
|
|
143
162
|
if (!text)
|
|
144
163
|
return "";
|
|
145
|
-
|
|
164
|
+
// Escape backslash and double-quote for the AppleScript string literal, and
|
|
165
|
+
// strip ASCII control characters. An AppleScript double-quoted literal cannot
|
|
166
|
+
// contain a raw newline, so an interpolated value with a `\n` (or other
|
|
167
|
+
// control char) would terminate the literal early and could inject a
|
|
168
|
+
// statement; stripping them closes that gap (audit finding #10).
|
|
169
|
+
return (text
|
|
170
|
+
.replace(/\\/g, "\\\\")
|
|
171
|
+
.replace(/"/g, '\\"')
|
|
172
|
+
// eslint-disable-next-line no-control-regex
|
|
173
|
+
.replace(/[\x00-\x1f\x7f]/g, ""));
|
|
146
174
|
}
|
|
147
175
|
/**
|
|
148
176
|
* Validates attachment file paths and builds AppleScript commands to attach them.
|
|
@@ -1730,9 +1758,7 @@ export class AppleMailManager {
|
|
|
1730
1758
|
}
|
|
1731
1759
|
// Resolve the save path to prevent symlink / ".." traversal bypass
|
|
1732
1760
|
const resolvedPath = resolve(savePath);
|
|
1733
|
-
|
|
1734
|
-
const isAllowed = allowedPrefixes.some((prefix) => resolvedPath.startsWith(prefix));
|
|
1735
|
-
if (!isAllowed) {
|
|
1761
|
+
if (!isPathWithinAllowedRoots(resolvedPath)) {
|
|
1736
1762
|
console.error(`Save path "${savePath}" is outside allowed directories`);
|
|
1737
1763
|
return false;
|
|
1738
1764
|
}
|
|
@@ -1783,8 +1809,7 @@ export class AppleMailManager {
|
|
|
1783
1809
|
try {
|
|
1784
1810
|
const outPath = resolve(resolvedPath, attachmentName);
|
|
1785
1811
|
// Verify the resolved output path is still within allowed directories
|
|
1786
|
-
|
|
1787
|
-
if (!isOutAllowed) {
|
|
1812
|
+
if (!isPathWithinAllowedRoots(outPath)) {
|
|
1788
1813
|
console.error(`Output path "${outPath}" is outside allowed directories`);
|
|
1789
1814
|
return false;
|
|
1790
1815
|
}
|
|
@@ -1816,7 +1841,10 @@ export class AppleMailManager {
|
|
|
1816
1841
|
return mailboxList as text
|
|
1817
1842
|
`;
|
|
1818
1843
|
const script = buildAccountScopedScript(targetAccount, listCommand);
|
|
1819
|
-
|
|
1844
|
+
// Counts every mailbox's message total, so it needs more than the default
|
|
1845
|
+
// 30s on accounts with many/large mailboxes; a timeout here silently
|
|
1846
|
+
// returned an empty list (audit finding #8).
|
|
1847
|
+
const result = executeAppleScript(script, { timeoutMs: 60000 });
|
|
1820
1848
|
if (!result.success) {
|
|
1821
1849
|
console.error(`Failed to list mailboxes: ${result.error}`);
|
|
1822
1850
|
return [];
|
|
@@ -1860,7 +1888,9 @@ export class AppleMailManager {
|
|
|
1860
1888
|
`;
|
|
1861
1889
|
}
|
|
1862
1890
|
const script = buildAccountScopedScript(targetAccount, command);
|
|
1863
|
-
|
|
1891
|
+
// Summing unread across every mailbox can exceed the default 30s; a timeout
|
|
1892
|
+
// previously degraded silently to 0 ("all read") — audit finding #8.
|
|
1893
|
+
const result = executeAppleScript(script, { timeoutMs: 60000 });
|
|
1864
1894
|
if (!result.success) {
|
|
1865
1895
|
console.error(`Failed to get unread count: ${result.error}`);
|
|
1866
1896
|
return 0;
|
|
@@ -2127,18 +2157,22 @@ export class AppleMailManager {
|
|
|
2127
2157
|
set pid to id of p
|
|
2128
2158
|
if seenIds does not contain pid then
|
|
2129
2159
|
set end of seenIds to pid
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
set pEmails to
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
set pPhones to
|
|
2140
|
-
|
|
2141
|
-
|
|
2160
|
+
-- Per-person try: one malformed contact (e.g. no emails) must not
|
|
2161
|
+
-- abort the whole search and return an empty list (audit finding #13).
|
|
2162
|
+
try
|
|
2163
|
+
set pName to name of p
|
|
2164
|
+
set pEmails to ""
|
|
2165
|
+
repeat with e in emails of p
|
|
2166
|
+
if pEmails is not "" then set pEmails to pEmails & ","
|
|
2167
|
+
set pEmails to pEmails & (value of e)
|
|
2168
|
+
end repeat
|
|
2169
|
+
set pPhones to ""
|
|
2170
|
+
repeat with ph in phones of p
|
|
2171
|
+
if pPhones is not "" then set pPhones to pPhones & ","
|
|
2172
|
+
set pPhones to pPhones & (value of ph)
|
|
2173
|
+
end repeat
|
|
2174
|
+
set end of matchedContacts to pName & "${FIELD_SEP}" & pEmails & "${FIELD_SEP}" & pPhones
|
|
2175
|
+
end try
|
|
2142
2176
|
end if
|
|
2143
2177
|
end repeat
|
|
2144
2178
|
|
|
@@ -2203,10 +2237,13 @@ export class AppleMailManager {
|
|
|
2203
2237
|
const template = this.templates.get(id);
|
|
2204
2238
|
if (!template)
|
|
2205
2239
|
return false;
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
const
|
|
2240
|
+
// Use `??` (not `||`) for subject/body so an intentional empty-string
|
|
2241
|
+
// override is honored rather than falling back to the template value
|
|
2242
|
+
// (audit finding #14).
|
|
2243
|
+
const to = overrides?.to ?? template.to ?? [];
|
|
2244
|
+
const cc = overrides?.cc ?? template.cc;
|
|
2245
|
+
const subject = overrides?.subject ?? template.subject;
|
|
2246
|
+
const body = overrides?.body ?? template.body;
|
|
2210
2247
|
if (to.length === 0)
|
|
2211
2248
|
return false;
|
|
2212
2249
|
return this.createDraft(to, subject, body, cc);
|
|
@@ -2429,7 +2466,9 @@ export class AppleMailManager {
|
|
|
2429
2466
|
|
|
2430
2467
|
return "running${FIELD_SEP}" & accountCount & "${FIELD_SEP}" & totalMailboxes
|
|
2431
2468
|
`);
|
|
2432
|
-
|
|
2469
|
+
// Counts mailboxes across every account; give it headroom over the 30s
|
|
2470
|
+
// default so a slow account doesn't silently report "not syncing" (#8).
|
|
2471
|
+
const result = executeAppleScript(script, { timeoutMs: 60000 });
|
|
2433
2472
|
if (!result.success) {
|
|
2434
2473
|
return {
|
|
2435
2474
|
syncDetected: false,
|