chrome 外掛實現mac地址獲取

qixiaobo發表於2018-01-05

title: chrome 外掛實現mac地址獲取 tags:

  • chrome
  • 外掛
  • 瀏覽器mac地址
  • host
  • 全平臺 categories: chrome date: 2017-07-25 18:18:53

瀏覽器無法通過js獲取到硬體資訊眾所周知,ie是也是通過ActiveX來完成的。

由於我們一直使用Chrome,因此考慮開發chrome外掛。

普通chrome外掛也是無法獲取到mac地址等資訊的,我們採取和本地通訊app的實現。

  1. 準備宿主端,我們稱之為host

  2. 準備外掛端,我們稱之為extension

    121912_l1si_871390.png

    如上圖所示,我們通過外掛端和host進行通訊,外掛也可以通過授權來訪問 指定的頁面的document。在進行指定編碼格式約定後就可以進行我們的編碼了。

    對於chrome的外掛開發我們就不說了,可以在網路上抄到一堆。

    外掛開發

    manifest

        {
          "name": "F6養車PC版安全外掛",
          "version": "1.0",
          "manifest_version": 2,
          "description": "使用本外掛實現從指定PC登入系統",
          "background": {
            "scripts": [
              "background.js"
            ]
          },
          "icons": {
            "128": "icon-128.png"
          },
          "browser_action": {
            "default_icon": "icon-19.png",
            "default_title": "F6養車PC版安全外掛"
          },
          "homepage_url": "http://m.f6car.com",
          "content_scripts": [
            {
              "matches": [
                "http://*/*"
              ],
              "js": [
                "content.js"
              ],
              "run_at": "document_end"
            }
          ],
          "externally_connectable": {
            "matches": [
              "http://*.f6car.com/*",
              "http://localhost:9001/*",
              "http://127.0.0.1:9001/*",
              "http://192.168.1.153:9001/*",
              "http://192.168.1.19:9001/*"
            ]
          },
          "permissions": [
            "nativeMessaging",
            "tabs",
            "http://*/*",
            "https://*/*"
          ]
        }
    複製程式碼

    content.js

    對應後需要增加content.js 負責和頁面dom互動

        chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
            console.debug("chrome.runtime.onMessage called");
            if (!!request.text) {
                console.debug("mac address:%s", request.text);
                var macEle = document.getElementById("mac");
                if (!!macEle) {
                    macEle.value = request.text
                }
            }
        });
    複製程式碼

    brankground.js

    增加和host通訊的background.js

        var port = null;
        var hostName = "com.f6car.chrome.safe.echo";
        var mac = {};
        function connect() {
            port = chrome.runtime.connectNative(hostName);
            port.onMessage.addListener(onNativeMessage);
            port.onDisconnect.addListener(onDisconnected);
        }
         
        function onNativeMessage(message) {
            console.debug("nativemessage:%s",JSON.stringify(message));
            chrome.tabs.query({active: true}, function (tabs) {
                console.debug("tabs:%s",JSON.stringify(tabs));
                chrome.tabs.sendMessage(tabs[0].id, message, function (response) {
                    console.debug("baground  respone");
                });
            });
         
        }
         
        function onDisconnected() {
            port = null;
        }
         
        chrome.runtime.onMessageExternal.addListener(
            function (request, sender, sendResponse) {
                if (request.requestType === "connect") {
                    if (port === null) {
                        connect();
                    }
                }
                else {
                    if (port === null) {
                        connect();
                    }
                    else {
                        if (!!mac.text) {
                            sendResponse(mac);
                        }
                    }
                }
            });
    複製程式碼

    host開發

    許可權配置

    windows

        {
          "name": "com.f6car.chrome.safe.echo",
          "description": "F6養車PC版安全外掛HOST",
          "path": "f6Safe.exe",
          "type": "stdio",
          "allowed_origins": [
            "chrome-extension://fndijacmgfpgicgknoceclheehanolhc/"
          ]
        }
    複製程式碼

    Mac/Linux

        {
          "name": "com.f6car.chrome.safe.echo",
          "description": "F6養車PC版安全外掛HOST",
          "path": "HOST_PATH",
          "type": "stdio",
          "allowed_origins": [
            "chrome-extension://fndijacmgfpgicgknoceclheehanolhc/"
          ]
        }
    複製程式碼

    host編寫

    windows

        #include <stdio.h>
        #include <windows.h>
        #include <string>
        #include <Assert.h>
        #include <iphlpapi.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <cstdlib>
        #include <unistd.h>
        #include <iostream>
         
         
        #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
         
         
        static std::string GetMACaddress(void)
        {
        IP_ADAPTER_INFO AdapterInfo[16];
        // Allocate information for up to 16 NICs
        DWORD dwBufLen = sizeof(AdapterInfo);
        // Save the memory size of buffer
         
         
        DWORD dwStatus = GetAdaptersInfo(
        // Call GetAdapterInfo
        AdapterInfo,  // [out] buffer to receive data
        &dwBufLen);  // [in] size of receive data buffer
        assert(dwStatus == ERROR_SUCCESS);
        // Verify return value is valid, no buffer overflow
         
         
        PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info
        std::string outMsg = "";
        do {
        char acMAC[32];
        sprintf(acMAC, "%02X-%02X-%02X-%02X-%02X-%02X",
        int (pAdapterInfo->Address[0]),
        int (pAdapterInfo->Address[1]),
        int (pAdapterInfo->Address[2]),
        int (pAdapterInfo->Address[3]),
        int (pAdapterInfo->Address[4]),
        int (pAdapterInfo->Address[5]));
        outMsg.append(acMAC);
        outMsg.append(",");
        pAdapterInfo = pAdapterInfo->Next;
        // Progress through linked list
        }
        while(pAdapterInfo);
        if(outMsg.length()>5){
        outMsg = outMsg.substr(0,outMsg.length()-1);
        }
            return outMsg;
        }
         
         
        int main(int argc, _TCHAR* argv[]){
         std::string outMsg = "{\"text\":\""+GetMACaddress()+"\"}";
         unsigned int outLen = outMsg.length();
         char *bOutLen = reinterpret_cast<char *>(&outLen);
         std::cout.write(bOutLen, 4);
         std::cout << outMsg << std::flush;
         return 0;
        }
        ```
    
    ####      Mac/Linux ####
    ```python
        #!/usr/bin/env python
        # Copyright (c) 2012 The Chromium Authors. All rights reserved.
        # Use of this source code is governed by a BSD-style license that can be
        # found in the LICENSE file.
         
        # A simple native messaging host. Shows a Tkinter dialog with incoming messages
        # that also allows to send message back to the webapp.
         
        import Queue
        import struct
        import sys
        import threading
         
        try:
            import Tkinter
            import tkMessageBox
        except ImportError:
            Tkinter = None
         
        # On Windows, the default I/O mode is O_TEXT. Set this to O_BINARY
        # to avoid unwanted modifications of the input/output streams.
        if sys.platform == "win32":
            import os, msvcrt
         
            msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
            msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
         
         
        # Helper function that sends a message to the webapp.
        def send_message(message):
            # Write message size.
            sys.stdout.write(struct.pack('I', len(message)))
            # Write the message itself.
            sys.stdout.write(message)
            sys.stdout.flush()
         
         
        # Thread that reads messages from the webapp.
        def read_thread_func(queue):
            message_number = 0
            while 1:
                # Read the message length (first 4 bytes).
                text_length_bytes = sys.stdin.read(4)
         
                if len(text_length_bytes) == 0:
                    if queue:
                        queue.put(None)
                    sys.exit(0)
         
                # Unpack message length as 4 byte integer.
                text_length = struct.unpack('i', text_length_bytes)[0]
         
                # Read the text (JSON object) of the message.
                text = sys.stdin.read(text_length).decode('utf-8')
         
                if queue:
                    queue.put(text)
                else:
                    # In headless mode just send an echo message back.
                    send_message('{"echo": %s}' % text)
         
         
        if Tkinter:
            class NativeMessagingWindow(Tkinter.Frame):
                def __init__(self, queue):
                    self.queue = queue
         
                    Tkinter.Frame.__init__(self)
                    self.pack()
         
                    self.text = Tkinter.Text(self)
                    self.text.grid(row=0, column=0, padx=10, pady=10, columnspan=2)
                    self.text.config(state=Tkinter.DISABLED, height=10, width=40)
         
                    self.messageContent = Tkinter.StringVar()
                    self.sendEntry = Tkinter.Entry(self, textvariable=self.messageContent)
                    self.sendEntry.grid(row=1, column=0, padx=10, pady=10)
         
                    self.sendButton = Tkinter.Button(self, text="Send", command=self.onSend)
                    self.sendButton.grid(row=1, column=1, padx=10, pady=10)
         
                    self.after(100, self.processMessages)
         
                def processMessages(self):
                    while not self.queue.empty():
                        message = self.queue.get_nowait()
                        if message == None:
                            self.quit()
                            return
                        self.log("Received %s" % message)
         
                    self.after(100, self.processMessages)
         
                def onSend(self):
                    text = '{"text": "' + self.messageContent.get() + '"}'
                    self.log('Sending %s' % text)
                    try:
                        send_message(text)
                    except IOError:
                        tkMessageBox.showinfo('Native Messaging Example',
                                              'Failed to send message.')
                        sys.exit(1)
         
                def log(self, message):
                    self.text.config(state=Tkinter.NORMAL)
                    self.text.insert(Tkinter.END, message + "\n")
                    self.text.config(state=Tkinter.DISABLED)
         
         
        def Main():
            if not Tkinter:
                send_message('"Tkinter python module wasn\'t found. Running in headless ' +
                             'mode. Please consider installing Tkinter."')
                read_thread_func(None)
                sys.exit(0)
         
            queue = Queue.Queue()
         
            main_window = NativeMessagingWindow(queue)
            main_window.master.title('Native Messaging Example')
         
            thread = threading.Thread(target=read_thread_func, args=(queue,))
            thread.daemon = True
            thread.start()
         
            main_window.mainloop()
         
            sys.exit(0)
        def get_mac_address():
            import sys
            import os
            mac = None
            if sys.platform == "win32":
                for line in os.popen("ipconfig /all"):
                    print line
                    if line.lstrip().startswith("Physical Address"):
                        mac = line.split(":")[1].strip().replace("-", ":")
                        break
            else:
                for line in os.popen("/sbin/ifconfig"):
                    if 'Ether' in line or 'ether' in line :
                        mac = line.split()[1].replace(":","-")
                        break
            return mac
        def get_json(message):
            return '{"text": "' +message+ '"}'
        if __name__ == '__main__':
            send_message (get_json(get_mac_address()))
    複製程式碼

    安裝指令碼

    windows

        :: Copyright 2014 The Chromium Authors. All rights reserved.
        :: Use of this source code is governed by a BSD-style license that can be
        :: found in the LICENSE file.
         
        :: Change HKCU to HKLM if you want to install globally.
        :: %~dp0 is the directory containing this bat script and ends with a backslash.
        REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.f6car.chrome.safe.echo" /ve /t REG_SZ /d "%~dp0com.f6car.chrome.safe.echo-win.json" /f
    複製程式碼

    Mac/Linux

        #!/bin/sh
        # Copyright 2013 The Chromium Authors. All rights reserved.
        # Use of this source code is governed by a BSD-style license that can be
        # found in the LICENSE file.
         
        set -e
         
        DIR="$( cd "$( dirname "$0" )" && pwd )"
        if [ "$(uname -s)" = "Darwin" ]; then
          if [ "$(whoami)" = "root" ]; then
            TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts"
          else
            TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
          fi
        else
          if [ "$(whoami)" = "root" ]; then
            TARGET_DIR="/etc/opt/chrome/native-messaging-hosts"
          else
            TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
          fi
        fi
         
        HOST_NAME=com.f6car.chrome.safe.echo
         
        # Create directory to store native messaging host.
        mkdir -p "$TARGET_DIR"
         
        # Copy native messaging host manifest.
        sudo cp "$DIR/$HOST_NAME.json" "$TARGET_DIR"
         
        # Update host path in the manifest.
        HOST_PATH=$DIR/$HOST_NAME
        ESCAPED_HOST_PATH=${HOST_PATH////\\/}
        sudo sed -i -e "s/HOST_PATH/$ESCAPED_HOST_PATH/" "$TARGET_DIR/$HOST_NAME.json"
         
        # Set permissions for the manifest so that all users can read it.
        sudo chmod o+r "$TARGET_DIR/$HOST_NAME.json"
         
        echo "Native messaging host $HOST_NAME has been installed."
    複製程式碼

    以上完成程式碼編寫,打包即可

參考資料:

http://blog.csdn.net/zhangjs712/article/details/50913114

https://developer.chrome.com/extensions/crx

http://bbs.360.cn/forum.php?mod=viewthread&tid=15079033 (本人就相容性問題在360瀏覽器無法安裝)

http://open.se.360.cn/open/extension_dev/overview.html

http://blog.csdn.net/talking12391239/article/details/38498557

developer.chrome.com/extensions/…

具體程式碼可以檢視 碼雲  http://git.oschina.net/qixiaobo/chromeMacGetter

相關文章