簡單的谷歌插件開發(fā)記錄

工作上遇到一個小問題, 就是桌面軟件里有個打開瀏覽器獲取cookie的功能, 這個功能C#里可能就是打開一個webview, 然后通過api獲取頁面cookie. 但是在網頁端就很坑了, 放iframe也不行, 畢竟打開的頁面不是可控的, 無法通信, 存在跨域問題.

功能類似上圖

實現(xiàn)代碼: https://github.com/klren0312/cookies-chrome-plugin/edit/master/README.md

原理

如果非要獲取, 只能用瀏覽器插件或者套個Electron, 當然還是用瀏覽器插件啦.瀏覽器插件, 通過右鍵點擊發(fā)送, 可以將獲取的cookie和ua發(fā)送到需要的頁面.

首先插件會在每個頁面創(chuàng)建一個id為'content-block'的DOM, 然后主頁面會通過postMessage, 通知插件獲取主頁面的tabId, 隨后, 進入需要獲取cookieua的頁面, 右鍵獲取, 然后通過之前緩存的主頁面tabId將獲取的cookieua發(fā)送到content.js, content.jscookieua組成的json寫入id為'content-block'的DOM, 主頁面通過mutationObserver監(jiān)聽id為'content-block'的DOM的變化, 觸發(fā)數(shù)據獲取

實現(xiàn)

1. 谷歌瀏覽器插件基本結構

前端內容(content.js), 后臺處理(utils.js), 插件彈框(popup.js, popup.html), 以及配置文件(manifest.json). 前面三個JS文件名稱都是自定義的, 需要在配置文件中配置

2.配置文件

{
  "name": "Cookie與UserAgent獲取",
  "description": "輔助抓取網站登陸后有效Cookies和UserAgent",
  "version": "0.0.3",
  "author": "ZZES",
  "homepage_url": "https://github.com/klren0312/cookies-chrome-plugin",
  "permissions": [
    "contextMenus",
    "tabs",
    "cookies",
    "<all_urls>"
  ],
  "icons": {
    "16": "icon-16.png",
    "48": "icon-48.png",
    "128": "icon-128.png"
  },
  "background": {
    "scripts": [
      "utils.js"
    ]
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "all_frames":true,
    "run_at": "document_start"
  }],
  "browser_action": {
    "default_icon": "icon-16.png",
    "default_title": "Cookie與UserAgent獲取",
    "default_popup": "popup.html"
  },
  "manifest_version": 2
}

主要問題解讀

1. permissions

權限介紹可以查看: https://developer.chrome.com/extensions/permissions

權限, 需要操作一些瀏覽器功能, 就需要列出權限, 比如需要在右鍵菜單使用插件, 就開啟contenMenus; 需要獲取tab頁信息, 就開啟tabs; 需要獲取瀏覽器cookie, 就開啟cookies;最后是插件的應用域名, 這個如果想在所有域名下運用, 就使用<all_urls>

2.background

后臺相關處理腳本, 幕后工作者, 進行一些瀏覽器相關操作

3.content_scripts

前臺相關操作, 比如DOM操作

4.browser_action

就是瀏覽器插件那塊的圖標和彈框


3.background代碼

let mainPageId = null

// 將當前頁面的cookies復制到剪切板
function copyCookies(info, tab) {
  let cookies = ''
  chrome.cookies.getAll({
    url: tab.url
  }, function (cookie) {
    // 遍歷當前域名下cookie, 拼接成字符串
    cookie.forEach(v => {
      cookies += v.name + "=" + v.value + ";"
    })
    // 添加到剪切板
    const input = document.createElement('input')
    input.style.position = 'fixed'
    input.style.opacity = 0
    input.value = cookies
    document.body.appendChild(input)
    input.select()
    document.execCommand('Copy')
    document.body.removeChild(input)
  })
}

// 將當前頁面的UA復制到剪切板
function copyUA () {
  const input = document.createElement('input')
  input.style.position = 'fixed'
  input.style.opacity = 0
  input.value = navigator.userAgent
  document.body.appendChild(input)
  input.select()
  document.execCommand('Copy')
  document.body.removeChild(input)
}

// 發(fā)送Cookies和UA到主頁面
function sendCookieAndUA (info, tab) {
  let cookies = ''
  const ua = navigator.userAgent
  chrome.cookies.getAll({
    url: tab.url
  }, function (cookie) {
    // 遍歷當前域名下cookie, 拼接成字符串
    cookie.forEach(v => {
      cookies += v.name + "=" + v.value + ";"
    })
    // 如果存在主頁面的 tabId, 則將當前頁的cookies發(fā)送給主頁面
    let sendId = mainPageId ? mainPageId : tab.id
    chrome.tabs.sendMessage(sendId, {
      cookies: cookies,
      ua: ua
    }, function(response) {
      console.log(response)
    })
  })
}

// 給popup使用的方法
// 獲取頁面ID
function popupGetTabId () {
  return mainPageId
}
// 清除頁面ID
function popupCleanTabId () {
  mainPageId = null
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    // https://zhuanlan.zhihu.com/p/57820028
    if (request !== 'ok') {
      if (request.type === 'tab') {
        if (request.level === 'main') { // 如果頁面是主頁面, 則將其 tabId 緩存, 并發(fā)送給主頁面
          mainPageId = sender.tab.id
          sendResponse({type: 'tab', level: 'main', tabId: sender.tab.id})
        }
      } else if (request.type === 'cookies') {
        let cookies = ''
        chrome.cookies.getAll({
          url: request.target
        }, function (cookie) {
          // 遍歷當前域名下cookie, 拼接成字符串
          cookie.forEach(v => {
            cookies += v.name + "=" + v.value + ";"
          })
          sendResponse({type: 'cookies', cookies: cookies})
        })
      }

    }
  }
)

var parent = chrome.contextMenus.create({
  "title": "Cookie與UserAgent獲取",
  "contexts": ["page"]
})
var copyCookie = chrome.contextMenus.create({
  "title": "提取Cookies至剪切板",
  "parentId": parent,
  "contexts": ["page"],
  "onclick": copyCookies
})

var copyUA = chrome.contextMenus.create({
  "title": "提取UserAgent至剪切板",
  "parentId": parent,
  "contexts": ["page"],
  "onclick": copyUA
})

var sendCookieAndUA = chrome.contextMenus.create({
  "title": "發(fā)送Cookies和UA到主頁面",
  "parentId": parent,
  "contexts": ["page"],
  "onclick": sendCookieAndUA
})

4.content代碼

(function() {
    document.addEventListener('DOMContentLoaded', function () {
        var div = document.createElement('div')
        div.id = 'cookie-block'
        div.style.display = 'none'
        document.body.appendChild(div);
    })
    chrome.runtime.onMessage.addListener(
        function (request, sender, sendResponse) {
            if (request !== 'ok') {
                document.getElementById('cookie-block').innerText = JSON.stringify(request)
                sendResponse('ok')
            }
        }
    )
})();
window.addEventListener('message', event => {
    if (event.source !== window) {
        return
    }
    // 如果是主頁面發(fā)送message, 則與background通信, 獲取頁面的 tabId
    if (event.data && event.data.hasOwnProperty('type') && event.data.type === 'tab' && event.data.hasOwnProperty('level') && event.data.level === 'main') {
        chrome.runtime.sendMessage({type: 'tab', level: 'main'}, function(response) {
      console.log('收到響應', response)
    })
    }
}, false)

5.功能演示

1.右鍵復制當前頁Cookies

演示圖片


1.gif

2.右鍵復制當前頁UserAgent

演示圖片


2.gif

3.右鍵將Cookies和UserAgent發(fā)送到主頁面
主頁面需要先發(fā)送 message 給插件, 緩存頁面 tabId

window.parent.postMessage({type: 'tab', level: 'main'}, '*');

然后在要獲取Cookie與UserAgent的頁面右鍵選擇"發(fā)送Cookies和UA到主頁面"

演示圖片


3.gif

6.參考資料

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末茵臭,一起剝皮案震驚了整個濱河市额各,隨后出現(xiàn)的幾起案子裂问,更是在濱河造成了極大的恐慌拍霜,老刑警劉巖并村,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顾瞪,死亡現(xiàn)場離奇詭異彻况,居然都是意外死亡名扛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門位喂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浪耘,“玉大人乱灵,你說我怎么就攤上這事塑崖。” “怎么了痛倚?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵规婆,是天一觀的道長。 經常有香客問我蝉稳,道長抒蚜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任耘戚,我火速辦了婚禮嗡髓,結果婚禮上,老公的妹妹穿的比我還像新娘收津。我一直安慰自己饿这,他們只是感情好浊伙,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著长捧,像睡著了一般嚣鄙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上串结,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天哑子,我揣著相機與錄音,去河邊找鬼肌割。 笑死卧蜓,一個胖子當著我的面吹牛,可吹牛的內容都是我干的把敞。 我是一名探鬼主播烦却,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼先巴!你這毒婦竟也來了其爵?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤伸蚯,失蹤者是張志新(化名)和其女友劉穎摩渺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剂邮,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡摇幻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了挥萌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绰姻。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖引瀑,靈堂內的尸體忽然破棺而出狂芋,到底是詐尸還是另有隱情,我是刑警寧澤憨栽,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布帜矾,位于F島的核電站,受9級特大地震影響屑柔,放射性物質發(fā)生泄漏屡萤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一掸宛、第九天 我趴在偏房一處隱蔽的房頂上張望死陆。 院中可真熱鬧,春花似錦唧瘾、人聲如沸措译。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞳遍。三九已至闻妓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掠械,已是汗流浹背由缆。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猾蒂,地道東北人均唉。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像肚菠,于是被迫代替她去往敵國和親舔箭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容