Así es como:
Para compartir entre subdominios de un superdominio determinado (por ejemplo, example.com), existe una técnica que puede utilizar en esa situación. Se puede aplicar a localStorage
, IndexedDB
, SharedWorker
, BroadcastChannel
, etc, todos los cuales ofrecen funcionalidad compartida entre las páginas del mismo origen, pero por alguna razón no respetan ninguna modificación a document.domain
que ejerzan el superdomain como su origen directamente.
(1) Elija un dominio "principal" para que pertenezcan los datos: es decir, https://example.com o https://www.example.com mantendrán sus datos de almacenamiento local. Digamos que elige https://example.com .
(2) Utilice localStorage normalmente para las páginas de ese dominio elegido.
(3) En todas las páginas https://www.example.com (el otro dominio), use javascript para configurar document.domain = "example.com";
. Luego, cree también un oculto <iframe>
y navegue a alguna página en el dominio https://example.com elegido ( no importa qué página , siempre que pueda insertar un pequeño fragmento de JavaScript allí. Si ' Al crear el sitio, simplemente cree una página vacía específicamente para este propósito. Si está escribiendo una extensión o un script de usuario al estilo Greasemonkey y, por lo tanto, no tiene ningún control sobre las páginas de example.comservidor, simplemente elija la página más liviana que pueda encontrar e inserte su script en ella. Algún tipo de página "no encontrada" probablemente estaría bien).
(4) La secuencia de comandos en la página de iframe oculta solo necesita (a) configurarse document.domain = "example.com";
y (b) notificar a la ventana principal cuando esto esté hecho. Después de eso, la ventana principal puede acceder a la ventana iframe y a todos sus objetos sin restricciones. Entonces, la página de iframe mínima es algo como:
<!doctype html>
<html>
<head>
<script>
document.domain = "example.com";
window.parent.iframeReady(); // function defined & called on parent window
</script>
</head>
<body></body>
</html>
Si escribir un userscript, puede que no desee añadir funciones accesibles externamente como iframeReady()
a su unsafeWindow
, por lo que en lugar de una mejor forma de notificar a la ventana principal userscript podría ser el uso de un evento personalizado:
window.parent.dispatchEvent(new CustomEvent("iframeReady"));
Lo cual detectaría agregando un oyente para el evento personalizado "iframeReady" en la ventana de su página principal.
(NOTA: Debe establecer document.domain = "example.com" incluso si el dominio del iframe ya es example.com : la asignación de un valor a document.domain establece implícitamente el puerto de origen en nulo, y ambos puertos deben coincidir con el iframe y su padre se considera del mismo origen. Consulte la nota aquí: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin )
(5) Una vez que el iframe oculto haya informado a su ventana primaria que está listo, la escritura en la ventana padre solo puede usar iframe.contentWindow.localStorage
, iframe.contentWindow.indexedDB
, iframe.contentWindow.BroadcastChannel
, iframe.contentWindow.SharedWorker
en lugar de window.localStorage
, window.indexedDB
, etc ... y todos estos objetos serán ámbito es el elegido https: // origen de example.com - ¡así tendrán el mismo origen compartido para todas sus páginas!
La parte más incómoda de esta técnica es que debe esperar a que se cargue el iframe antes de continuar. Entonces, no puede simplemente comenzar a usar alegremente localStorage en su controlador DOMContentLoaded, por ejemplo. También es posible que desee agregar algún manejo de errores para detectar si el iframe oculto no se carga correctamente.
Obviamente, también debe asegurarse de que el iframe oculto no se elimine ni se navegue durante la vida útil de su página ... OTOH No sé cuál sería el resultado de eso, pero es muy probable que sucedan cosas malas.
Y una advertencia: la configuración / cambio document.domain
se puede bloquear mediante el Feature-Policy
encabezado, en cuyo caso esta técnica no se podrá utilizar como se describe.
Sin embargo, hay una generalización significativamente más complicada de esta técnica, que no puede ser bloqueada Feature-Policy
y que también permite que dominios completamente no relacionados compartan datos, comunicaciones y trabajadores compartidos (es decir, no solo subdominios de un superdominio común). @Mayank Jain ya lo describió en su respuesta, a saber:
La idea general es que, al igual que antes, cree un iframe oculto para proporcionar el origen correcto para el acceso; pero en lugar de simplemente tomar las propiedades de la ventana del iframe directamente, usa un script dentro del iframe para hacer todo el trabajo, y se comunica entre el iframe y su ventana principal solo usando postMessage()
y addEventListener("message",...)
.
Esto funciona porque postMessage()
se puede usar incluso entre ventanas de diferentes orígenes. Pero también es significativamente más complicado porque tienes que pasar todo a través de algún tipo de infraestructura de mensajería que creas entre el iframe y la ventana principal, en lugar de usar las API localStorage, IndexedDB, etc. directamente en el código de tu ventana principal.