Kullanıcının yüklü bir Chrome uzantısı olup olmadığını kontrol edin


100

Bir Chrome uzantısı oluşturma sürecindeyim ve her şeyin benim istediğim şekilde çalışması için, bir kullanıcının uzantımın yüklü olup olmadığını algılayabilmesi için harici bir JavaScript komut dosyasına ihtiyacım var.

Örneğin: Bir kullanıcı eklentimi yükler ve ardından komut dosyamın bulunduğu bir web sitesine gider. Web sitesi, uzantımın yüklendiğini algılar ve sayfayı buna göre günceller.

Mümkün mü?


2
Evet, uzantı kimliğinizi bildiğiniz sürece (ki bildiğinizden eminim) uzantıları tespit etmek mümkündür. Daha fazla bilgi için bu siteyi kontrol edin: blog.kotowicz.net/2012/02/intro-to-chrome-addons-hacking.html 'Eklentilerinizi tek tek bulma' bölümüne geçin. İyi şanslar!
Martin Hughes

Bunu uygulamanın doğru yolu BJury tarafından aşağıda açıklanmıştır.
Rahatur

bu gönderi yardımcı oldu: ide.hey.network/post/5c3b6c7aa7af38479accc0c7
nab.

Yanıtlar:


47

Doğrudan bir yol olduğundan eminim (uzantılarınızdaki işlevleri doğrudan veya uzantılar için JS sınıflarını kullanarak), ancak dolaylı bir yöntem (daha iyi bir şey gelene kadar):

Chrome uzantınızın, sayfanızda çok özel bir kimlikle belirli bir DIV veya başka bir öğeyi aramasını sağlayın.

Örneğin:

<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>

Bir yapın getElementByIdve innerHTMLuzantınızın sürüm numarasına veya başka bir şeye ayarlayın. Daha sonra bu istemci tarafının içeriğini okuyabilirsiniz.

Yine de, eğer mevcutsa doğrudan bir yöntem kullanmalısınız.


DÜZENLEME: Doğrudan yöntem bulundu !!

Burada bulunan bağlantı yöntemlerini kullanın: https://developer.chrome.com/extensions/extension#global-events

Test edilmedi, ama yapabilmelisin ...

var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);

3
hmmm chrome.extension.connect, yalnızca uzantı (veya herhangi bir uzantı) içinden yürütüldüğünde çalışıyor gibi görünüyor. Herhangi bir rastgele js betiğinden çalışması için ihtiyacım var. Herhangi bir fikir?

Garip, belgeler çalışması gerektiğini söylüyor. "Diğer krom aksine. * API'ler, chrome.extension parçaları içerik komut tarafından kullanılabilir" ve listeleri sendRequest(), onRequest, connect(), onRequest, ve getURL().
Brad

@James, barındırılan bir komut dosyasından .connect () kullanan komut dosyasını mı çalıştırıyorsunuz? Chrome'un yalnızca güvenlik amacıyla barındırılmayan yerel dosyalarla çalışmamaya çalıştığını biliyorum. - Sadece kontrol.
JamesEggers

@James .connect () çalıştırdığım komut dosyası aynı sunucuda, demek istediğin buysa?

23
Son yöntem artık geçerli değil gibi connectişlev taşındı chrome.runtimead. Daha güncel bir sürüm için BJury'nin cevabına (ve yorumlarına) bakın
Xan

121

Chrome artık web sitesinden uzantıya mesaj gönderme yeteneğine sahip.

Dolayısıyla, background.js (content.js çalışmayacak) uzantısına aşağıdaki gibi bir şey ekleyin:

chrome.runtime.onMessageExternal.addListener(
    function(request, sender, sendResponse) {
        if (request) {
            if (request.message) {
                if (request.message == "version") {
                    sendResponse({version: 1.0});
                }
            }
        }
        return true;
    });

Bu daha sonra web sitesinden arama yapmanıza izin verecektir:

var hasExtension = false;

chrome.runtime.sendMessage(extensionId, { message: "version" },
    function (reply) {
        if (reply) {
            if (reply.version) {
                if (reply.version >= requiredVersion) {
                    hasExtension = true;
                }
            }
        }
        else {
          hasExtension = false;
        }
    });

Daha sonra hasExtension değişkenini kontrol edebilirsiniz. Tek dezavantajı, aramanın eşzamansız olmasıdır, bu yüzden bir şekilde bunun üzerinde çalışmanız gerekir.

Düzenleme: Aşağıda belirtildiği gibi, manifest.json'a eklentinize mesaj gönderebilecek etki alanlarını listeleyen bir giriş eklemeniz gerekir . Örneğin:

"externally_connectable": {
    "matches": ["*://localhost/*", "*://your.domain.com/*"]
},

2
Bu bir cazibe gibi çalışıyor. Diğer bir dezavantaj, elbette, uzantıyı kontrol etmeniz gerekmesidir - bunu, rastgele bir üçüncü taraf uzantısının yüklü olup olmadığını görmek için kullanamazsınız.
Eric P

2
@EricP Asıl soru uzantıyı yazdıklarını belirtti, bu yüzden konu tartışmalı.
BJury

13
Ayrıca manifest.json'unuza şunu eklemeniz gerekir: "externally_connectable": {"eşleşir": [" : // .alaniniz.com / *"]}
noname

3
Bu, {version: '1.0'} olmalı ve {version: 1.0} değil, aksi takdirde Inspect görünüm konsolunda 'Yakalanmamış Sözdizimi Hatası: Beklenmeyen sayı' mesajı alacaksınız.
ET-CS

1
"Kontrol" tarafında (belirli bir uzantının kullanılabilirliğini kontrol etmeye çalışan web sayfası), chrome.runtime tanımsızdır, linux üzerinde chrome 36.
reallynice

22

Diğer bir yöntem, web'den erişilebilen bir kaynağı ortaya çıkarmaktır , ancak bu, herhangi bir web sitesinin uzantınızın yüklü olup olmadığını test etmesine izin verecektir.

Uzantınızın kimliğinin olduğunu aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaave test.pnguzantınızın dosyalarında olduğu gibi bir dosya (örneğin, şeffaf bir piksel görüntüsü) eklediğinizi varsayalım .

Ardından, bu dosyayı web_accessible_resourcesmanifest anahtarıyla web sayfalarına açarsınız:

  "web_accessible_resources": [
    "test.png"
  ],

Web sayfanızda, bu dosyayı tam URL'siyle (bir <img>etikette, XHR aracılığıyla veya başka bir şekilde) yüklemeyi deneyebilirsiniz :

chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.png

Dosya yüklenirse, uzantı yüklenir. Bu dosyayı yüklerken bir hata oluşursa, uzantı yüklenmemiş demektir.

// Code from https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/8ArcsWMBaM4/2GKwVOZm1qMJ
function detectExtension(extensionId, callback) { 
  var img; 
  img = new Image(); 
  img.src = "chrome-extension://" + extensionId + "/test.png"; 
  img.onload = function() { 
    callback(true); 
  }; 
  img.onerror = function() { 
    callback(false); 
  };
}

Not: Bu dosyayı yüklerken bir hata oluşursa, söz konusu ağ yığını hatası, konsolda onu sessize alma olasılığı olmaksızın görünecektir. Chromecast bu yöntemi kullandığında, bu nedenle oldukça tartışmalara neden oldu ; Sonunda çok çirkin bir çözümle birlikte, Chrome ekibi tarafından Dev Tools'daki çok spesifik hataları tamamen kara listeye alma .


Önemli not: bu yöntem Firefox WebExtensions'ta çalışmayacaktır. Web'den erişilebilen kaynaklar, URL'nin kimliği bilinerek öngörülebilir olduğundan, uzantıyı doğal olarak parmak izine maruz bırakır. Firefox , web'den erişilebilen kaynaklara örneğe özgü rastgele bir URL atayarak bu deliği kapatmaya karar verdi :

Dosyalar daha sonra aşağıdaki gibi bir URL kullanılarak kullanılabilir olacaktır:

moz-extension://<random-UUID>/<path/to/resource>

Bu UUID, her tarayıcı örneği için rastgele oluşturulur ve uzantınızın kimliği değildir. Bu, web sitelerinin bir kullanıcının yüklediği uzantıların parmak izini almasını engeller.

Ancak, uzantı runtime.getURL()bu adresi almak için kullanabilse de, web sitenize kodu sabitleyemezsiniz.


Bu cevap stackoverflow.com/a/9216924/1504300 adresinden "suyu" alsa da , IMHO uzantıdaki kaynağı açığa çıkarmak ve var olup olmadığını kontrol etmek için bir ajax isteği kullanabileceğiniz gerçeği gibi oldukça önemli bilgiler ekler (Görüntü nesnesi yanılmıyorsam sadece HTML5'te mevcut görünüyor goo.gl/HBeI1i ). Bu
yanıttaki bilgilerle

@niconic Bu yanıt (yine de yalnızca bağlantı olarak kötü), manifesto sürüm 2 yürürlüğe girmeden önceki durumu ifade eder. Önceden, kaynakların web'den erişilebilir olduğunu bildirmeye gerek yoktu.
Xan

19

Bununla ilgili araştırmamı paylaşacağımı düşündüm. Bazı file: /// bağlantılarının çalışması için belirli bir uzantının yüklenip yüklenmediğini algılayabilmem gerekiyordu. Bu makaleye burada rastladım Bu , bir uzantının manifest.json dosyasını alma yöntemini açıkladı.

Kodu biraz değiştirdim ve şunu buldum:

function Ext_Detect_NotInstalled(ExtName, ExtID) {
  console.log(ExtName + ' Not Installed');
  if (divAnnounce.innerHTML != '')
    divAnnounce.innerHTML = divAnnounce.innerHTML + "<BR>"

  divAnnounce.innerHTML = divAnnounce.innerHTML + 'Page needs ' + ExtName + ' Extension -- to intall the LocalLinks extension click <a href="https://chrome.google.com/webstore/detail/locallinks/' + ExtID + '">here</a>';
}

function Ext_Detect_Installed(ExtName, ExtID) {
  console.log(ExtName + ' Installed');
}

var Ext_Detect = function (ExtName, ExtID) {
  var s = document.createElement('script');
  s.onload = function () { Ext_Detect_Installed(ExtName, ExtID); };
  s.onerror = function () { Ext_Detect_NotInstalled(ExtName, ExtID); };
  s.src = 'chrome-extension://' + ExtID + '/manifest.json';
  document.body.appendChild(s);
}

var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

if (is_chrome == true) {
  window.onload = function () { Ext_Detect('LocalLinks', 'jllpkdkcdjndhggodimiphkghogcpida'); };
}

Bununla, herhangi bir sayıda uzantının kurulumunu tespit etmek için Ext_Detect (ExtensionName, ExtensionID) kullanabilmeniz gerekir.


3
Görünüşe göre Google işleri daha güvenli hale getirdi, Ext_Detect () çalıştırdığımda şu hatayı alıyorum: chrome-extension: // [my_extension_id] /manifest.json yükünü reddediyorum. Uzantı dışındaki sayfaların yüklenebilmesi için kaynakların web_accessible_resources manifest anahtarında listelenmesi gerekir.
Lounge 9

27.02.2014
JE Carter II

1
@ Lounge9'un dediği gibi. Manifest_version 2'yi (veya üstünü) kullanan paketlerin içindeki kaynaklar varsayılan olarak engellenir ve bu özellik aracılığıyla kullanım için manifest.json'a eklenerek beyaz listeye alınmalıdır : "web_accessible_resources": ["manifest..json"],
ET-CS

@BJury cevabını kullanarak, verileri uzantıdan betiğe kolayca aktarabilirsiniz (örneğin uzantı sürümü) ve uzantıdaki herhangi bir dosyayı açığa çıkarmanız gerekmez.
ET-CS

1
Bu benim için en iyisi oldu, çünkü uzantımız birden çok alanda kullanılacak ve yeni alanlar düzenli olarak eklendiğinden önceden tanımlanamayacak. Manifest.json'a erişmek yerine yeni bir version.json dosyası oluşturdum ve sürüm numarasını içine koydum. Bu aynı şekilde çalışır.
Paul Haggo

7

Web sitesinin sahibiyseniz olası bir başka çözüm de satır içi kurulum kullanmaktır .

if (chrome.app.isInstalled) {
  // extension is installed.
}

Bunun eski bir soru olduğunu biliyorum, ancak bu yol Chrome 15'te tanıtıldı ve bu yüzden Id'yi yalnızca şimdi bir cevap arayan herkes için listelemeyi düşündüm.


12
Bu, bir Chrome Uygulaması için harika çalışıyor , ancak bir Chrome Uzantısı için harika çalışıyor AFAIK
Eran Medan

Evet, bu web sitesi size bir uzantıyı satır içi olarak nasıl yükleyeceğinizi anlatıyor , ancak görünüşe göre "Uzantılar, yerleştirme sayfasıyla içerik komut dosyaları aracılığıyla iletişim kurarak zaten yüklenmiş olduklarını bildirebilir." chrome.app.isInstalled kullanabilmek yerine. Beni de
şaşırttı


4

Çerez yöntemini kullandım:

Manifest.js dosyama yalnızca sitemde çalışan bir içerik komut dosyası ekledim:

 "content_scripts": [
        {
        "matches": [
            "*://*.mysite.co/*"
            ],
        "js": ["js/mysite.js"],
        "run_at": "document_idle"
        }
    ], 

js / mysite.js dosyamda bir satırım var:

document.cookie = "extension_downloaded=True";

ve index.html sayfamda o çerezi arıyorum.

if (document.cookie.indexOf('extension_downloaded') != -1){
    document.getElementById('install-btn').style.display = 'none';
}

Yukarıdaki tüm çözümleri denedim ama işe yaramıyor, sonra cevabını görüyorum, aradığım şey bu!
John Doe

Bu, bundan sonra her HTTP isteğine ek yük getirir.
mlissner

3

Uzantının bir çerez ayarlamasını ve web sitelerinizin JavaScript'in bu çerezin mevcut olup olmadığını kontrol etmesini ve buna göre güncellemesini sağlayabilirsiniz. Bu ve belki de en diğer yöntemler burada söz tabii ki, kullanıcı tarafından cirvumvented olabilir sürece denemek ve uzatma damgaları vb bağlı olarak özel kurabiye oluşturmak ve uygulama gerçekten kullanıcı ile olup olmadığını anlamak için onları sunucu tarafında analiz sahip olması uzantısı veya çerezlerini değiştirerek ona sahipmiş gibi davranan biri.


5
tek sorun, bir kullanıcı uzantılarınızı silerse. Çerez muhtemelen ayarlanmış olarak kalacaktır.
Chase Roberts

3

Bu Google Grupları gönderisinde gösterilen başka bir yöntem var . Kısacası, uzantı simgesinin başarıyla yüklenip yüklenmediğini tespit etmeyi deneyebilirsiniz. Kontrol ettiğiniz uzantı size ait değilse bu yardımcı olabilir.


1
Tamam. Bir uzantı simgesinin olup olmadığını nasıl kontrol ederiz?
Michael Rogers

3

Web sayfası, arka plan komut dosyası aracılığıyla uzantı ile etkileşime girer.

manifest.json:

"background": {
    "scripts": ["background.js"],
    "persistent": true
},
"externally_connectable": {
    "matches": ["*://(domain.ext)/*"]
},

background.js:
chrome.runtime.onMessageExternal.addListener(function(msg, sender, sendResponse) {
    if ((msg.action == "id") && (msg.value == id))
    {
        sendResponse({id : id});
    }
});

page.html:

<script>
var id = "some_ext_id";
chrome.runtime.sendMessage(id, {action: "id", value : id}, function(response) {
    if(response && (response.id == id)) //extension installed
    {
        console.log(response);
    }
    else //extension not installed
    {
        console.log("Please consider installig extension");
    }

});
</script>

Externally_connectable'ın desteklenmediği Firefox WebExtensions üzerinde çalışmaz.
mlissner

3

Uzantınız web sitesiyle etkileşime girebilir (örneğin değişkenleri değiştirebilir) ve web siteniz bunu algılayabilir.

Ancak bunu yapmanın daha iyi bir yolu olmalı. Google'ın uzantı galerisinde bunu nasıl yaptığını merak ediyorum (önceden yüklenmiş uygulamalar işaretlenmiştir).

Düzenle:

Galeri, chrome.management.get işlevini kullanır. Misal:

chrome.management.get("mblbciejcodpealifnhfjbdlkedplodp", function(a){console.log(a);});

Ancak yönteme yalnızca doğru izinlere sahip sayfalardan erişebilirsiniz.


1
Uzantının, uygulaması yavaş / zor ve hatalı olabilecek her sekmedeki her siteyle etkileşime girmesini gerektirecek olanlar: - /

Sorun, Chrome'un güvenlik modeli nedeniyle diğer yönde (sayfadan uzantıya) iletişimin mümkün olmamasıdır. 'Etkileşimli' yoldan gitmek istemiyorsanız, çerez yolunu kullanın.
Fox32

2
Sayın @ Fox32, chrome.management.get ..., şu hatayı döndürür:Uncaught TypeError: Cannot read property 'get' of undefined
Hosein Aqajani

3

Buradaki yanıtların çoğu şu ana kadar yalnızca Chrome'dur veya bir HTTP ek yük cezasına tabidir. Kullandığımız çözüm biraz farklı:

1. Manifest content_scripts listesine aşağıdaki gibi yeni bir nesne ekleyin:

{
  "matches": ["https://www.yoursite.com/*"],
  "js": [
    "install_notifier.js"
  ],
  "run_at": "document_idle"
}

Bu, install_notifier.js içindeki kodun o sitede çalışmasına izin verecektir (orada önceden izinleriniz yoksa).

2. Yukarıdaki manifest anahtarındaki her siteye bir mesaj gönderin.

İnstall_notifier.js'ye buna benzer bir şey ekleyin (bunun değişkenlerin global olmasını önlemek için bir kapatma kullandığına dikkat edin, ancak bu kesinlikle gerekli değildir):

// Dispatch a message to every URL that's in the manifest to say that the extension is
// installed.  This allows webpages to take action based on the presence of the
// extension and its version. This is only allowed for a small whitelist of
// domains defined in the manifest.
(function () {
  let currentVersion = chrome.runtime.getManifest().version;
  window.postMessage({
    sender: "my-extension",
    message_name: "version",
    message: currentVersion
  }, "*");
})();

Mesajınız herhangi bir şey söyleyebilir, ancak neyle karşı karşıya olduğunuzu bilmeniz için sürümü göndermek yararlıdır. Sonra...

3. Web sitenizde bu mesajı dinleyin.

Bunu web sitenize bir yere ekleyin:

window.addEventListener("message", function (event) {
  if (event.source == window &&
    event.data.sender &&
    event.data.sender === "my-extension" &&
    event.data.message_name &&
    event.data.message_name === "version") {
    console.log("Got the message");
  }
});

Bu, Firefox ve Chrome'da çalışır ve HTTP ek yüküne neden olmaz veya sayfayı değiştirmez.


2

İşte başka bir modern yaklaşım:

const checkExtension = (id, src, callback) => {
    let e = new Image()
    e.src = 'chrome-extension://'+ id +'/'+ src
    e.onload = () => callback(1), e.onerror = () => callback(0)
}

// "src" must be included to "web_accessible_resources" in manifest.json
checkExtension('gighmmpiobklfepjocnamgkkbiglidom', 'icons/icon24.png', (ok) => {
    console.log('AdBlock: %s', ok ? 'installed' : 'not installed')
})
checkExtension('bhlhnicpbhignbdhedgjhgdocnmhomnp', 'images/checkmark-icon.png', (ok) => {
    console.log('ColorZilla: %s', ok ? 'installed' : 'not installed')
})

1
kaynaklara erişime izin vermek için manifest'i güncellediğinizden emin olun: "web_accessible_resources": ["icons / *. png"]
Derek Wade

0

Chrome uzantısı üzerinde kontrolünüz varsa, yaptığımı deneyebilirsiniz:

// Inside Chrome extension
var div = document.createElement('div');
div.setAttribute('id', 'myapp-extension-installed-div');
document.getElementsByTagName('body')[0].appendChild(div);

Ve sonra:

// On web page that needs to detect extension
if ($('#myapp-extension-installed-div').length) {

}

Biraz zor geliyor, ancak diğer yöntemlerin çalışmasını sağlayamadım ve Chrome'un burada API'sini değiştirmesinden endişeleniyorum. Bu yöntemin yakın zamanda çalışmayı bırakacağı şüphelidir.


yukarıda belirtildiği gibi - bunu test ettim ama işlem sırası tuhaf görünüyor - önce hangi komut dosyası çalıştırılır?
Brady Moritz

0

Benim kullandığım bir çapraz tarayıcı yöntemini de kullanabilirsiniz. Bir div ekleme kavramını kullanır.

içerik komut dosyanızda (komut dosyası her yüklendiğinde, bunu yapmalıdır)

if ((window.location.href).includes('*myurl/urlregex*')) {
        $('html').addClass('ifextension');
        }

web sitenizde şöyle bir şey iddia ediyorsunuz:

if (!($('html').hasClass('ifextension')){}

Ve uygun mesajı atın.


Bunu test ettim ama işlemlerin sırası tuhaf görünüyor - önce hangi komut dosyası çalıştırılır vb.
Brady Moritz

@BradyMoritz yanıttakiyle aynı sırada. Önce sınıfı ekleyin ve ardından onaylayın.
Prakash Palnati

içerik komut dosyam sayfa içi komut dosyamdan önce çalışmıyor gibi görünüyordu?
Brady Moritz

Bunu düzeltmenin kolay olduğunu düşünüyorum. Regex kullanarak gerekli URL'ye / rotaya tıkladıktan hemen sonra içerik betiğinizin çalıştığından emin olabilirsiniz. Bunu denediniz mi?
Prakash Palnati

0

Herhangi bir web sitesinden herhangi bir uzantı tespit etmeye çalışıyorsanız, bu gönderi yardımcı oldu: https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7

Temel olarak çözüm, uzantıdan yolunu belirterek belirli bir dosyayı (manifest.json veya bir görüntü) almaya çalışmak olacaktır. İşte kullandım. Kesinlikle çalışıyor:

const imgExists = function(_f, _cb) {
    const __i = new Image();
    __i.onload = function() {
        if (typeof _cb === 'function') {
            _cb(true);
        }
    }
    __i.onerror = function() {
        if (typeof _cb === 'function') {
            _cb(false);
        }
    }
    __i.src = _f;
    __i = null;
});

try {
    imgExists("chrome-extension://${CHROME_XT_ID}/xt_content/assets/logo.png", function(_test) {
        console.log(_test ? 'chrome extension installed !' : 'chrome extension not installed..');
        ifrm.xt_chrome = _test;
        // use that information
    });
} catch (e) {
    console.log('ERROR', e)
}

0

Yüklü belirli bir Uzantıyı nasıl tespit edebileceğiniz ve bir uyarı mesajı gösterebileceğiniz aşağıda açıklanmıştır.

Öncelikle chrome-extension: //extension_id_here_hkdppipefbchgpohn/manifest.json adresine giderek uzantının manifest dosyasını açmanız ve "web_accessible_resources" bölümünde herhangi bir dosya adı aramanız gerekir.

<div class="chromewarning" style="display:none">
    <script type="text/javascript">
                            $.get("chrome-extension://extension_id_here_hkdppipefbchgpohn/filename_found_in_ web_accessible_resources.png").done(function () {
                              $(".chromewarning").show();
                            }).fail(function () {
                             //  alert("failed.");
                            });
                        </script>
                        <p>We have detected a browser extension that conflicts with learning modules in this course.</p>
            </div>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.