pdscors.js
1// ==UserScript==
2// @name PDS CORS Reload Workaround
3// @namespace Violentmonkey Scripts
4// @match https://pds-nd.whey.party/oauth/authorize*
5// @grant none
6// @version 1.3
7// @author -
8// @description Reliably bypasses the 'sec-fetch-site' error by using a MutationObserver to wait for the error message and then triggering a cross-site reload via a hidden iframe.
9// ==/UserScript==
10
11(function () {
12 'use strict';
13
14 // Use a session storage flag to prevent an infinite redirect loop.
15 const retryKey = '__cors_workaround_attempted__';
16
17 // 1. ABORT if we've already tried the fix in this session.
18 // This is the most important check to prevent loops.
19 if (sessionStorage.getItem(retryKey)) {
20 console.log("[Workaround] Already attempted a fix in this session. Aborting.");
21 // The page has reloaded. We now assume it's either fixed or has a different error.
22 // We clear the key so that a manual refresh by the user can trigger the script again.
23 sessionStorage.removeItem(retryKey);
24 return;
25 }
26
27 // 2. Define the keywords that identify the specific error message.
28 const TARGET_KEYWORDS = [
29 'Forbidden sec-fetch-site header',
30 'same-site',
31 'expected cross-site',
32 ];
33
34 // The function that performs the fix.
35 function triggerFix() {
36 console.log("[Workaround] Error detected in DOM. Initiating cross-site reload via hidden iframe.");
37
38 // Set the flag BEFORE navigating to prevent a loop if the fix fails.
39 sessionStorage.setItem(retryKey, '1');
40
41 const iframe = document.createElement('iframe');
42 iframe.style.display = 'none';
43 iframe.src = `data:text/html,<script>window.top.location.replace(${JSON.stringify(location.href)});</script>`;
44 document.body.appendChild(iframe);
45 }
46
47 // 3. The CORE LOGIC: Use a MutationObserver to watch for the error.
48 // This solves the race condition where the error message is added dynamically.
49 const observer = new MutationObserver((mutations, obs) => {
50 const bodyText = document.body.textContent || '';
51 const isErrorPage = TARGET_KEYWORDS.every(k => bodyText.includes(k));
52
53 if (isErrorPage) {
54 // Error found! Trigger the fix.
55 triggerFix();
56 // IMPORTANT: Stop observing once we've acted.
57 obs.disconnect();
58 }
59 });
60
61 // 4. Start observing.
62 // We need to wait for the <body> to exist before we can observe it.
63 function startObserver() {
64 if (document.body) {
65 console.log("[Workaround] Observer started. Waiting for 'same-site' error to appear...");
66 // Also do an initial check, in case the error is already present.
67 const initialBodyText = document.body.textContent || '';
68 if (TARGET_KEYWORDS.every(k => initialBodyText.includes(k))) {
69 triggerFix();
70 return; // No need to observe if we fix it instantly.
71 }
72
73 observer.observe(document.body, {
74 childList: true, // Watch for added/removed nodes (like the error <dd>)
75 subtree: true, // Watch all descendants of the body
76 });
77 } else {
78 // If body isn't ready, wait for DOMContentLoaded.
79 window.addEventListener("DOMContentLoaded", startObserver, { once: true });
80 }
81 }
82
83 startObserver();
84
85 // Safety net: Stop observing after 10 seconds if nothing happens,
86 // to prevent it from running forever on a page that is just slow to load.
87 setTimeout(() => {
88 observer.disconnect();
89 console.log("[Workaround] Observer timed out after 10 seconds. Assuming no error or a different issue.");
90 }, 10000);
91
92})();