@trops/dash-core 0.1.485 → 0.1.487
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/electron/index.js +314 -60
- package/dist/electron/index.js.map +1 -1
- package/package.json +3 -1
package/dist/electron/index.js
CHANGED
|
@@ -4,7 +4,7 @@ var require$$0$1 = require('electron');
|
|
|
4
4
|
var require$$1$1 = require('electron-store');
|
|
5
5
|
var require$$1$2 = require('path');
|
|
6
6
|
var require$$0$2 = require('fs');
|
|
7
|
-
var require$$
|
|
7
|
+
var require$$6$1 = require('objects-to-csv');
|
|
8
8
|
var require$$1$3 = require('readline');
|
|
9
9
|
var require$$2 = require('xtreamer');
|
|
10
10
|
var require$$3$1 = require('xml2js');
|
|
@@ -12,12 +12,12 @@ var require$$4 = require('JSONStream');
|
|
|
12
12
|
var require$$5 = require('stream');
|
|
13
13
|
var require$$6 = require('csv-parser');
|
|
14
14
|
var require$$0$3 = require('quickjs-emscripten');
|
|
15
|
-
var require$$
|
|
15
|
+
var require$$8$1 = require('https');
|
|
16
16
|
var require$$0$5 = require('@modelcontextprotocol/sdk/client/index.js');
|
|
17
17
|
var require$$1$4 = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
18
18
|
var require$$0$4 = require('pkce-challenge');
|
|
19
19
|
var require$$2$1 = require('os');
|
|
20
|
-
var require$$7
|
|
20
|
+
var require$$7 = require('child_process');
|
|
21
21
|
var require$$3$2 = require('adm-zip');
|
|
22
22
|
var require$$4$1 = require('url');
|
|
23
23
|
var require$$2$2 = require('vm');
|
|
@@ -28,7 +28,7 @@ var require$$0$6 = require('openai');
|
|
|
28
28
|
require('live-plugin-manager');
|
|
29
29
|
var require$$0$9 = require('@anthropic-ai/sdk');
|
|
30
30
|
var require$$3$4 = require('crypto');
|
|
31
|
-
var require$$8$
|
|
31
|
+
var require$$8$2 = require('zod');
|
|
32
32
|
var require$$0$7 = require('http');
|
|
33
33
|
var require$$1$6 = require('http2');
|
|
34
34
|
var require$$2$4 = require('node-forge');
|
|
@@ -1107,7 +1107,7 @@ var secureStoreController$1 = {
|
|
|
1107
1107
|
getData: getData$1,
|
|
1108
1108
|
};
|
|
1109
1109
|
|
|
1110
|
-
const path$
|
|
1110
|
+
const path$k = require$$1$2;
|
|
1111
1111
|
const {
|
|
1112
1112
|
readFileSync,
|
|
1113
1113
|
writeFileSync: writeFileSync$4,
|
|
@@ -1125,7 +1125,7 @@ const {
|
|
|
1125
1125
|
function ensureDirectoryExistence$2(filePath) {
|
|
1126
1126
|
try {
|
|
1127
1127
|
// isDirectory
|
|
1128
|
-
var dirname = path$
|
|
1128
|
+
var dirname = path$k.dirname(filePath);
|
|
1129
1129
|
// check if the directory exists...return true
|
|
1130
1130
|
// if not, we can pass in the dirname as the filepath
|
|
1131
1131
|
// and check each directory recursively.
|
|
@@ -1240,7 +1240,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
|
|
|
1240
1240
|
|
|
1241
1241
|
for (const file of files) {
|
|
1242
1242
|
if (!excludeFiles.includes(file)) {
|
|
1243
|
-
unlinkSync(path$
|
|
1243
|
+
unlinkSync(path$k.join(directory, file), (err) => {
|
|
1244
1244
|
if (err) throw err;
|
|
1245
1245
|
});
|
|
1246
1246
|
}
|
|
@@ -1257,8 +1257,8 @@ var file = {
|
|
|
1257
1257
|
checkDirectory: checkDirectory$1,
|
|
1258
1258
|
};
|
|
1259
1259
|
|
|
1260
|
-
const { app: app$
|
|
1261
|
-
const path$
|
|
1260
|
+
const { app: app$c } = require$$0$1;
|
|
1261
|
+
const path$j = require$$1$2;
|
|
1262
1262
|
const { writeFileSync: writeFileSync$3 } = require$$0$2;
|
|
1263
1263
|
const { getFileContents: getFileContents$7 } = file;
|
|
1264
1264
|
|
|
@@ -1305,8 +1305,8 @@ const workspaceController$3 = {
|
|
|
1305
1305
|
saveWorkspaceForApplication: (win, appId, workspaceObject) => {
|
|
1306
1306
|
try {
|
|
1307
1307
|
// filename to the pages file (live pages)
|
|
1308
|
-
const filename = path$
|
|
1309
|
-
app$
|
|
1308
|
+
const filename = path$j.join(
|
|
1309
|
+
app$c.getPath("userData"),
|
|
1310
1310
|
appName$7,
|
|
1311
1311
|
appId,
|
|
1312
1312
|
configFilename$5,
|
|
@@ -1354,8 +1354,8 @@ const workspaceController$3 = {
|
|
|
1354
1354
|
saveMenuItemsForApplication: (win, appId, menuItems) => {
|
|
1355
1355
|
try {
|
|
1356
1356
|
// filename to the workspaces file
|
|
1357
|
-
const filename = path$
|
|
1358
|
-
app$
|
|
1357
|
+
const filename = path$j.join(
|
|
1358
|
+
app$c.getPath("userData"),
|
|
1359
1359
|
appName$7,
|
|
1360
1360
|
appId,
|
|
1361
1361
|
configFilename$5,
|
|
@@ -1403,8 +1403,8 @@ const workspaceController$3 = {
|
|
|
1403
1403
|
*/
|
|
1404
1404
|
deleteWorkspaceForApplication: (win, appId, workspaceId) => {
|
|
1405
1405
|
try {
|
|
1406
|
-
const filename = path$
|
|
1407
|
-
app$
|
|
1406
|
+
const filename = path$j.join(
|
|
1407
|
+
app$c.getPath("userData"),
|
|
1408
1408
|
appName$7,
|
|
1409
1409
|
appId,
|
|
1410
1410
|
configFilename$5,
|
|
@@ -1437,8 +1437,8 @@ const workspaceController$3 = {
|
|
|
1437
1437
|
|
|
1438
1438
|
listWorkspacesForApplication: (win, appId) => {
|
|
1439
1439
|
try {
|
|
1440
|
-
const filename = path$
|
|
1441
|
-
app$
|
|
1440
|
+
const filename = path$j.join(
|
|
1441
|
+
app$c.getPath("userData"),
|
|
1442
1442
|
appName$7,
|
|
1443
1443
|
appId,
|
|
1444
1444
|
configFilename$5,
|
|
@@ -1465,8 +1465,8 @@ const workspaceController$3 = {
|
|
|
1465
1465
|
|
|
1466
1466
|
listMenuItemsForApplication: (win, appId) => {
|
|
1467
1467
|
try {
|
|
1468
|
-
const filename = path$
|
|
1469
|
-
app$
|
|
1468
|
+
const filename = path$j.join(
|
|
1469
|
+
app$c.getPath("userData"),
|
|
1470
1470
|
appName$7,
|
|
1471
1471
|
appId,
|
|
1472
1472
|
configFilename$5,
|
|
@@ -1509,8 +1509,8 @@ const workspaceController$3 = {
|
|
|
1509
1509
|
|
|
1510
1510
|
var workspaceController_1 = workspaceController$3;
|
|
1511
1511
|
|
|
1512
|
-
const { app: app$
|
|
1513
|
-
const path$
|
|
1512
|
+
const { app: app$b } = require$$0$1;
|
|
1513
|
+
const path$i = require$$1$2;
|
|
1514
1514
|
const { writeFileSync: writeFileSync$2 } = require$$0$2;
|
|
1515
1515
|
const { getFileContents: getFileContents$6 } = file;
|
|
1516
1516
|
|
|
@@ -1530,8 +1530,8 @@ const themeController$5 = {
|
|
|
1530
1530
|
saveThemeForApplication: (win, appId, name, obj) => {
|
|
1531
1531
|
try {
|
|
1532
1532
|
// filename to the pages file (live pages)
|
|
1533
|
-
const filename = path$
|
|
1534
|
-
app$
|
|
1533
|
+
const filename = path$i.join(
|
|
1534
|
+
app$b.getPath("userData"),
|
|
1535
1535
|
appName$6,
|
|
1536
1536
|
appId,
|
|
1537
1537
|
configFilename$4,
|
|
@@ -1576,8 +1576,8 @@ const themeController$5 = {
|
|
|
1576
1576
|
*/
|
|
1577
1577
|
listThemesForApplication: (win, appId) => {
|
|
1578
1578
|
try {
|
|
1579
|
-
const filename = path$
|
|
1580
|
-
app$
|
|
1579
|
+
const filename = path$i.join(
|
|
1580
|
+
app$b.getPath("userData"),
|
|
1581
1581
|
appName$6,
|
|
1582
1582
|
appId,
|
|
1583
1583
|
configFilename$4,
|
|
@@ -1618,8 +1618,8 @@ const themeController$5 = {
|
|
|
1618
1618
|
*/
|
|
1619
1619
|
deleteThemeForApplication: (win, appId, themeKey) => {
|
|
1620
1620
|
try {
|
|
1621
|
-
const filename = path$
|
|
1622
|
-
app$
|
|
1621
|
+
const filename = path$i.join(
|
|
1622
|
+
app$b.getPath("userData"),
|
|
1623
1623
|
appName$6,
|
|
1624
1624
|
appId,
|
|
1625
1625
|
configFilename$4,
|
|
@@ -1650,6 +1650,179 @@ const themeController$5 = {
|
|
|
1650
1650
|
|
|
1651
1651
|
var themeController_1 = themeController$5;
|
|
1652
1652
|
|
|
1653
|
+
/**
|
|
1654
|
+
* safePath.js
|
|
1655
|
+
*
|
|
1656
|
+
* Path-traversal containment for IPC handlers that accept renderer-
|
|
1657
|
+
* supplied paths.
|
|
1658
|
+
*
|
|
1659
|
+
* Why: dash-core exposes IPC handlers (mainApi.data.saveData,
|
|
1660
|
+
* mainApi.data.parseXMLStream, mainApi.algolia.createBatchesFromFile,
|
|
1661
|
+
* etc.) that historically passed renderer-controlled paths directly to
|
|
1662
|
+
* fs.writeFileSync / fs.createReadStream. A widget could pass
|
|
1663
|
+
* "../../etc/passwd" and the handler would write/read OUTSIDE the
|
|
1664
|
+
* intended app data directory because path.join doesn't reject `..`
|
|
1665
|
+
* segments. See docs/security/ipc-filesystem-audit.md for the full
|
|
1666
|
+
* finding set.
|
|
1667
|
+
*
|
|
1668
|
+
* This utility resolves the requested path, walks symlinks, and asserts
|
|
1669
|
+
* containment within at least one explicitly-allowed root. Any handler
|
|
1670
|
+
* that takes a renderer path runs it through `safePath(p, roots)` and
|
|
1671
|
+
* either gets back a validated absolute real-path, or throws.
|
|
1672
|
+
*
|
|
1673
|
+
* Public API:
|
|
1674
|
+
*
|
|
1675
|
+
* safePath(requested, allowedRoots[]) → string
|
|
1676
|
+
* Throws on traversal, missing input, or empty roots. Returns the
|
|
1677
|
+
* resolved real-path (which is what the caller should pass to fs).
|
|
1678
|
+
*
|
|
1679
|
+
* getAllowedRoots(category) → string[]
|
|
1680
|
+
* Canonical roots per category. Categories:
|
|
1681
|
+
* "data" — userData/Dashboard/data + user-configured override
|
|
1682
|
+
* "themes" — userData/Dashboard/themes
|
|
1683
|
+
* "widgets" — userData/widgets
|
|
1684
|
+
* "plugins" — userData/plugins
|
|
1685
|
+
* "downloads"— OS Downloads folder
|
|
1686
|
+
*
|
|
1687
|
+
* Defense layers:
|
|
1688
|
+
* 1. path.resolve() to absolute form.
|
|
1689
|
+
* 2. fs.realpathSync() through any symlinks. If the path doesn't
|
|
1690
|
+
* exist yet, realpath the parent directory (so a symlink-in-parent
|
|
1691
|
+
* can't trick a future create operation).
|
|
1692
|
+
* 3. startsWith(realRoot + path.sep) test — single-equals check
|
|
1693
|
+
* handles "exactly the root" case, prefix-with-sep handles
|
|
1694
|
+
* "inside the root" without false-matching `/data-evil/` against
|
|
1695
|
+
* `/data/`.
|
|
1696
|
+
*/
|
|
1697
|
+
|
|
1698
|
+
const path$h = require$$1$2;
|
|
1699
|
+
const fs$c = require$$0$2;
|
|
1700
|
+
const { app: app$a } = require$$0$1;
|
|
1701
|
+
|
|
1702
|
+
const APP_NAME = "Dashboard";
|
|
1703
|
+
|
|
1704
|
+
/**
|
|
1705
|
+
* @param {string} category
|
|
1706
|
+
* @returns {string[]} ordered allowed roots for that category
|
|
1707
|
+
*/
|
|
1708
|
+
function getAllowedRoots$2(category) {
|
|
1709
|
+
const userData = app$a.getPath("userData");
|
|
1710
|
+
switch (category) {
|
|
1711
|
+
case "data": {
|
|
1712
|
+
const def = path$h.join(userData, APP_NAME, "data");
|
|
1713
|
+
// The user can configure a custom data directory in
|
|
1714
|
+
// Settings → General → Data Directory. If set, that
|
|
1715
|
+
// location is ALSO an allowed root. We don't replace the
|
|
1716
|
+
// default — both are valid because legacy data may still
|
|
1717
|
+
// live in the default while new data goes to the override.
|
|
1718
|
+
const override = readDataDirectoryFromSettings();
|
|
1719
|
+
return override ? [def, override] : [def];
|
|
1720
|
+
}
|
|
1721
|
+
case "themes":
|
|
1722
|
+
return [path$h.join(userData, APP_NAME, "themes")];
|
|
1723
|
+
case "widgets":
|
|
1724
|
+
return [path$h.join(userData, "widgets")];
|
|
1725
|
+
case "plugins":
|
|
1726
|
+
return [path$h.join(userData, "plugins")];
|
|
1727
|
+
case "downloads":
|
|
1728
|
+
return [app$a.getPath("downloads")];
|
|
1729
|
+
default:
|
|
1730
|
+
throw new Error("safePath: unknown allowed-roots category: " + category);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
/**
|
|
1735
|
+
* Read the user-configured data directory from settings.json. Returns
|
|
1736
|
+
* undefined if not set or unreadable.
|
|
1737
|
+
*
|
|
1738
|
+
* Inlined to avoid a circular require with settingsController. Reads
|
|
1739
|
+
* the same settings.json file directly.
|
|
1740
|
+
*/
|
|
1741
|
+
function readDataDirectoryFromSettings() {
|
|
1742
|
+
try {
|
|
1743
|
+
const settingsPath = path$h.join(
|
|
1744
|
+
app$a.getPath("userData"),
|
|
1745
|
+
APP_NAME,
|
|
1746
|
+
"settings.json",
|
|
1747
|
+
);
|
|
1748
|
+
if (!fs$c.existsSync(settingsPath)) return undefined;
|
|
1749
|
+
const raw = fs$c.readFileSync(settingsPath, "utf8");
|
|
1750
|
+
const settings = JSON.parse(raw);
|
|
1751
|
+
const dir = settings && settings.dataDirectory;
|
|
1752
|
+
if (typeof dir === "string" && dir) return dir;
|
|
1753
|
+
} catch (_e) {
|
|
1754
|
+
// best-effort — fall through to default
|
|
1755
|
+
}
|
|
1756
|
+
return undefined;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* Resolve and validate a path against allowed roots.
|
|
1761
|
+
*
|
|
1762
|
+
* @param {string} requested the path the renderer asked for
|
|
1763
|
+
* @param {string[]} allowedRoots list of absolute paths the result must be inside
|
|
1764
|
+
* @returns {string} validated absolute real-path
|
|
1765
|
+
* @throws if requested is not contained within any allowed root
|
|
1766
|
+
*/
|
|
1767
|
+
function safePath$2(requested, allowedRoots) {
|
|
1768
|
+
if (typeof requested !== "string" || !requested) {
|
|
1769
|
+
throw new Error("safePath: requested must be a non-empty string");
|
|
1770
|
+
}
|
|
1771
|
+
if (!Array.isArray(allowedRoots) || allowedRoots.length === 0) {
|
|
1772
|
+
throw new Error("safePath: allowedRoots must be a non-empty array");
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
const resolved = path$h.resolve(requested);
|
|
1776
|
+
|
|
1777
|
+
// Real-path through symlinks. If the file doesn't exist yet (a
|
|
1778
|
+
// create-new operation), real-path the parent so a symlink in the
|
|
1779
|
+
// parent chain can't trick us.
|
|
1780
|
+
let real = resolved;
|
|
1781
|
+
try {
|
|
1782
|
+
real = fs$c.realpathSync(resolved);
|
|
1783
|
+
} catch (_e) {
|
|
1784
|
+
try {
|
|
1785
|
+
const parent = fs$c.realpathSync(path$h.dirname(resolved));
|
|
1786
|
+
real = path$h.join(parent, path$h.basename(resolved));
|
|
1787
|
+
} catch (_e2) {
|
|
1788
|
+
// Parent doesn't exist either. Use the resolved-but-not-
|
|
1789
|
+
// real path; the caller's mkdirSync will happen inside the
|
|
1790
|
+
// validated root, and any symlinks underneath will be
|
|
1791
|
+
// re-checked the next time safePath sees the same path.
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
for (const root of allowedRoots) {
|
|
1796
|
+
let realRoot = root;
|
|
1797
|
+
try {
|
|
1798
|
+
if (fs$c.existsSync(root)) realRoot = fs$c.realpathSync(root);
|
|
1799
|
+
} catch (_e) {
|
|
1800
|
+
// root doesn't exist or isn't reachable — keep as-is for
|
|
1801
|
+
// the comparison below
|
|
1802
|
+
}
|
|
1803
|
+
// Exact match OR strictly-inside (with separator to prevent
|
|
1804
|
+
// /data-evil/ matching /data/).
|
|
1805
|
+
if (real === realRoot || real.startsWith(realRoot + path$h.sep)) {
|
|
1806
|
+
return real;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
throw new Error(
|
|
1811
|
+
"safePath: requested path is not within any allowed root. " +
|
|
1812
|
+
"Requested: " +
|
|
1813
|
+
requested +
|
|
1814
|
+
" (resolved to " +
|
|
1815
|
+
real +
|
|
1816
|
+
"). Allowed roots: " +
|
|
1817
|
+
allowedRoots.join(", "),
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
var safePath_1 = {
|
|
1822
|
+
safePath: safePath$2,
|
|
1823
|
+
getAllowedRoots: getAllowedRoots$2,
|
|
1824
|
+
};
|
|
1825
|
+
|
|
1653
1826
|
/**
|
|
1654
1827
|
* safeJsExecutor.js
|
|
1655
1828
|
*
|
|
@@ -2337,11 +2510,12 @@ var fs$a = require$$0$2;
|
|
|
2337
2510
|
const path$f = require$$1$2;
|
|
2338
2511
|
const events$5 = events$8;
|
|
2339
2512
|
const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
|
|
2513
|
+
const { safePath: safePath$1, getAllowedRoots: getAllowedRoots$1 } = safePath_1;
|
|
2340
2514
|
|
|
2341
2515
|
// Convert Json to Csv
|
|
2342
|
-
const ObjectsToCsv = require$$
|
|
2516
|
+
const ObjectsToCsv = require$$6$1;
|
|
2343
2517
|
const Transform = transform;
|
|
2344
|
-
const https$3 = require$$
|
|
2518
|
+
const https$3 = require$$8$1;
|
|
2345
2519
|
const appName$5 = "Dashboard";
|
|
2346
2520
|
|
|
2347
2521
|
const dataController$1 = {
|
|
@@ -2355,14 +2529,25 @@ const dataController$1 = {
|
|
|
2355
2529
|
*/
|
|
2356
2530
|
convertJsonToCsvFile: (win, appId, jsonObject, toFilename = "test.csv") => {
|
|
2357
2531
|
try {
|
|
2358
|
-
//
|
|
2359
|
-
|
|
2532
|
+
// Validate the renderer-supplied filename is contained within
|
|
2533
|
+
// the data directory. path.join doesn't reject `..` segments;
|
|
2534
|
+
// safePath does.
|
|
2535
|
+
const candidate = path$f.join(
|
|
2360
2536
|
app$8.getPath("userData"),
|
|
2361
2537
|
appName$5,
|
|
2362
2538
|
appId,
|
|
2363
2539
|
"data",
|
|
2364
2540
|
toFilename,
|
|
2365
2541
|
);
|
|
2542
|
+
let filename;
|
|
2543
|
+
try {
|
|
2544
|
+
filename = safePath$1(candidate, getAllowedRoots$1("data"));
|
|
2545
|
+
} catch (pathErr) {
|
|
2546
|
+
win.webContents.send(events$5.DATA_JSON_TO_CSV_FILE_ERROR, {
|
|
2547
|
+
error: pathErr.message,
|
|
2548
|
+
});
|
|
2549
|
+
return;
|
|
2550
|
+
}
|
|
2366
2551
|
|
|
2367
2552
|
// make sure the file exists...
|
|
2368
2553
|
const fileContents = getFileContents$5(filename, "");
|
|
@@ -2420,8 +2605,17 @@ const dataController$1 = {
|
|
|
2420
2605
|
|
|
2421
2606
|
readLinesFromFile: (win, filepath, lineCount) => {
|
|
2422
2607
|
try {
|
|
2608
|
+
let validated;
|
|
2609
|
+
try {
|
|
2610
|
+
validated = safePath$1(filepath, getAllowedRoots$1("data"));
|
|
2611
|
+
} catch (pathErr) {
|
|
2612
|
+
win.webContents.send(events$5.READ_LINES_ERROR, {
|
|
2613
|
+
error: pathErr.message,
|
|
2614
|
+
});
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2423
2617
|
const t = new Transform();
|
|
2424
|
-
t.readLinesFromFile(win,
|
|
2618
|
+
t.readLinesFromFile(win, validated, lineCount, events$5.READ_LINES_UPDATE)
|
|
2425
2619
|
.then((res) => {
|
|
2426
2620
|
win.webContents.send(events$5.READ_LINES_COMPLETE, {
|
|
2427
2621
|
success: true,
|
|
@@ -2445,9 +2639,18 @@ const dataController$1 = {
|
|
|
2445
2639
|
|
|
2446
2640
|
readJSONFromFile: (win, filepath, objectCount = null) => {
|
|
2447
2641
|
try {
|
|
2448
|
-
|
|
2642
|
+
let validated;
|
|
2643
|
+
try {
|
|
2644
|
+
validated = safePath$1(filepath, getAllowedRoots$1("data"));
|
|
2645
|
+
} catch (pathErr) {
|
|
2646
|
+
win.webContents.send(events$5.READ_JSON_ERROR, {
|
|
2647
|
+
error: pathErr.message,
|
|
2648
|
+
});
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
console.log("reading json from file ", validated, objectCount);
|
|
2449
2652
|
const t = new Transform();
|
|
2450
|
-
t.readJSONFromFile(win,
|
|
2653
|
+
t.readJSONFromFile(win, validated, objectCount, events$5.READ_JSON_UPDATE)
|
|
2451
2654
|
.then((res) => {
|
|
2452
2655
|
win.webContents.send(events$5.READ_JSON_COMPLETE, {
|
|
2453
2656
|
success: true,
|
|
@@ -2483,14 +2686,10 @@ const dataController$1 = {
|
|
|
2483
2686
|
);
|
|
2484
2687
|
}
|
|
2485
2688
|
|
|
2486
|
-
// Validate toFilepath is within the app data directory
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
throw new Error(
|
|
2491
|
-
"File path must be within the application data directory",
|
|
2492
|
-
);
|
|
2493
|
-
}
|
|
2689
|
+
// Validate toFilepath is within the app data directory.
|
|
2690
|
+
// safePath replaces the previous inline check; same containment
|
|
2691
|
+
// intent, plus realpath/symlink protection.
|
|
2692
|
+
const resolvedFilepath = safePath$1(toFilepath, getAllowedRoots$1("data"));
|
|
2494
2693
|
|
|
2495
2694
|
const writeStream = fs$a.createWriteStream(resolvedFilepath);
|
|
2496
2695
|
|
|
@@ -2537,10 +2736,21 @@ const dataController$1 = {
|
|
|
2537
2736
|
objectIdKey = null,
|
|
2538
2737
|
) => {
|
|
2539
2738
|
try {
|
|
2739
|
+
let validatedIn, validatedOut;
|
|
2740
|
+
try {
|
|
2741
|
+
const roots = getAllowedRoots$1("data");
|
|
2742
|
+
validatedIn = safePath$1(filepath, roots);
|
|
2743
|
+
validatedOut = safePath$1(outpath, roots);
|
|
2744
|
+
} catch (pathErr) {
|
|
2745
|
+
win.webContents.send(events$5.PARSE_XML_STREAM_ERROR, {
|
|
2746
|
+
error: pathErr.message,
|
|
2747
|
+
});
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2540
2750
|
const t = new Transform();
|
|
2541
2751
|
t.parseXMLStream(
|
|
2542
|
-
|
|
2543
|
-
|
|
2752
|
+
validatedIn,
|
|
2753
|
+
validatedOut,
|
|
2544
2754
|
start,
|
|
2545
2755
|
// recordNode,
|
|
2546
2756
|
// objectIdKey,
|
|
@@ -2586,10 +2796,21 @@ const dataController$1 = {
|
|
|
2586
2796
|
limit = null,
|
|
2587
2797
|
) => {
|
|
2588
2798
|
try {
|
|
2799
|
+
let validatedIn, validatedOut;
|
|
2800
|
+
try {
|
|
2801
|
+
const roots = getAllowedRoots$1("data");
|
|
2802
|
+
validatedIn = safePath$1(filepath, roots);
|
|
2803
|
+
validatedOut = safePath$1(outpath, roots);
|
|
2804
|
+
} catch (pathErr) {
|
|
2805
|
+
win.webContents.send(events$5.PARSE_CSV_STREAM_ERROR, {
|
|
2806
|
+
error: pathErr.message,
|
|
2807
|
+
});
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2589
2810
|
const t = new Transform();
|
|
2590
2811
|
t.parseCSVStream(
|
|
2591
|
-
|
|
2592
|
-
|
|
2812
|
+
validatedIn,
|
|
2813
|
+
validatedOut,
|
|
2593
2814
|
delimiter,
|
|
2594
2815
|
objectIdKey,
|
|
2595
2816
|
headers,
|
|
@@ -2632,13 +2853,25 @@ const dataController$1 = {
|
|
|
2632
2853
|
saveToFile: (win, data, filename, append, returnEmpty = {}) => {
|
|
2633
2854
|
try {
|
|
2634
2855
|
if (data) {
|
|
2635
|
-
// filename
|
|
2636
|
-
|
|
2856
|
+
// Validate filename is contained within the data directory.
|
|
2857
|
+
// path.join doesn't reject `..` segments; safePath does.
|
|
2858
|
+
const candidate = path$f.join(
|
|
2637
2859
|
app$8.getPath("userData"),
|
|
2638
2860
|
appName$5,
|
|
2639
2861
|
"data",
|
|
2640
2862
|
filename,
|
|
2641
2863
|
);
|
|
2864
|
+
let toFilename;
|
|
2865
|
+
try {
|
|
2866
|
+
toFilename = safePath$1(candidate, getAllowedRoots$1("data"));
|
|
2867
|
+
} catch (pathErr) {
|
|
2868
|
+
win.webContents.send(events$5.DATA_SAVE_TO_FILE_ERROR, {
|
|
2869
|
+
success: false,
|
|
2870
|
+
filename,
|
|
2871
|
+
message: pathErr.message,
|
|
2872
|
+
});
|
|
2873
|
+
return;
|
|
2874
|
+
}
|
|
2642
2875
|
|
|
2643
2876
|
//console.log("saving to file ", toFilename);
|
|
2644
2877
|
|
|
@@ -21078,7 +21311,7 @@ function getShellPath$1() {
|
|
|
21078
21311
|
return _shellPath$1;
|
|
21079
21312
|
}
|
|
21080
21313
|
|
|
21081
|
-
const { execSync } = require$$7
|
|
21314
|
+
const { execSync } = require$$7;
|
|
21082
21315
|
const fallbackDirs = ["/usr/local/bin", "/opt/homebrew/bin"];
|
|
21083
21316
|
|
|
21084
21317
|
// Scan nvm versions, tracking both latest and best compatible version
|
|
@@ -21258,7 +21491,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
|
|
|
21258
21491
|
|
|
21259
21492
|
console.log("[mcpController] Refreshing Google OAuth token...");
|
|
21260
21493
|
|
|
21261
|
-
const https = require$$
|
|
21494
|
+
const https = require$$8$1;
|
|
21262
21495
|
const postData = [
|
|
21263
21496
|
`client_id=${encodeURIComponent(keyData.client_id)}`,
|
|
21264
21497
|
`client_secret=${encodeURIComponent(keyData.client_secret)}`,
|
|
@@ -21951,7 +22184,7 @@ const mcpController$3 = {
|
|
|
21951
22184
|
* @returns {{ success } | { error, message }}
|
|
21952
22185
|
*/
|
|
21953
22186
|
runAuth: async (win, mcpConfig, credentials, authCommand) => {
|
|
21954
|
-
const { spawn } = require$$7
|
|
22187
|
+
const { spawn } = require$$7;
|
|
21955
22188
|
|
|
21956
22189
|
const env = cleanEnvForChildProcess();
|
|
21957
22190
|
|
|
@@ -25973,6 +26206,7 @@ const algoliasearch = require$$2$3;
|
|
|
25973
26206
|
const events$3 = events$8;
|
|
25974
26207
|
const AlgoliaIndex = algolia;
|
|
25975
26208
|
var fs$3 = require$$0$2;
|
|
26209
|
+
const { safePath, getAllowedRoots } = safePath_1;
|
|
25976
26210
|
|
|
25977
26211
|
const algoliaController$1 = {
|
|
25978
26212
|
/**
|
|
@@ -26129,10 +26363,19 @@ const algoliaController$1 = {
|
|
|
26129
26363
|
createIfNotExists = false,
|
|
26130
26364
|
) {
|
|
26131
26365
|
try {
|
|
26366
|
+
let validatedDir;
|
|
26367
|
+
try {
|
|
26368
|
+
validatedDir = safePath(dir, getAllowedRoots("data"));
|
|
26369
|
+
} catch (pathErr) {
|
|
26370
|
+
win.webContents.send(events$3.ALGOLIA_PARTIAL_UPDATE_OBJECTS_ERROR, {
|
|
26371
|
+
error: pathErr.message,
|
|
26372
|
+
});
|
|
26373
|
+
return;
|
|
26374
|
+
}
|
|
26132
26375
|
const a = new AlgoliaIndex(appId, apiKey, indexName);
|
|
26133
26376
|
// now we can make the call to the utility and we are passing in the createIfNotExists FALSE by default
|
|
26134
26377
|
a.partialUpdateObjectsFromDirectorySync(
|
|
26135
|
-
|
|
26378
|
+
validatedDir,
|
|
26136
26379
|
createIfNotExists,
|
|
26137
26380
|
(data) => {
|
|
26138
26381
|
win.webContents.send(
|
|
@@ -26172,10 +26415,21 @@ const algoliaController$1 = {
|
|
|
26172
26415
|
batchSize = 500,
|
|
26173
26416
|
) => {
|
|
26174
26417
|
try {
|
|
26418
|
+
let validatedIn, validatedOut;
|
|
26419
|
+
try {
|
|
26420
|
+
const roots = getAllowedRoots("data");
|
|
26421
|
+
validatedIn = safePath(filepath, roots);
|
|
26422
|
+
validatedOut = safePath(batchFilepath, roots);
|
|
26423
|
+
} catch (pathErr) {
|
|
26424
|
+
win.webContents.send(events$3.ALGOLIA_CREATE_BATCH_ERROR, {
|
|
26425
|
+
error: pathErr.message,
|
|
26426
|
+
});
|
|
26427
|
+
return;
|
|
26428
|
+
}
|
|
26175
26429
|
const a = new AlgoliaIndex();
|
|
26176
26430
|
a.createBatchesFromJSONFile(
|
|
26177
|
-
|
|
26178
|
-
|
|
26431
|
+
validatedIn,
|
|
26432
|
+
validatedOut,
|
|
26179
26433
|
batchSize,
|
|
26180
26434
|
(data) => {
|
|
26181
26435
|
win.webContents.send(events$3.ALGOLIA_CREATE_BATCH_UPDATE, data);
|
|
@@ -43641,7 +43895,7 @@ const completable_js_1 = completable;
|
|
|
43641
43895
|
const uriTemplate_js_1 = uriTemplate;
|
|
43642
43896
|
const toolNameValidation_js_1 = toolNameValidation;
|
|
43643
43897
|
const mcp_server_js_1 = mcpServer$1;
|
|
43644
|
-
const zod_1 = require$$8$
|
|
43898
|
+
const zod_1 = require$$8$2;
|
|
43645
43899
|
/**
|
|
43646
43900
|
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
|
|
43647
43901
|
* For advanced usage (like sending notifications or setting custom request handlers), use the underlying
|
|
@@ -46274,7 +46528,7 @@ var tlsCert = { getOrCreateCert: getOrCreateCert$1 };
|
|
|
46274
46528
|
* for Zod schemas in tool input validation (safeParseAsync).
|
|
46275
46529
|
*/
|
|
46276
46530
|
|
|
46277
|
-
const z$1 = require$$8$
|
|
46531
|
+
const z$1 = require$$8$2;
|
|
46278
46532
|
|
|
46279
46533
|
/**
|
|
46280
46534
|
* Convert a JSON Schema property definition to a Zod v3 schema.
|
|
@@ -46367,7 +46621,7 @@ var jsonSchemaToZod_1 = { jsonSchemaToZod: jsonSchemaToZod$1, jsonSchemaProperty
|
|
|
46367
46621
|
* - Rate limiting via token bucket (60 req/min)
|
|
46368
46622
|
*/
|
|
46369
46623
|
|
|
46370
|
-
const https$1 = require$$
|
|
46624
|
+
const https$1 = require$$8$1;
|
|
46371
46625
|
const { randomUUID } = require$$3$4;
|
|
46372
46626
|
const { BrowserWindow: BrowserWindow$1 } = require$$0$1;
|
|
46373
46627
|
const { McpServer } = mcp;
|
|
@@ -46498,7 +46752,7 @@ function registerPrompt$1(promptDef) {
|
|
|
46498
46752
|
registeredPrompts.push(promptDef);
|
|
46499
46753
|
}
|
|
46500
46754
|
|
|
46501
|
-
const z = require$$8$
|
|
46755
|
+
const z = require$$8$2;
|
|
46502
46756
|
const { jsonSchemaToZod } = jsonSchemaToZod_1;
|
|
46503
46757
|
|
|
46504
46758
|
/**
|
|
@@ -46879,7 +47133,7 @@ var mcpDashServerController_1 = mcpDashServerController$4;
|
|
|
46879
47133
|
* can use the Chat widget without a separate API key.
|
|
46880
47134
|
*/
|
|
46881
47135
|
|
|
46882
|
-
const { spawn, execSync } = require$$7
|
|
47136
|
+
const { spawn, execSync } = require$$7;
|
|
46883
47137
|
const {
|
|
46884
47138
|
LLM_STREAM_DELTA: LLM_STREAM_DELTA$2,
|
|
46885
47139
|
LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$2,
|
|
@@ -48176,7 +48430,7 @@ var themeFromUrlErrors$1 = {
|
|
|
48176
48430
|
|
|
48177
48431
|
const css = require$$0$8;
|
|
48178
48432
|
const { Vibrant } = require$$1$7;
|
|
48179
|
-
const https = require$$
|
|
48433
|
+
const https = require$$8$1;
|
|
48180
48434
|
const http = require$$0$7;
|
|
48181
48435
|
const { URL: URL$1 } = require$$4$1;
|
|
48182
48436
|
const {
|