apple-mail-mcp 2.20.22 → 2.20.23
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/build/cli.js +58 -21
- package/build/index.js +58 -21
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -12265,44 +12265,77 @@ function sensitiveRoots() {
|
|
|
12265
12265
|
}
|
|
12266
12266
|
});
|
|
12267
12267
|
}
|
|
12268
|
+
function homeCanonical() {
|
|
12269
|
+
try {
|
|
12270
|
+
return canonicalize(homedir());
|
|
12271
|
+
} catch {
|
|
12272
|
+
return void 0;
|
|
12273
|
+
}
|
|
12274
|
+
}
|
|
12268
12275
|
function isWithinRoot(candidate, root) {
|
|
12269
12276
|
return candidate === root || candidate.startsWith(root + sep);
|
|
12270
12277
|
}
|
|
12271
12278
|
function hasHiddenPathSegment(candidate) {
|
|
12272
12279
|
return candidate.split(sep).some((segment) => segment.startsWith(".") && segment.length > 1);
|
|
12273
12280
|
}
|
|
12274
|
-
function
|
|
12281
|
+
function userLibraryTail(candidate) {
|
|
12282
|
+
const segments = candidate.split(sep).filter(Boolean);
|
|
12283
|
+
const lower = segments.map((segment) => segment.toLowerCase());
|
|
12284
|
+
const volumeTops = [
|
|
12285
|
+
0,
|
|
12286
|
+
lower[0] === "volumes" ? 2 : -1,
|
|
12287
|
+
lower.slice(0, 3).join("/") === "system/volumes/data" ? 3 : -1
|
|
12288
|
+
];
|
|
12289
|
+
for (const i of volumeTops) {
|
|
12290
|
+
if (i >= 0 && lower[i] === "users" && lower[i + 2] === "library") return lower.slice(i + 3);
|
|
12291
|
+
}
|
|
12292
|
+
const home = homeCanonical() ?? resolve3(homedir());
|
|
12293
|
+
if (home === sep || !isWithinRoot(candidate, home)) return void 0;
|
|
12294
|
+
const relative = candidate.slice(home.length).split(sep).filter(Boolean);
|
|
12295
|
+
if (relative[0]?.toLowerCase() !== "library") return void 0;
|
|
12296
|
+
return relative.slice(1).map((segment) => segment.toLowerCase());
|
|
12297
|
+
}
|
|
12298
|
+
function isLibraryDocument(tail) {
|
|
12299
|
+
return LIBRARY_DOCUMENT_FOLDERS.some((folder) => folder.every((name2, i) => tail[i] === name2));
|
|
12300
|
+
}
|
|
12301
|
+
function isProtectedPath(candidate, exemptRoots = []) {
|
|
12275
12302
|
if (hasHiddenPathSegment(candidate)) return true;
|
|
12276
12303
|
if (sensitiveRoots().some((root) => isWithinRoot(candidate, root))) return true;
|
|
12277
|
-
|
|
12304
|
+
const tail = userLibraryTail(candidate);
|
|
12305
|
+
if (!tail || isLibraryDocument(tail)) return false;
|
|
12306
|
+
const home = homeCanonical();
|
|
12307
|
+
return !exemptRoots.some(
|
|
12308
|
+
(root) => isWithinRoot(candidate, root) && !(home && isWithinRoot(home, root))
|
|
12309
|
+
);
|
|
12310
|
+
}
|
|
12311
|
+
function canonicalTmpdir() {
|
|
12278
12312
|
try {
|
|
12279
|
-
|
|
12313
|
+
return [canonicalize(tmpdir())];
|
|
12280
12314
|
} catch {
|
|
12281
|
-
|
|
12315
|
+
return [];
|
|
12282
12316
|
}
|
|
12283
|
-
if (!isWithinRoot(candidate, home)) return false;
|
|
12284
|
-
const relative = candidate.slice(home.length).split(sep).filter(Boolean);
|
|
12285
|
-
return relative.length >= 4 && relative[0].toLowerCase() === "library" && relative[1].toLowerCase() === "application support" && relative.at(-1)?.toLowerCase() === "config.json";
|
|
12286
12317
|
}
|
|
12287
|
-
function
|
|
12288
|
-
const raw = env[ATTACHMENT_READ_ROOTS_ENV];
|
|
12289
|
-
const extraRoots = raw === void 0 ? [] : raw.split(delimiter2).map((root) => root.trim()).filter(Boolean);
|
|
12290
|
-
const requested = [...DEFAULT_ATTACHMENT_READ_ROOTS, ...extraRoots];
|
|
12291
|
-
for (const root of requested) {
|
|
12292
|
-
if (!isAbsolute(root)) {
|
|
12293
|
-
throw new Error(`${ATTACHMENT_READ_ROOTS_ENV} entries must be absolute paths.`);
|
|
12294
|
-
}
|
|
12295
|
-
}
|
|
12318
|
+
function canonicalRoots(requested) {
|
|
12296
12319
|
const resolved = [];
|
|
12297
12320
|
for (const root of requested) {
|
|
12298
12321
|
try {
|
|
12299
12322
|
const canonical = canonicalize(resolve3(root));
|
|
12300
|
-
if (!resolved.includes(canonical)) resolved.push(canonical);
|
|
12323
|
+
if (canonical !== sep && !resolved.includes(canonical)) resolved.push(canonical);
|
|
12301
12324
|
} catch {
|
|
12302
12325
|
}
|
|
12303
12326
|
}
|
|
12304
12327
|
return resolved;
|
|
12305
12328
|
}
|
|
12329
|
+
function explicitRoots(env) {
|
|
12330
|
+
const raw = env[ATTACHMENT_READ_ROOTS_ENV];
|
|
12331
|
+
const extraRoots = raw === void 0 ? [] : raw.split(delimiter2).map((root) => root.trim()).filter(Boolean);
|
|
12332
|
+
for (const root of extraRoots) {
|
|
12333
|
+
if (!isAbsolute(root)) {
|
|
12334
|
+
throw new Error(`${ATTACHMENT_READ_ROOTS_ENV} entries must be absolute paths.`);
|
|
12335
|
+
}
|
|
12336
|
+
}
|
|
12337
|
+
return canonicalRoots(extraRoots);
|
|
12338
|
+
}
|
|
12306
12339
|
function resolveAttachmentReadPath(filePath, env = process.env) {
|
|
12307
12340
|
if (!isAbsolute(filePath)) {
|
|
12308
12341
|
throw new Error(`Attachment path must be absolute: "${filePath}"`);
|
|
@@ -12321,19 +12354,22 @@ function resolveAttachmentReadPath(filePath, env = process.env) {
|
|
|
12321
12354
|
if (error2 instanceof Error && error2.message.includes("not a regular file")) throw error2;
|
|
12322
12355
|
throw new Error(`Attachment file not found: "${filePath}"`);
|
|
12323
12356
|
}
|
|
12324
|
-
|
|
12357
|
+
const explicit = explicitRoots(env);
|
|
12358
|
+
const exempt = [...explicit, ...canonicalTmpdir()];
|
|
12359
|
+
if (isProtectedPath(canonical, exempt) || isProtectedPath(resolve3(filePath), exempt)) {
|
|
12325
12360
|
throw new Error(
|
|
12326
|
-
`Attachment path is in a protected location: "${filePath}". Hidden files
|
|
12361
|
+
`Attachment path is in a protected location: "${filePath}". Hidden files, credential locations and user Library folders (except iCloud Drive and CloudStorage) cannot be sent as attachments unless ${ATTACHMENT_READ_ROOTS_ENV} names a root for them.`
|
|
12327
12362
|
);
|
|
12328
12363
|
}
|
|
12329
|
-
|
|
12364
|
+
const roots = [...canonicalRoots(DEFAULT_ATTACHMENT_READ_ROOTS), ...explicit];
|
|
12365
|
+
if (!roots.some((root) => isWithinRoot(canonical, root))) {
|
|
12330
12366
|
throw new Error(
|
|
12331
12367
|
`Attachment path is outside the allowed read roots: "${filePath}". Use an ordinary home-directory, /Volumes, or temporary path, or configure ${ATTACHMENT_READ_ROOTS_ENV} for an additional explicit root.`
|
|
12332
12368
|
);
|
|
12333
12369
|
}
|
|
12334
12370
|
return canonical;
|
|
12335
12371
|
}
|
|
12336
|
-
var ATTACHMENT_READ_ROOTS_ENV, DEFAULT_ATTACHMENT_READ_ROOTS, SENSITIVE_HOME_ROOTS;
|
|
12372
|
+
var ATTACHMENT_READ_ROOTS_ENV, DEFAULT_ATTACHMENT_READ_ROOTS, SENSITIVE_HOME_ROOTS, LIBRARY_DOCUMENT_FOLDERS;
|
|
12337
12373
|
var init_attachmentReadPolicy = __esm({
|
|
12338
12374
|
"src/utils/attachmentReadPolicy.ts"() {
|
|
12339
12375
|
"use strict";
|
|
@@ -12345,6 +12381,7 @@ var init_attachmentReadPolicy = __esm({
|
|
|
12345
12381
|
join(homedir(), ".config", "gh"),
|
|
12346
12382
|
join(homedir(), "Library", "Keychains")
|
|
12347
12383
|
];
|
|
12384
|
+
LIBRARY_DOCUMENT_FOLDERS = [["mobile documents", "com~apple~clouddocs"], ["cloudstorage"]];
|
|
12348
12385
|
}
|
|
12349
12386
|
});
|
|
12350
12387
|
|
package/build/index.js
CHANGED
|
@@ -64830,44 +64830,77 @@ function sensitiveRoots() {
|
|
|
64830
64830
|
}
|
|
64831
64831
|
});
|
|
64832
64832
|
}
|
|
64833
|
+
function homeCanonical() {
|
|
64834
|
+
try {
|
|
64835
|
+
return canonicalize(homedir());
|
|
64836
|
+
} catch {
|
|
64837
|
+
return void 0;
|
|
64838
|
+
}
|
|
64839
|
+
}
|
|
64833
64840
|
function isWithinRoot(candidate, root) {
|
|
64834
64841
|
return candidate === root || candidate.startsWith(root + sep);
|
|
64835
64842
|
}
|
|
64836
64843
|
function hasHiddenPathSegment(candidate) {
|
|
64837
64844
|
return candidate.split(sep).some((segment) => segment.startsWith(".") && segment.length > 1);
|
|
64838
64845
|
}
|
|
64839
|
-
function
|
|
64846
|
+
function userLibraryTail(candidate) {
|
|
64847
|
+
const segments = candidate.split(sep).filter(Boolean);
|
|
64848
|
+
const lower = segments.map((segment) => segment.toLowerCase());
|
|
64849
|
+
const volumeTops = [
|
|
64850
|
+
0,
|
|
64851
|
+
lower[0] === "volumes" ? 2 : -1,
|
|
64852
|
+
lower.slice(0, 3).join("/") === "system/volumes/data" ? 3 : -1
|
|
64853
|
+
];
|
|
64854
|
+
for (const i of volumeTops) {
|
|
64855
|
+
if (i >= 0 && lower[i] === "users" && lower[i + 2] === "library") return lower.slice(i + 3);
|
|
64856
|
+
}
|
|
64857
|
+
const home = homeCanonical() ?? resolve3(homedir());
|
|
64858
|
+
if (home === sep || !isWithinRoot(candidate, home)) return void 0;
|
|
64859
|
+
const relative = candidate.slice(home.length).split(sep).filter(Boolean);
|
|
64860
|
+
if (relative[0]?.toLowerCase() !== "library") return void 0;
|
|
64861
|
+
return relative.slice(1).map((segment) => segment.toLowerCase());
|
|
64862
|
+
}
|
|
64863
|
+
function isLibraryDocument(tail) {
|
|
64864
|
+
return LIBRARY_DOCUMENT_FOLDERS.some((folder) => folder.every((name2, i) => tail[i] === name2));
|
|
64865
|
+
}
|
|
64866
|
+
function isProtectedPath(candidate, exemptRoots = []) {
|
|
64840
64867
|
if (hasHiddenPathSegment(candidate)) return true;
|
|
64841
64868
|
if (sensitiveRoots().some((root) => isWithinRoot(candidate, root))) return true;
|
|
64842
|
-
|
|
64869
|
+
const tail = userLibraryTail(candidate);
|
|
64870
|
+
if (!tail || isLibraryDocument(tail)) return false;
|
|
64871
|
+
const home = homeCanonical();
|
|
64872
|
+
return !exemptRoots.some(
|
|
64873
|
+
(root) => isWithinRoot(candidate, root) && !(home && isWithinRoot(home, root))
|
|
64874
|
+
);
|
|
64875
|
+
}
|
|
64876
|
+
function canonicalTmpdir() {
|
|
64843
64877
|
try {
|
|
64844
|
-
|
|
64878
|
+
return [canonicalize(tmpdir())];
|
|
64845
64879
|
} catch {
|
|
64846
|
-
|
|
64880
|
+
return [];
|
|
64847
64881
|
}
|
|
64848
|
-
if (!isWithinRoot(candidate, home)) return false;
|
|
64849
|
-
const relative = candidate.slice(home.length).split(sep).filter(Boolean);
|
|
64850
|
-
return relative.length >= 4 && relative[0].toLowerCase() === "library" && relative[1].toLowerCase() === "application support" && relative.at(-1)?.toLowerCase() === "config.json";
|
|
64851
64882
|
}
|
|
64852
|
-
function
|
|
64853
|
-
const raw = env[ATTACHMENT_READ_ROOTS_ENV];
|
|
64854
|
-
const extraRoots = raw === void 0 ? [] : raw.split(delimiter2).map((root) => root.trim()).filter(Boolean);
|
|
64855
|
-
const requested = [...DEFAULT_ATTACHMENT_READ_ROOTS, ...extraRoots];
|
|
64856
|
-
for (const root of requested) {
|
|
64857
|
-
if (!isAbsolute(root)) {
|
|
64858
|
-
throw new Error(`${ATTACHMENT_READ_ROOTS_ENV} entries must be absolute paths.`);
|
|
64859
|
-
}
|
|
64860
|
-
}
|
|
64883
|
+
function canonicalRoots(requested) {
|
|
64861
64884
|
const resolved = [];
|
|
64862
64885
|
for (const root of requested) {
|
|
64863
64886
|
try {
|
|
64864
64887
|
const canonical = canonicalize(resolve3(root));
|
|
64865
|
-
if (!resolved.includes(canonical)) resolved.push(canonical);
|
|
64888
|
+
if (canonical !== sep && !resolved.includes(canonical)) resolved.push(canonical);
|
|
64866
64889
|
} catch {
|
|
64867
64890
|
}
|
|
64868
64891
|
}
|
|
64869
64892
|
return resolved;
|
|
64870
64893
|
}
|
|
64894
|
+
function explicitRoots(env) {
|
|
64895
|
+
const raw = env[ATTACHMENT_READ_ROOTS_ENV];
|
|
64896
|
+
const extraRoots = raw === void 0 ? [] : raw.split(delimiter2).map((root) => root.trim()).filter(Boolean);
|
|
64897
|
+
for (const root of extraRoots) {
|
|
64898
|
+
if (!isAbsolute(root)) {
|
|
64899
|
+
throw new Error(`${ATTACHMENT_READ_ROOTS_ENV} entries must be absolute paths.`);
|
|
64900
|
+
}
|
|
64901
|
+
}
|
|
64902
|
+
return canonicalRoots(extraRoots);
|
|
64903
|
+
}
|
|
64871
64904
|
function resolveAttachmentReadPath(filePath, env = process.env) {
|
|
64872
64905
|
if (!isAbsolute(filePath)) {
|
|
64873
64906
|
throw new Error(`Attachment path must be absolute: "${filePath}"`);
|
|
@@ -64886,19 +64919,22 @@ function resolveAttachmentReadPath(filePath, env = process.env) {
|
|
|
64886
64919
|
if (error3 instanceof Error && error3.message.includes("not a regular file")) throw error3;
|
|
64887
64920
|
throw new Error(`Attachment file not found: "${filePath}"`);
|
|
64888
64921
|
}
|
|
64889
|
-
|
|
64922
|
+
const explicit = explicitRoots(env);
|
|
64923
|
+
const exempt = [...explicit, ...canonicalTmpdir()];
|
|
64924
|
+
if (isProtectedPath(canonical, exempt) || isProtectedPath(resolve3(filePath), exempt)) {
|
|
64890
64925
|
throw new Error(
|
|
64891
|
-
`Attachment path is in a protected location: "${filePath}". Hidden files
|
|
64926
|
+
`Attachment path is in a protected location: "${filePath}". Hidden files, credential locations and user Library folders (except iCloud Drive and CloudStorage) cannot be sent as attachments unless ${ATTACHMENT_READ_ROOTS_ENV} names a root for them.`
|
|
64892
64927
|
);
|
|
64893
64928
|
}
|
|
64894
|
-
|
|
64929
|
+
const roots = [...canonicalRoots(DEFAULT_ATTACHMENT_READ_ROOTS), ...explicit];
|
|
64930
|
+
if (!roots.some((root) => isWithinRoot(canonical, root))) {
|
|
64895
64931
|
throw new Error(
|
|
64896
64932
|
`Attachment path is outside the allowed read roots: "${filePath}". Use an ordinary home-directory, /Volumes, or temporary path, or configure ${ATTACHMENT_READ_ROOTS_ENV} for an additional explicit root.`
|
|
64897
64933
|
);
|
|
64898
64934
|
}
|
|
64899
64935
|
return canonical;
|
|
64900
64936
|
}
|
|
64901
|
-
var ATTACHMENT_READ_ROOTS_ENV, DEFAULT_ATTACHMENT_READ_ROOTS, SENSITIVE_HOME_ROOTS;
|
|
64937
|
+
var ATTACHMENT_READ_ROOTS_ENV, DEFAULT_ATTACHMENT_READ_ROOTS, SENSITIVE_HOME_ROOTS, LIBRARY_DOCUMENT_FOLDERS;
|
|
64902
64938
|
var init_attachmentReadPolicy = __esm({
|
|
64903
64939
|
"src/utils/attachmentReadPolicy.ts"() {
|
|
64904
64940
|
"use strict";
|
|
@@ -64910,6 +64946,7 @@ var init_attachmentReadPolicy = __esm({
|
|
|
64910
64946
|
join(homedir(), ".config", "gh"),
|
|
64911
64947
|
join(homedir(), "Library", "Keychains")
|
|
64912
64948
|
];
|
|
64949
|
+
LIBRARY_DOCUMENT_FOLDERS = [["mobile documents", "com~apple~clouddocs"], ["cloudstorage"]];
|
|
64913
64950
|
}
|
|
64914
64951
|
});
|
|
64915
64952
|
|
package/package.json
CHANGED