Skip to content

Commit

Permalink
chore: add a trust project for live preview in phoenix iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
abose committed Jan 6, 2024
1 parent 945cfd6 commit 2505ece
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 2 deletions.
46 changes: 45 additions & 1 deletion src/extensions/default/Phoenix-live-preview/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,13 @@ define(function (require, exports, module) {
LiveDevelopment = brackets.getModule("LiveDevelopment/main"),
LiveDevServerManager = brackets.getModule("LiveDevelopment/LiveDevServerManager"),
NativeApp = brackets.getModule("utils/NativeApp"),
FileUtils = brackets.getModule("file/FileUtils"),
StaticServer = require("StaticServer"),
utils = require('utils');

const PREVIEW_TRUSTED_PROJECT_KEY = "preview_trusted";
const moduleDir = FileUtils.getNativeModuleDirectoryPath(module);

const LIVE_PREVIEW_PANEL_ID = "live-preview-panel",
IFRAME_EVENT_SERVER_READY = 'SERVER_READY';
let serverReady = false;
Expand All @@ -70,6 +74,42 @@ define(function (require, exports, module) {
</iframe>
`;

function _getTrustProjectPage() {
return `${moduleDir}/trust-project.html?`
+`&localMessage=${encodeURIComponent(Strings.DESCRIPTION_LIVEDEV_SECURITY_TRUST_MESSAGE)}`
+`&initialProjectRoot=${encodeURIComponent(ProjectManager.getProjectRoot().fullPath)}`
+`&okMessage=${encodeURIComponent(Strings.TRUST_PROJECT)}`;
}

function _isProjectPreviewTrusted() {
// In desktop builds, each project is securely sandboxed in its own live preview server:port domain.
// This setup ensures security within the browser sandbox, eliminating the need for a trust
// confirmation dialog. We can display the live preview immediately.
if(Phoenix.browser.isTauri || Phoenix.isTestWindow){ // for test windows, we trust all test files
return true;
}
// In browsers, since all live previews for all projects uses the same phcode.live domain,
// untrusted projects can access data of past opened projects. So we have to show a trust project?
// dialog in live preview in browser.
// Future plans for browser versions include adopting a similar approach to dynamically generate
// URLs in the format `project-name.phcode.live`. This will streamline the workflow by removing
// the current reliance on users to manually verify and trust each project in the browser.
const projectPath = ProjectManager.getProjectRoot().fullPath;
if(projectPath === ProjectManager.getWelcomeProjectPath() ||
projectPath === ProjectManager.getExploreProjectPath()){
return true;
}
const isTrustedProject = `${PREVIEW_TRUSTED_PROJECT_KEY}-${projectPath}`;
return !!PhStore.getItem(isTrustedProject);
}

window._trustCurrentProjectForLivePreview = function () {
const projectPath = ProjectManager.getProjectRoot().fullPath;
const isTrustedProjectKey = `${PREVIEW_TRUSTED_PROJECT_KEY}-${projectPath}`;
PhStore.setItem(isTrustedProjectKey, true);
_loadPreview(true);
};

ExtensionInterface.registerExtensionInterface(
ExtensionInterface._DEFAULT_EXTENSIONS_INTERFACE_NAMES.PHOENIX_LIVE_PREVIEW, exports);

Expand Down Expand Up @@ -265,7 +305,11 @@ define(function (require, exports, module) {
newIframe.insertAfter($iframe);
$iframe.remove();
$iframe = newIframe;
$iframe.attr('src', newSrc);
if(_isProjectPreviewTrusted()){
$iframe.attr('src', newSrc);
} else {
$iframe.attr('src', _getTrustProjectPage());
}
}
Metrics.countEvent(Metrics.EVENT_TYPE.LIVE_PREVIEW, "render",
utils.getExtension(previewDetails.fullPath));
Expand Down
140 changes: 140 additions & 0 deletions src/extensions/default/Phoenix-live-preview/trust-project.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Phoenix Live Preview Loader...</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
iframe {
width: 100%;
height: 100%;
border: none; /* Removes the default border around an iframe */
}
</style>
<style>

.outer-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}

.dialog-container {
border: 1px solid #ccc;
background-color: #fff;
padding: 20px;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
/* Other styles remain the same */
}

.dialog-title {
font-size: 1.2em;
margin-bottom: 10px;
}

.dialog-message {
margin-bottom: 20px;
}

.dialog-buttons {
text-align: right;
}

button {
padding: 5px 10px;
margin-left: 10px;
background-color: #eee; /* Light background for buttons */
color: #000; /* Dark text for buttons */
border: 1px solid #ccc; /* Border for buttons */
}

/* Dark theme styles */
@media (prefers-color-scheme: dark) {

.outer-container {
background-color: #1e1e1e; /* Dark background for the body */
color: #ffffff; /* Light text color for dark theme */
}

.dialog-container {
border: 1px solid #444; /* Darker border for the dialog */
background-color: #2a2a2a; /* Dark background for the dialog */
}

button {
background-color: #4a4a4a; /* Darker background for buttons */
color: #fff; /* Light text for buttons */
border: 1px solid #6a6a6a; /* Border for buttons */
}

button:hover {
background-color: #5a5a5a; /* Lighter background on hover for buttons */
}
}

</style>
<script>
let okMessageTemplate;
let currentProjectRoot;

function getTrustOkButton() {
if(! okMessageTemplate){
return "Trust Project?";
}
if(!currentProjectRoot){
return okMessageTemplate.replace("{0}", "");
}
let projectName = currentProjectRoot;
if(projectName.endsWith("/")){
projectName = projectName.slice(0, -1);
}
projectName = projectName.split("/");
projectName = projectName[projectName.length-1];
return okMessageTemplate.replace("{0}", projectName);
}

function navigateToInitialURL() {
const queryParams = new URLSearchParams(window.location.search);
const localiseMessage = queryParams.get('localMessage');
okMessageTemplate = decodeURIComponent(queryParams.get('okMessage'));
currentProjectRoot = queryParams.get('initialProjectRoot');

if(!okMessageTemplate || !currentProjectRoot){
console.error("Expected required query strings: okMessageTemplate, currentProjectRoot");
return;
}

document.getElementById('okButton').textContent = getTrustOkButton();
localiseMessage && (document.getElementById('dialog-message').textContent = decodeURIComponent(localiseMessage));
document.getElementById('okButton').addEventListener('click', function() {
window.parent._trustCurrentProjectForLivePreview();
});
}

</script>
</head>
<body onload="navigateToInitialURL()">
<div id="outer-container" class="outer-container">
<div id='dialog-container' class="dialog-container">
<div class="dialog-title">Phoenix Code Live Preview</div>
<div id="dialog-message" class="dialog-message">
You are about to open an HTML file for live preview. Please proceed only if you trust the source of this project. Click 'OK' to continue, or close this window if you do not trust the source.
</div>
<div class="dialog-buttons">
<button id="okButton">Trust Project</button>
</div>
</div>
</div>
</body>
</html>
1 change: 1 addition & 0 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,7 @@ define({
"DESCRIPTION_LIVEDEV_MAIN_SPAN": "Get the best live preview experience by downloading our native apps for Windows, Mac, and Linux from <a href=\"https://phcode.io\" style=\"color: white\">phcode.io</a>.<br>",
"DESCRIPTION_LIVEDEV_SECURITY": "Security Warning from phcode.dev<br><br> This live preview attempted to access a non-project file. Access was denied for your safety. Please exercise caution when working on untrusted projects.",
"DESCRIPTION_LIVEDEV_SECURITY_POPOUT_MESSAGE": "You are about to open a file for live preview. Please proceed only if you trust the source of this project. Click 'Trust Project' to continue, or close this window if you do not trust the source.",
"DESCRIPTION_LIVEDEV_SECURITY_TRUST_MESSAGE": "You are about to open a file for live preview. Please proceed by clicking 'Trust Project' only if you trust the source of this project!",
"TRUST_PROJECT": "Trust Project - {0}",

// Strings for Auto Update
Expand Down
2 changes: 1 addition & 1 deletion src/project/ProjectManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ define(function (require, exports, module) {
}

function getExploreProjectPath() {
return `${getLocalProjectsPath()}explore`;
return `${getLocalProjectsPath()}explore/`;
}

/**
Expand Down

0 comments on commit 2505ece

Please sign in to comment.