Skip to content

Commit

Permalink
WIP: Sandbox implementation.
Browse files Browse the repository at this point in the history
Current state:
- I'm able to send messages to the sandbox.
- The sandbox is able to render the Handlebars content.
- *The sandbox cannot send messages back to the caller!*

I don't understand why this isn't working given that I'm following the
doc here:
https://developer.chrome.com/docs/extensions/mv2/sandboxingEval/; when I
attempt to send a message to the source of my message, the source is the
sandboxed frame.  This is obviously not going to work given that I want
to send the message to the parent frame instead (& unforch, you can't
access `window.parent` either).

Definitely perplexed and I've already spent enough time on this today.
  • Loading branch information
coddingtonbear committed Feb 16, 2022
1 parent 216a760 commit 5bd2480
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 24 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
],
"editor.formatOnSave": true,
"html.autoClosingTags": false,
"typescript.autoClosingTags": false
"typescript.autoClosingTags": false,
"files.exclude": {
"dist/**": true
}
}
79 changes: 68 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.3.1",
"@mui/material": "^5.4.0",
"micromustache": "^8.0.3",
"handlebars": "^4.7.7",
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
Expand Down
13 changes: 13 additions & 0 deletions public/handlebars.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Obsidian Handlebars Sandbox</title>
<script src="js/vendor.js"></script>
</head>

<body class="options">
<script src="js/handlebars.js"></script>
<div id="debug">
</div>
</body>
</html>
4 changes: 4 additions & 0 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

"options_page": "options.html",

"sandbox": {
"pages": ["handlebars.html"]
},

"icons": {
"16": "icon16.png",
"48": "icon48.png",
Expand Down
1 change: 1 addition & 0 deletions public/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<body class="options">
<div id="root"></div>
<iframe id="handlebars-sandbox" src="handlebars.html"></iframe>
<script src="js/options.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions public/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</head>
<body class="popup">
<div id="root"></div>
<iframe id="handlebars-sandbox" src="handlebars.html"></iframe>
<script src="js/popup.js"></script>
</body>
</html>
Expand Down
57 changes: 57 additions & 0 deletions src/handlebars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Handlebars from "handlebars";
import {
SandboxRequest,
SandboxRenderResponse,
SandboxRenderRequest,
} from "./types";

const render = (request: SandboxRenderRequest): SandboxRenderResponse => {
const compiled = Handlebars.compile(request.template);

return {
success: true,
request,
rendered: compiled(request.context),
};
};

function handleEvent(evt: MessageEvent<SandboxRequest>): void {
if (evt.origin === "null") {
console.log("Received event from self :-(", evt);
return;
}
console.log("Parent: ", window.parent);
console.log("Received event: ", evt);

const command = evt.data.command;
const postMessage = (evt.source as WindowProxy).postMessage;
console.log("Received event (Src): ", evt.source);

const debug = document.getElementById("debug");
if (debug) {
debug.innerHTML = JSON.stringify(evt.data);
}

try {
switch (command) {
case "render":
postMessage(render(evt.data), "*");
break;
default:
return;
throw new Error(`Unexpected command: ${command}`);
}
} catch (e) {
console.error(e);
postMessage(
{
success: false,
request: evt.data,
message: (e as Error).message,
},
"*"
);
}
}

window.addEventListener("message", handleEvent);
10 changes: 4 additions & 6 deletions src/options.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react";
import { compile } from "micromustache";
import ReactDOM from "react-dom";

import ThemeProvider from "@mui/system/ThemeProvider";
Expand Down Expand Up @@ -34,7 +33,7 @@ import {
DefaultUrlTemplate,
} from "./constants";
import { ExtensionSettings, OutputPreset, AlertStatus } from "./types";
import { getSettings, obsidianRequest } from "./utils";
import { getSettings, obsidianRequest, compile } from "./utils";
import Alert from "./components/Alert";
import RequestParameters from "./components/RequestParameters";
import { PurpleTheme } from "./theme";
Expand Down Expand Up @@ -112,7 +111,6 @@ const Options = () => {
// stored in chrome.storage.
async function handle() {
const settings = await getSettings(chrome.storage.sync);
console.log(settings);

setApiKey(settings.apiKey);
setPresets(settings.presets);
Expand Down Expand Up @@ -167,22 +165,22 @@ const Options = () => {
setPresets(newPresets);
};

const savePreset = () => {
const savePreset = async () => {
if (editingPreset === undefined) {
return;
}

let errorMessage: string | undefined = undefined;

try {
compile(contentTemplate);
await compile(contentTemplate, {});
} catch (e) {
errorMessage = "Could not compile content template.";
}

if (!errorMessage) {
try {
compile(urlTemplate);
await compile(urlTemplate, {});
} catch (e) {
errorMessage = "Could not compile url template.";
}
Expand Down
10 changes: 6 additions & 4 deletions src/popup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { compile } from "micromustache";
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import Button from "@mui/material/Button";
Expand All @@ -15,7 +14,7 @@ import MaterialAlert from "@mui/material/Alert";

import Alert from "./components/Alert";
import { AlertStatus, ExtensionSettings, OutputPreset } from "./types";
import { getSettings, obsidianRequest } from "./utils";
import { getSettings, obsidianRequest, compile } from "./utils";
import RequestParameters from "./components/RequestParameters";

const Popup = () => {
Expand Down Expand Up @@ -88,12 +87,15 @@ const Popup = () => {
},
};

const compiledUrl = await compile(preset.urlTemplate, context);
const compiledContent = await compile(preset.contentTemplate, context);

setApiKey(items.apiKey);
setInsecureMode(items.insecureMode ?? false);
setMethod(preset.method as OutputPreset["method"]);
setCompiledUrl(compile(preset.urlTemplate).render(context));
setCompiledUrl(compiledUrl);
setHeaders(preset.headers);
setCompiledContent(compile(preset.contentTemplate).render(context));
setCompiledContent(compiledContent);
setReady(true);
}

Expand Down
29 changes: 29 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,32 @@ export interface AlertStatus {
title: string;
message: string;
}

export interface SandboxRenderRequest {
command: "render";
template: string;
context: Record<string, any>;
}

export type SandboxRequest = SandboxRenderRequest;

export interface SandboxResponseBase {
request: SandboxRequest;
success: boolean;
}

export interface SandboxExceptionResponse extends SandboxResponseBase {
success: false;
message: string;
}

export interface SandboxSuccessResponse extends SandboxResponseBase {
success: true;
}

export interface SandboxRenderResponse extends SandboxSuccessResponse {
request: SandboxRenderRequest;
rendered: string;
}

export type SandboxResponse = SandboxRenderResponse | SandboxExceptionResponse;
Loading

0 comments on commit 5bd2480

Please sign in to comment.