mirror of
https://github.com/HeyPuter/puter.git
synced 2026-07-09 00:31:53 +00:00
Puter.js auth hardening
This commit is contained in:
@@ -56,6 +56,9 @@ class Auth {
|
||||
let settled = false;
|
||||
// Interval id for polling whether the user closed the popup.
|
||||
let checkClosed = null;
|
||||
// The auth popup window we opened. Pinned as the expected
|
||||
// `event.source` when validating the token message.
|
||||
let popupWindow = null;
|
||||
|
||||
const cleanup = () => {
|
||||
if ( checkClosed ) {
|
||||
@@ -66,6 +69,20 @@ class Auth {
|
||||
};
|
||||
|
||||
function messageHandler (e) {
|
||||
// Only accept the token from the Puter GUI origin AND from the
|
||||
// popup window we opened. Origin alone is insufficient (any
|
||||
// frame on the GUI domain could post), so also pin
|
||||
// event.source. Mirrors the validated handler in index.js.
|
||||
// msg_id binds the message to this attempt.
|
||||
if ( e.origin !== puter.defaultGUIOrigin ) {
|
||||
return;
|
||||
}
|
||||
if ( popupWindow && e.source !== popupWindow ) {
|
||||
return;
|
||||
}
|
||||
if ( e.data?.msg !== 'puter.token' ) {
|
||||
return;
|
||||
}
|
||||
if ( e.data?.msg_id != msg_id ) {
|
||||
return;
|
||||
}
|
||||
@@ -101,6 +118,8 @@ class Auth {
|
||||
reject({ error: 'popup_blocked', msg: 'The sign-in popup was blocked by the browser.' });
|
||||
return;
|
||||
}
|
||||
// Record the popup so messageHandler can pin event.source.
|
||||
popupWindow = popup;
|
||||
checkClosed = setInterval(() => {
|
||||
if ( ! popup.closed ) {
|
||||
return;
|
||||
|
||||
@@ -440,6 +440,16 @@ class PuterDialog extends (globalThis.HTMLElement || Object) { // It will fall b
|
||||
|
||||
// Event listener for the 'message' event
|
||||
this.messageListener = async (event) => {
|
||||
// Only accept the token from the Puter GUI origin AND from the
|
||||
// popup we opened. Origin alone is insufficient (any frame on the
|
||||
// GUI domain could post), so also pin event.source. Mirrors the
|
||||
// validated handler in index.js.
|
||||
if ( event.origin !== puter.defaultGUIOrigin ) {
|
||||
return;
|
||||
}
|
||||
if ( this.authPopup && event.source !== this.authPopup ) {
|
||||
return;
|
||||
}
|
||||
if ( event.data.msg === 'puter.token' ) {
|
||||
this.close();
|
||||
// Set the authToken property
|
||||
@@ -519,6 +529,8 @@ class PuterDialog extends (globalThis.HTMLElement || Object) { // It will fall b
|
||||
// safe from being popup-blocked because it happens inside a click.
|
||||
this.shadowRoot.querySelector('#launch-auth-popup')?.addEventListener('click', () => {
|
||||
const popup = openAuthPopup(this.#popupURL());
|
||||
// Pinned as the expected event.source in messageListener.
|
||||
this.authPopup = popup;
|
||||
|
||||
// Launcher mode: hand the popup back to the caller and close the
|
||||
// consent dialog — its only job was to provide the user gesture.
|
||||
@@ -544,6 +556,8 @@ class PuterDialog extends (globalThis.HTMLElement || Object) { // It will fall b
|
||||
open () {
|
||||
if ( hasUserActivation() ) {
|
||||
const popup = openAuthPopup(this.#popupURL());
|
||||
// Pinned as the expected event.source in messageListener.
|
||||
this.authPopup = popup;
|
||||
if ( this.options.popupURL && typeof this.options.onLaunch === 'function' ) {
|
||||
this.options.onLaunch(popup);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user