Skip to content

Commit

Permalink
Introduce moonlightNodeSandboxed
Browse files Browse the repository at this point in the history
  • Loading branch information
NotNite committed Oct 14, 2024
1 parent 04fda32 commit dbdd48d
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 123 deletions.
123 changes: 64 additions & 59 deletions packages/browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,68 +26,73 @@ window._moonlightBrowserInit = async () => {
}
});

window.moonlightFS = {
async readFile(path) {
return new Uint8Array(await fs.readFile(path));
},
async readFileString(path) {
const file = await this.readFile(path);
return new TextDecoder().decode(file);
},
async writeFile(path, data) {
await fs.writeFile(path, data);
},
async writeFileString(path, data) {
const file = new TextEncoder().encode(data);
await this.writeFile(path, file);
},
async unlink(path) {
await fs.unlink(path);
},

async readdir(path) {
return await fs.readdir(path);
},
async mkdir(path) {
const parts = getParts(path);
for (let i = 0; i < parts.length; i++) {
const path = this.join(...parts.slice(0, i + 1));
if (!(await this.exists(path))) await fs.mkdir(path);
}
},

async rmdir(path) {
const entries = await this.readdir(path);

for (const entry of entries) {
const fullPath = this.join(path, entry);
const isFile = await this.isFile(fullPath);
if (isFile) {
await this.unlink(fullPath);
} else {
await this.rmdir(fullPath);
window.moonlightNodeSandboxed = {
fs: {
async readFile(path) {
return new Uint8Array(await fs.readFile(path));
},
async readFileString(path) {
const file = await this.readFile(path);
return new TextDecoder().decode(file);
},
async writeFile(path, data) {
await fs.writeFile(path, data);
},
async writeFileString(path, data) {
const file = new TextEncoder().encode(data);
await this.writeFile(path, file);
},
async unlink(path) {
await fs.unlink(path);
},

async readdir(path) {
return await fs.readdir(path);
},
async mkdir(path) {
const parts = getParts(path);
for (let i = 0; i < parts.length; i++) {
const path = this.join(...parts.slice(0, i + 1));
if (!(await this.exists(path))) await fs.mkdir(path);
}
},

async rmdir(path) {
const entries = await this.readdir(path);

for (const entry of entries) {
const fullPath = this.join(path, entry);
const isFile = await this.isFile(fullPath);
if (isFile) {
await this.unlink(fullPath);
} else {
await this.rmdir(fullPath);
}
}
}

await fs.rmdir(path);
},

async exists(path) {
return await fs.exists(path);
},
async isFile(path) {
return (await fs.stat(path)).isFile();
},

join(...parts) {
let str = parts.join("/");
if (!str.startsWith("/")) str = "/" + str;
return str;
await fs.rmdir(path);
},

async exists(path) {
return await fs.exists(path);
},
async isFile(path) {
return (await fs.stat(path)).isFile();
},

join(...parts) {
let str = parts.join("/");
if (!str.startsWith("/")) str = "/" + str;
return str;
},
dirname(path) {
const parts = getParts(path);
return "/" + parts.slice(0, parts.length - 1).join("/");
}
},
dirname(path) {
const parts = getParts(path);
return "/" + parts.slice(0, parts.length - 1).join("/");
}
// TODO
addCors(url) {},
addBlocked(url) {}
};

// Actual loading begins here
Expand Down
34 changes: 17 additions & 17 deletions packages/core-extensions/src/moonbase/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ export default function getNatives(): MoonbaseNatives {

if (!tar || !ref) return;

const dist = moonlightFS.join(moonlightNode.getMoonlightDir(), distDir);
if (await moonlightFS.exists(dist)) await moonlightFS.rmdir(dist);
await moonlightFS.mkdir(dist);
const dist = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), distDir);
if (await moonlightNodeSandboxed.fs.exists(dist)) await moonlightNodeSandboxed.fs.rmdir(dist);
await moonlightNodeSandboxed.fs.mkdir(dist);

logger.debug("Extracting update");
const files = await parseTarGzip(tar);
Expand All @@ -115,15 +115,15 @@ export default function getNatives(): MoonbaseNatives {
// @ts-expect-error What do you mean their own types are wrong
if (file.type !== "file") continue;

const fullFile = moonlightFS.join(dist, file.name);
const fullDir = moonlightFS.dirname(fullFile);
if (!(await moonlightFS.exists(fullDir))) await moonlightFS.mkdir(fullDir);
await moonlightFS.writeFile(fullFile, file.data);
const fullFile = moonlightNodeSandboxed.fs.join(dist, file.name);
const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile);
if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir);
await moonlightNodeSandboxed.fs.writeFile(fullFile, file.data);
}

logger.debug("Writing version file:", ref);
const versionFile = moonlightFS.join(moonlightNode.getMoonlightDir(), installedVersionFile);
await moonlightFS.writeFileString(versionFile, ref.trim());
const versionFile = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), installedVersionFile);
await moonlightNodeSandboxed.fs.writeFileString(versionFile, ref.trim());

logger.debug("Update extracted");
},
Expand Down Expand Up @@ -159,25 +159,25 @@ export default function getNatives(): MoonbaseNatives {

const dir = moonlightNode.getExtensionDir(manifest.id);
// remake it in case of updates
if (await moonlightFS.exists(dir)) await moonlightFS.rmdir(dir);
await moonlightFS.mkdir(dir);
if (await moonlightNodeSandboxed.fs.exists(dir)) await moonlightNodeSandboxed.fs.rmdir(dir);
await moonlightNodeSandboxed.fs.mkdir(dir);

const buffer = await req.arrayBuffer();
const files = extractAsar(buffer);
for (const [file, buf] of Object.entries(files)) {
const fullFile = moonlightFS.join(dir, file);
const fullDir = moonlightFS.dirname(fullFile);
const fullFile = moonlightNodeSandboxed.fs.join(dir, file);
const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile);

if (!(await moonlightFS.exists(fullDir))) await moonlightFS.mkdir(fullDir);
await moonlightFS.writeFile(moonlightFS.join(dir, file), buf);
if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir);
await moonlightNodeSandboxed.fs.writeFile(moonlightNodeSandboxed.fs.join(dir, file), buf);
}

await moonlightFS.writeFileString(moonlightFS.join(dir, repoUrlFile), repo);
await moonlightNodeSandboxed.fs.writeFileString(moonlightNodeSandboxed.fs.join(dir, repoUrlFile), repo);
},

async deleteExtension(id) {
const dir = moonlightNode.getExtensionDir(id);
await moonlightFS.rmdir(dir);
await moonlightNodeSandboxed.fs.rmdir(dir);
},

getExtensionConfig(id, key) {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const defaultConfig: Config = {
export async function writeConfig(config: Config) {
try {
const configPath = await getConfigPath();
await moonlightFS.writeFileString(configPath, JSON.stringify(config, null, 2));
await moonlightNodeSandboxed.fs.writeFileString(configPath, JSON.stringify(config, null, 2));
} catch (e) {
logger.error("Failed to write config", e);
}
Expand All @@ -30,12 +30,12 @@ export async function readConfig(): Promise<Config> {
}

const configPath = await getConfigPath();
if (!(await moonlightFS.exists(configPath))) {
if (!(await moonlightNodeSandboxed.fs.exists(configPath))) {
await writeConfig(defaultConfig);
return defaultConfig;
} else {
try {
let config: Config = JSON.parse(await moonlightFS.readFileString(configPath));
let config: Config = JSON.parse(await moonlightNodeSandboxed.fs.readFileString(configPath));
// Assign the default values if they don't exist (newly added)
config = { ...defaultConfig, ...config };
await writeConfig(config);
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const cors: string[] = [];
const blocked: string[] = [];

export function registerCors(url: string) {
cors.push(url);
}

export function registerBlocked(url: string) {
blocked.push(url);
}

export function getDynamicCors() {
return {
cors,
blocked
};
}
58 changes: 33 additions & 25 deletions packages/core/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ const logger = new Logger("core/extension");
async function findManifests(dir: string): Promise<string[]> {
const ret = [];

if (await moonlightFS.exists(dir)) {
for (const file of await moonlightFS.readdir(dir)) {
const path = moonlightFS.join(dir, file);
if (await moonlightNodeSandboxed.fs.exists(dir)) {
for (const file of await moonlightNodeSandboxed.fs.readdir(dir)) {
const path = moonlightNodeSandboxed.fs.join(dir, file);
if (file === "manifest.json") {
ret.push(path);
}

if (!(await moonlightFS.isFile(path))) {
if (!(await moonlightNodeSandboxed.fs.isFile(path))) {
ret.push(...(await findManifests(path)));
}
}
Expand All @@ -34,48 +34,54 @@ async function loadDetectedExtensions(
const manifests = await findManifests(dir);
for (const manifestPath of manifests) {
try {
if (!(await moonlightFS.exists(manifestPath))) continue;
const dir = moonlightFS.dirname(manifestPath);
if (!(await moonlightNodeSandboxed.fs.exists(manifestPath))) continue;
const dir = moonlightNodeSandboxed.fs.dirname(manifestPath);

const manifest: ExtensionManifest = JSON.parse(await moonlightFS.readFileString(manifestPath));
const manifest: ExtensionManifest = JSON.parse(await moonlightNodeSandboxed.fs.readFileString(manifestPath));
if (seen.has(manifest.id)) {
logger.warn(`Duplicate extension found, skipping: ${manifest.id}`);
continue;
}
seen.add(manifest.id);

const webPath = moonlightFS.join(dir, "index.js");
const nodePath = moonlightFS.join(dir, "node.js");
const hostPath = moonlightFS.join(dir, "host.js");
const webPath = moonlightNodeSandboxed.fs.join(dir, "index.js");
const nodePath = moonlightNodeSandboxed.fs.join(dir, "node.js");
const hostPath = moonlightNodeSandboxed.fs.join(dir, "host.js");

// if none exist (empty manifest) don't give a shit
if (!moonlightFS.exists(webPath) && !moonlightFS.exists(nodePath) && !moonlightFS.exists(hostPath)) {
if (
!moonlightNodeSandboxed.fs.exists(webPath) &&
!moonlightNodeSandboxed.fs.exists(nodePath) &&
!moonlightNodeSandboxed.fs.exists(hostPath)
) {
continue;
}

const web = (await moonlightFS.exists(webPath)) ? await moonlightFS.readFileString(webPath) : undefined;
const web = (await moonlightNodeSandboxed.fs.exists(webPath))
? await moonlightNodeSandboxed.fs.readFileString(webPath)
: undefined;

let url: string | undefined = undefined;
const urlPath = moonlightFS.join(dir, constants.repoUrlFile);
if (type === ExtensionLoadSource.Normal && (await moonlightFS.exists(urlPath))) {
url = await moonlightFS.readFileString(urlPath);
const urlPath = moonlightNodeSandboxed.fs.join(dir, constants.repoUrlFile);
if (type === ExtensionLoadSource.Normal && (await moonlightNodeSandboxed.fs.exists(urlPath))) {
url = await moonlightNodeSandboxed.fs.readFileString(urlPath);
}

const wpModules: Record<string, string> = {};
const wpModulesPath = moonlightFS.join(dir, "webpackModules");
if (await moonlightFS.exists(wpModulesPath)) {
const wpModulesFile = await moonlightFS.readdir(wpModulesPath);
const wpModulesPath = moonlightNodeSandboxed.fs.join(dir, "webpackModules");
if (await moonlightNodeSandboxed.fs.exists(wpModulesPath)) {
const wpModulesFile = await moonlightNodeSandboxed.fs.readdir(wpModulesPath);

for (const wpModuleFile of wpModulesFile) {
if (wpModuleFile.endsWith(".js")) {
wpModules[wpModuleFile.replace(".js", "")] = await moonlightFS.readFileString(
moonlightFS.join(wpModulesPath, wpModuleFile)
wpModules[wpModuleFile.replace(".js", "")] = await moonlightNodeSandboxed.fs.readFileString(
moonlightNodeSandboxed.fs.join(wpModulesPath, wpModuleFile)
);
}
}
}

const stylePath = moonlightFS.join(dir, "style.css");
const stylePath = moonlightNodeSandboxed.fs.join(dir, "style.css");

ret.push({
id: manifest.id,
Expand All @@ -88,9 +94,11 @@ async function loadDetectedExtensions(
web,
webPath: web != null ? webPath : undefined,
webpackModules: wpModules,
nodePath: (await moonlightFS.exists(nodePath)) ? nodePath : undefined,
hostPath: (await moonlightFS.exists(hostPath)) ? hostPath : undefined,
style: (await moonlightFS.exists(stylePath)) ? await moonlightFS.readFileString(stylePath) : undefined
nodePath: (await moonlightNodeSandboxed.fs.exists(nodePath)) ? nodePath : undefined,
hostPath: (await moonlightNodeSandboxed.fs.exists(hostPath)) ? hostPath : undefined,
style: (await moonlightNodeSandboxed.fs.exists(stylePath))
? await moonlightNodeSandboxed.fs.readFileString(stylePath)
: undefined
}
});
} catch (e) {
Expand Down Expand Up @@ -155,7 +163,7 @@ async function getExtensionsBrowser(): Promise<DetectedExtension[]> {
seen.add(manifest.id);
}

if (await moonlightFS.exists("/extensions")) {
if (await moonlightNodeSandboxed.fs.exists("/extensions")) {
ret.push(...(await loadDetectedExtensions("/extensions", ExtensionLoadSource.Normal, seen)));
}

Expand Down
Loading

0 comments on commit dbdd48d

Please sign in to comment.