Fixed CORS issue
Cette révision appartient à :
@@ -1,5 +1,11 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 1.0.3 - 2025-11-01
|
||||||
|
|
||||||
|
- **Added**: Runtime optional host permission flow so users can authorize their own YTPTube servers without manual manifest edits.
|
||||||
|
- **Improved**: Options page now normalizes instance URLs, records granted origins, and cleans up old host permissions when the server changes.
|
||||||
|
- **Fixed**: Background requests to user-managed servers no longer hit CORS/address-space blocks after permissions are granted.
|
||||||
|
|
||||||
## 1.0.2 - 2025-08-12
|
## 1.0.2 - 2025-08-12
|
||||||
|
|
||||||
- **Fixed**: Selected preset was not being sent to YTPTube API - now properly includes preset in requests
|
- **Fixed**: Selected preset was not being sent to YTPTube API - now properly includes preset in requests
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "YTPTube Extension",
|
"name": "YTPTube Extension",
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"description": "Add URLs to YTPTube instance",
|
"description": "Add URLs to YTPTube instance",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"activeTab",
|
"activeTab",
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
"storage",
|
"storage",
|
||||||
"notifications"
|
"notifications"
|
||||||
],
|
],
|
||||||
|
"optional_host_permissions": [
|
||||||
|
"http://*/*",
|
||||||
|
"https://*/*"
|
||||||
|
],
|
||||||
"homepage_url": "https://github.com/arabcoders/ytptube-extension",
|
"homepage_url": "https://github.com/arabcoders/ytptube-extension",
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "icons/icon-16.png",
|
"16": "icons/icon-16.png",
|
||||||
|
|||||||
+66
-3
@@ -1,6 +1,7 @@
|
|||||||
// noinspection JSUnresolvedReference
|
// noinspection JSUnresolvedReference
|
||||||
|
|
||||||
const str_keys = ["instance_url", "preset", "template", "folder", "username", "password"]
|
const str_keys = ["instance_url", "preset", "template", "folder", "username", "password"]
|
||||||
|
let storedOriginPattern = null;
|
||||||
|
|
||||||
if (typeof chrome === 'undefined') {
|
if (typeof chrome === 'undefined') {
|
||||||
let chrome = browser
|
let chrome = browser
|
||||||
@@ -19,11 +20,46 @@ const notify = (message, no_inline) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildOriginPattern = (instanceUrl) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(instanceUrl);
|
||||||
|
return `${url.protocol}//${url.host}/*`;
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ensureOriginPermission = async (originPattern) => {
|
||||||
|
if (!originPattern) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasPermission = await chrome.permissions.contains({origins: [originPattern]});
|
||||||
|
if (hasPermission) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await chrome.permissions.request({origins: [originPattern]});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeOriginPermission = async (originPattern) => {
|
||||||
|
if (!originPattern) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasPermission = await chrome.permissions.contains({origins: [originPattern]});
|
||||||
|
if (!hasPermission) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await chrome.permissions.remove({origins: [originPattern]});
|
||||||
|
};
|
||||||
|
|
||||||
const testConfig = async () => {
|
const testConfig = async () => {
|
||||||
|
|
||||||
document.querySelector('#error_msg').innerText = "";
|
document.querySelector('#error_msg').innerText = "";
|
||||||
|
|
||||||
let instance_url = document.querySelector("#instance_url").value;
|
let instance_url = document.querySelector("#instance_url").value.trim();
|
||||||
if (!instance_url) {
|
if (!instance_url) {
|
||||||
notify("Please enter a valid YTPTube instance URL.");
|
notify("Please enter a valid YTPTube instance URL.");
|
||||||
return false;
|
return false;
|
||||||
@@ -33,6 +69,20 @@ const testConfig = async () => {
|
|||||||
instance_url = instance_url.slice(0, -1);
|
instance_url = instance_url.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelector("#instance_url").value = instance_url;
|
||||||
|
|
||||||
|
const originPattern = buildOriginPattern(instance_url);
|
||||||
|
if (!originPattern) {
|
||||||
|
notify("Please enter a valid YTPTube instance URL.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const granted = await ensureOriginPermission(originPattern);
|
||||||
|
if (!granted) {
|
||||||
|
notify("Permission to access the YTPTube instance was denied.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let username = document.querySelector("#username").value;
|
let username = document.querySelector("#username").value;
|
||||||
let password = document.querySelector("#password").value;
|
let password = document.querySelector("#password").value;
|
||||||
|
|
||||||
@@ -69,7 +119,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
chrome.storage.sync.get(k).then(r => document.querySelector(`#${k}`).value = r[k] || "", onError);
|
chrome.storage.sync.get(k).then(r => document.querySelector(`#${k}`).value = r[k] || "", onError);
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.sync.get("showContextMenu").then(r => document.querySelector("#showContextMenu").checked = r.showContextMenu || false);
|
chrome.storage.sync.get(["showContextMenu", "instance_origin"]).then(r => {
|
||||||
|
document.querySelector("#showContextMenu").checked = r.showContextMenu || false;
|
||||||
|
storedOriginPattern = r.instance_origin || null;
|
||||||
|
}, onError);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("ytptube_options").addEventListener("submit", async e => {
|
document.getElementById("ytptube_options").addEventListener("submit", async e => {
|
||||||
@@ -84,7 +137,16 @@ document.getElementById("ytptube_options").addEventListener("submit", async e =>
|
|||||||
let data = {presets: {presets: ['default'], last_updated: 0}}
|
let data = {presets: {presets: ['default'], last_updated: 0}}
|
||||||
|
|
||||||
str_keys.forEach(key => data[key] = document.querySelector(`#${key}`).value)
|
str_keys.forEach(key => data[key] = document.querySelector(`#${key}`).value)
|
||||||
data["showContextMenu"] = showContextMenu
|
data["showContextMenu"] = showContextMenu;
|
||||||
|
|
||||||
|
const newOriginPattern = buildOriginPattern(data.instance_url);
|
||||||
|
if (storedOriginPattern && storedOriginPattern !== newOriginPattern) {
|
||||||
|
await removeOriginPermission(storedOriginPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.instance_origin = newOriginPattern;
|
||||||
|
storedOriginPattern = newOriginPattern;
|
||||||
|
|
||||||
chrome.storage.sync.set(data);
|
chrome.storage.sync.set(data);
|
||||||
chrome.contextMenus.update("send-to-ytptube", {visible: showContextMenu});
|
chrome.contextMenus.update("send-to-ytptube", {visible: showContextMenu});
|
||||||
|
|
||||||
@@ -102,3 +164,4 @@ document.getElementById("test_config").addEventListener("click", async e => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await testConfig();
|
await testConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Référencer dans un nouveau ticket
Bloquer un utilisateur