Puter Worker Sandbox Playground
+Use this page to interact with the puter APIs in the same sandbox as your worker.
+ +diff --git a/extensions/whoami/routes.js b/extensions/whoami/routes.js index 2421b6454..9184ce50e 100644 --- a/extensions/whoami/routes.js +++ b/extensions/whoami/routes.js @@ -98,6 +98,7 @@ extension.get('/whoami', { subdomain: 'api' }, async (req, res, next) => { human_readable_age: timeago.format(new Date(req.user.timestamp)), hasDevAccountAccess: !!req.actor.type.user.metadata?.hasDevAccountAccess, ...(req.new_token ? { token: req.token } : {}), + is_user_token: true, // gets deleted if not a user token }; // TODO: redundant? GetUserService already puts these values on 'user' @@ -128,6 +129,7 @@ extension.get('/whoami', { subdomain: 'api' }, async (req, res, next) => { delete details.taskbar_items; delete details.token; delete details.human_readable_age; + delete details.is_user_token; } if ( actor.type instanceof AppUnderUserActorType ) { diff --git a/extensions/worker-sandbox.js b/extensions/worker-sandbox.js new file mode 100644 index 000000000..b0926cf7d --- /dev/null +++ b/extensions/worker-sandbox.js @@ -0,0 +1,201 @@ +const page = ` + + +
+ + +Use this page to interact with the puter APIs in the same sandbox as your worker.
+ +${html_encode(err)}`;
+ }
+
+ $(el_window).find('.publish-worker-error-msg').html(errorHtml);
$(el_window).find('.publish-worker-error-msg').fadeIn();
// re-enable 'Publish' button and restore original text
$(el_window).find('.publish-btn').prop('disabled', false).text(originalText);
- });
+ });
});
$(el_window).find('.publish-window-ok-btn').on('click', function () {
diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css
index 0c2758bb1..37288da0b 100644
--- a/src/gui/src/css/style.css
+++ b/src/gui/src/css/style.css
@@ -1953,6 +1953,10 @@ label {
font-size: 13px;
}
+.publish-worker-error-msg{
+ text-align: left;
+}
+
.error {
display: none;
color: red;
diff --git a/src/puter-js/src/modules/Workers.js b/src/puter-js/src/modules/Workers.js
index 92c3c81ed..f78c4f92f 100644
--- a/src/puter-js/src/modules/Workers.js
+++ b/src/puter-js/src/modules/Workers.js
@@ -18,6 +18,22 @@ export class WorkersHandler {
}
let appId;
+ if ( typeof (appName) === 'object' || typeof (appName) === 'undefined' ) {
+ const user = (puter.whoami || await puter.getUser());
+
+ if ( user.is_user_token && (appName === undefined || appName?.sandbox !== false) ) {
+ let sandboxApp;
+ try {
+ sandboxApp = await puter.apps.get(`sandbox-${ workerName }`);
+ } catch ( e ) {
+ sandboxApp = await puter.apps.create(`sandbox-${ workerName }`, 'https://worker-sandbox.puter.com/');
+ }
+ if ( sandboxApp.owner.uuid !== user.uuid ) {
+ throw new Error(`Sandbox context is not owned by you! This worker's sandbox is currently owned by: ${ sandboxApp.owner.username }`);
+ }
+ appId = sandboxApp.uid;
+ }
+ }
if ( typeof (appName) === 'string' ) {
appId = ((await puter.apps.list()).find(el => el.name === appName)).uid;
}
@@ -121,7 +137,7 @@ export class WorkersHandler {
const loggingEndpoint = await utils.make_driver_method([], 'workers', 'worker-service', 'getLoggingUrl')(puter.authToken, workerName);
const socket = new WebSocket(`${loggingEndpoint}/${puter.authToken}/${workerName}`);
const logStreamObject = new EventTarget();
- logStreamObject.onLog = (data) => {
+ logStreamObject.onLog = (_data) => {
};
@@ -132,11 +148,11 @@ export class WorkersHandler {
socket.addEventListener('message', (event) => {
controller.enqueue(JSON.parse(event.data));
});
- socket.addEventListener('close', (event) => {
+ socket.addEventListener('close', () => {
try {
controller.close();
} catch (e) {
-
+ // no-op
}
});
},