@SmokyA

Как провести миграцию с манифест 2 на манифест 3 гугл хром?

Добрый день!
Уже несколько суток бьюсь с задачей перевести расширение с манифеста2 на манифест3 для Хрома.
Суть в следующем: в настоящее время расширение открывается в iframe внутри любой вкладки браузера и выполняется внешний скрипт, который загружает данные в расширение.
Манифест2
{
  "manifest_version": 2,
  "name": "__MSG_extension_name__",
  "short_name": "__MSG_extension_short_name__",
  "version": "1.4.1",
  "default_locale": "ru",
  "description":"__MSG_extension_description__",
  "icons":{
    "128":"img/icons/128.png",
    "16":"img/icons/16.png",
    "48":"img/icons/48.png"
  },
  "background": {
    "scripts": [
      "background.js"
    ]
  },
  "permissions": [
    "http://*/*",
    "https://*/*",
    "\u003Call_urls\u003E"
  ],
  "browser_action": {
    "default_title": "My widget",
    "default_icon": "img/icons/128.png"
  }
}


background.js
var SSChromePanelTab = function (id) {
    var t = this;
    t.id = id;
    t.init();
};

/**
 * Скрипт показывающий/скрывающий панельку
 */
SSChromePanelTab.prototype.executeToggleScript = function () {
    chrome.tabs.executeScript(this.id, {file: "functions/toggle.js"});
};

/**
 * Инициализация виджета во вкладке
 */
SSChromePanelTab.prototype.init = function () {
    var t = this;
    t.executeToggleScript();
};

/**
 * Инспектор, следящий за всеми объектами вкладок
 *
 * @constructor
 */
var SSChromePanelInspector = function () {
    var i = this;

    i.tabs = {};
};

/**
 * Функция-обработчик клика по кнопке расширения
 *
 * @param tab_id
 */
SSChromePanelInspector.prototype.toggle = function (tab_id) {
    var i = this;

    if (typeof i.tabs[tab_id] === 'undefined') {
        i.tabs[tab_id] = new SSChromePanelTab(tab_id);
    } else {
        i.tabs[tab_id].executeToggleScript();
    }
};

// Инициализируем инспектор панелей
var sschromepanelinspector = new SSChromePanelInspector();

// Инициализируем обработчик клика по кнопке расширения
chrome.browserAction.onClicked.addListener(function (tab) {
    sschromepanelinspector.toggle(tab.id);
});

chrome.tabs.onUpdated.addListener( function (tabId, changeInfo, tab) {
    if (changeInfo.status == 'complete') {
        chrome.tabs.executeScript(tabId, {file: "functions/auto_init.js"});
    }
});


toggle.js файл
var loaded = document.getElementById('sswidget-loaded');

function getIsSSWidgetDestryed() {
    var from_storage = localStorage.getItem('sswidget');

    if (from_storage) {
        var data = JSON.parse(from_storage);
        return data.destroyed;
    }

    return false;
}

if (!loaded) {
    var elt = document.createElement("script");
    elt.innerHTML = "window['SSWidgetInstance'] = 'sswidget';";
    document.head.appendChild(elt);

    (function (d, w) {
        var n = d.getElementsByTagName("script")[0],
            s = d.createElement("script"),
            f = function () {
                n.parentNode.insertBefore(s, n);
            };
        s.type = "text/javascript";
        s.async = true;
        s.src = "//mysite.ru/widget.js";

        if (w.opera == "[object Opera]") {
            d.addEventListener("DOMContentLoaded", f, false);
        } else {
            f();
        }
    })(document, window);

} else if (getIsSSWidgetDestryed()) {
    var elt = document.createElement("script");
    elt.innerHTML = "window['sswidget'].init()";
    document.head.appendChild(elt);
} else {
    var elt = document.createElement("script");
    elt.innerHTML = "window['sswidget'].destroy()";
    document.head.appendChild(elt);
}


auto_init.js
function getIsSSWidgetEnabled() {
    var from_storage = localStorage.getItem('sswidget');

    if (from_storage) {
        var data = JSON.parse(from_storage);
        return !data.destroyed;
    }

    return false;
}

var loaded = document.getElementById('sswidget-loaded');

if (!loaded && getIsSSWidgetEnabled()) {
    console.log('auto init!');
    var elt = document.createElement("script");
    elt.innerHTML = "window['SSWidgetInstance'] = 'sswidget';";
    document.head.appendChild(elt);

    (function (d, w) {
        var n = d.getElementsByTagName("script")[0],
            s = d.createElement("script"),
            f = function () {
                n.parentNode.insertBefore(s, n);
            };
        s.type = "text/javascript";
        s.async = true;
        s.src = "//mysite.ru/widget.js";

        if (w.opera == "[object Opera]") {
            d.addEventListener("DOMContentLoaded", f, false);
        } else {
            f();
        }
    })(document, window);
}


Я переделываю уже на разный манер данный виджет для 3 манифеста, но не могу нащупать путь, как мне подгрузить внешний скрипт src = "//mysite.ru/widget.js" и везде натыкаюсь на CSP. Последний вариант такой:
Манифест3
{
  "manifest_version": 3,
  "name": "Action API Demo",
  "short_name": "__Action API Demo__",
  "version": "1.4.8",  
  "description": "Uses the Action API to change the badge text, icon, hover text, or popup page.",
  "icons": {
    "32": "icons/32.png",
    "72": "icons/72.png",
    "128": "icons/128.png",
    "512": "icons/512.png"
  },
   "content_scripts": [
   {
     "matches": ["<all_urls>",
    "http://*/*",
    "https://*/*"],         
     "js": ["content.js"]
   }
 ],  
  "background": {
    "service_worker": "background.js",
	"action": {}
  },
  "permissions": [      
      "tabs", "activeTab", "scripting"
  ],
  "host_permissions": [
    "<all_urls>",
    "http://*/*",
    "https://*/*"
  ],
  "action": {
    "default_title": "Default Title"
  }
}


Сервис-вокер:
// Инициализируем обработчик клика по кнопке расширения
/**
 * Обработчик нажатия на действие расширения
 */
chrome.action.onClicked.addListener(tab => {
    chrome.scripting.executeScript({
        target: {tabId: tab.id},
        files: ['content.js']
    }, () => {
        if (chrome.runtime.lastError) {
            console.error("Ошибка при выполнении скрипта:", chrome.runtime.lastError.message);
        } else {
            console.log("Скрипт content.js успешно выполнен на вкладке с ID:", tab.id);
            // Добавляем небольшую задержку перед отправкой сообщения
            setTimeout(() => {
                sendMessageToContentScript(tab.id);
            }, 100); // Установите время задержки по вашему усмотрению
        }
    });
});

function sendMessageToContentScript(tabId) {
    chrome.tabs.sendMessage(tabId, {action: "toggle", tabId: tabId}, response => {
        if (chrome.runtime.lastError) {
            console.error("Ошибка при отправке сообщения:", chrome.runtime.lastError.message);
        } else {
            console.log("Сообщение успешно отправлено на вкладку с ID:", tabId);
        }
    });
}


Контентный скрипт:
/**
 * Объект-обертка для функций вкладки
 * @param id
 * @constructor
 */
class SSChromePanelTab {
    constructor(id) {
        this.id = id;
        this.init();
    }

    executeToggleScript() {
		console.log('executeToggleScript');
         
        var loaded = document.getElementById('sswidget-loaded');

        function getIsSSWidgetDestryed() {
            var from_storage = localStorage.getItem('sswidget');

            if (from_storage) {
                var data = JSON.parse(from_storage);
                return data.destroyed;
            }

            return false;
        }

        if (!loaded) {            
			// Устанавливаем переменную окружения для виджета
			window['SSWidgetInstance'] = 'sswidget';

			// Создаем элемент <script> для загрузки внешнего скрипта
			var script = document.createElement('script');
			script.src = 'https://mysite.ru/widget.js';
			script.async = true; // Устанавливаем асинхронную загрузку
			document.head.appendChild(script);

        } else if (getIsSSWidgetDestryed()) {
            var elt = document.createElement("script");
            elt.innerHTML = "window['sswidget'].init()";
            document.head.appendChild(elt);
        } else {
            var elt = document.createElement("script");
            elt.innerHTML = "window['sswidget'].destroy()";
            document.head.appendChild(elt);
        }
        
    }

    init() {
        this.executeToggleScript(); 	
    }
}

/**
 * Инспектор, следящий за всеми объектами вкладок
 */
class SSChromePanelInspector {
    constructor() {
        this.tabs = {};
    }

    toggle(tab_id) {
		console.log('toggle');
        if (typeof this.tabs[tab_id] === 'undefined') {
            this.tabs[tab_id] = new SSChromePanelTab(tab_id);
        } else {
            this.tabs[tab_id].executeToggleScript();
        }
    }
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === "toggle") {
        console.log('Content script received toggle action for tab ID:', message.tabId);        
		const ssChromePanelInspector = new SSChromePanelInspector();
		ssChromePanelInspector.toggle(message.tabId);
    }
});

И на строке контентного скрипта document.head.appendChild(script); получаю ошибку в консоли Refused to load the script 'https://mysite.ru/widget.js' because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Пробовала создать расширение-песочницу - там открывается отдельная страница html и пропадает смысл приложения, тк оно позиционируется как помощник на любой вкладке. С popup не получилось, возможно, Вы мне посоветуете, как переделать код, для открытия расширения в popup...

Подскажите, пожалуйста, как мне вывести в iframe расширение в текущих условиях манифеста3?
  • Вопрос задан
  • 59 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы