@geml/logseq-sync 2.0.3 → 2.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geml/logseq-sync",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -135,7 +135,9 @@ for (let i = 0; i < args.length; i++) {
135
135
  } else if (arg === "--api-server-token") {
136
136
  needValue(i, "--api-server-token");
137
137
  flags.apiServerToken = args[++i];
138
- } else if (arg.startsWith("--")) {
138
+ } else if (arg.startsWith("-")) {
139
+ // One dash included: "-graph demo" once sailed through as a graph literally
140
+ // named "-graph" and a vault named "demo" — a typo must stop, not sync.
139
141
  console.error(`Error: Unknown flag "${arg}". Run \`logseq-sync --help\` for usage.`);
140
142
  process.exit(2);
141
143
  } else if (subcommand === null && positional.length === 0 && (arg === "doctor" || arg === "restore")) {
@@ -278,13 +280,13 @@ function resolveGraphOrExit() {
278
280
  if (detected?.candidates) {
279
281
  console.error(
280
282
  `Error: several graphs and none open in the app — ${detected.candidates.join(", ")}. ` +
281
- `Pick one with --graph <name>.`
283
+ `Pick one with --graph <name>. Run \`logseq-sync doctor\` for the full picture.`
282
284
  );
283
285
  process.exit(2);
284
286
  }
285
287
  console.error(
286
288
  `Error: no Logseq graphs found under ${join(logseqRootDir(probe), "graphs")}. ` +
287
- `Open a graph in Logseq first, or name one with --graph <name>.`
289
+ `Open a graph in Logseq first. Run \`logseq-sync doctor\` for the full picture.`
288
290
  );
289
291
  process.exit(2);
290
292
  }
@@ -293,7 +295,8 @@ function resolveVaultOrExit() {
293
295
  if (vaultRaw) return resolve(expandHome(vaultRaw));
294
296
  console.error(
295
297
  `Error: no vault directory. Set it in Logseq — Settings → Plugins → ${PLUGIN_TITLE} → ` +
296
- `"Vault folder" — or pass one: logseq-sync <vault-dir>.`
298
+ `"Vault folder" — or pass one: logseq-sync <vault-dir>. ` +
299
+ `Run \`logseq-sync doctor\` for the full picture.`
297
300
  );
298
301
  process.exit(2);
299
302
  }
@@ -395,20 +398,34 @@ if (subcommand === "doctor") doctor();
395
398
  graphName = resolveGraphOrExit();
396
399
 
397
400
  // Validate graph name to prevent command/path injection
398
- if (!/^[a-zA-Z0-9_.-]+$/.test(graphName)) {
401
+ // The first character must not be a dash or a dot: the name travels as argv
402
+ // into the exporting CLI, where a leading dash reads as a flag ("-graph"
403
+ // arrived here as a real user typo for --graph), and "." / ".." read as paths.
404
+ if (!/^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/.test(graphName)) {
399
405
  console.error(`Error: Invalid graph name "${graphName}". Only alphanumeric characters, hyphens, and underscores are allowed.`);
400
406
  process.exit(2);
401
407
  }
402
408
 
403
409
  // `logseq graph export --graph <name>` does not fail on an unknown name — it
404
410
  // CREATES that graph and exports the empty result. A typo would then sync
405
- // emptiness over the vault and commit it. Refuse names we cannot see on disk.
406
- // An unreadable graphs directory yields an empty list; that is "I do not know",
407
- // not "it is missing", so the check only fires when we did find graphs.
408
- if (knownGraphs.length > 0 && !knownGraphs.includes(graphName)) {
411
+ // emptiness over the vault and commit it. Refuse names we cannot see,
412
+ // INCLUDING when we see none at all: a bare run calls zero graphs a hard
413
+ // error, and naming one does not make graphs exist treating the same state
414
+ // as "cannot verify, proceed" is how `--graph demo` once sailed past this
415
+ // check straight into the vault error, and reads as a contradiction. The
416
+ // escape hatches are real, not hypothetical: LOGSEQ_ROOT_DIR when the graphs
417
+ // live elsewhere, and the API-server route, which exports whatever graph the
418
+ // app has open and ignores local directories entirely.
419
+ if (!apiServerToken && !knownGraphs.includes(graphName)) {
409
420
  console.error(
410
- `Error: no graph named "${graphName}" — found ${knownGraphs.join(", ")}. ` +
411
- `(The app CLI would silently create "${graphName}" rather than fail.)`
421
+ knownGraphs.length > 0
422
+ ? `Error: no graph named "${graphName}" found ${knownGraphs.join(", ")}. ` +
423
+ `(The app CLI would silently create "${graphName}" rather than fail.) ` +
424
+ `Run \`logseq-sync doctor\` for the full picture.`
425
+ : `Error: no graph named "${graphName}" — no graphs found under ` +
426
+ `${join(logseqRootDir(probe), "graphs")} at all, and the app CLI would silently ` +
427
+ `create "${graphName}" and sync emptiness. If your graphs live elsewhere, set ` +
428
+ `LOGSEQ_ROOT_DIR. Run \`logseq-sync doctor\` for the full picture.`
412
429
  );
413
430
  process.exit(2);
414
431
  }
@@ -476,9 +493,19 @@ function runLogseqCli(...cmdArgs) {
476
493
  });
477
494
  }
478
495
 
479
- // Fallback to npx (executable npx.cmd on Windows, npx on Unix) without shell: true
480
- const npxCmd = process.platform === "win32" ? "npx.cmd" : "npx";
481
- return execFileSync(npxCmd, ["-y", "@logseq/cli", ...cmdArgs], {
496
+ // On Windows the npx fallback is an instruction, not a spawn: Node refuses
497
+ // to run a .cmd without a shell (CVE-2024-27980), and routing a user-typed
498
+ // graph name through cmd.exe to get around that is how injection happens.
499
+ // Every prior attempt died as `spawnSync npx.cmd EINVAL`, once every poll.
500
+ if (process.platform === "win32") {
501
+ throw new Error(
502
+ "@logseq/cli is not installed where I can see it. Install it once\n" +
503
+ " (mkdir logseq-cli && cd logseq-cli && npm init -y && npm i @logseq/cli)\n" +
504
+ "and point LOGSEQ_CLI_DIR at that directory — or pass --app-cli <path>\n" +
505
+ "to the desktop app's CLI."
506
+ );
507
+ }
508
+ return execFileSync("npx", ["-y", "@logseq/cli", ...cmdArgs], {
482
509
  cwd: cliCwd,
483
510
  encoding: "utf8",
484
511
  shell: false,