commit 984ff6cfce517f15d884f8772510616c9000272d
Author: woni <320753691@qq.com>
Date: Tue Sep 5 22:48:20 2023 +0800
fisrt commit
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..caac5d9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# BotExt
+
+Chrome 插件
diff --git a/app/content-script.js b/app/content-script.js
new file mode 100644
index 0000000..434a7ff
--- /dev/null
+++ b/app/content-script.js
@@ -0,0 +1,27 @@
+
+// declare message listener from inject script
+window.addEventListener('message', (event) => {
+ if (event.source === window && event.data.from === 'inject-script') {
+ console.log('[Demo] receive', event.data);
+
+ }
+});
+
+
+
+chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
+
+
+
+ console.log('[Demo] ==============================================');
+
+ const func = request.func;
+ if (func === 'addRecord') {
+ window.postMessage({ msg: 'ping from content script', from: 'content-script', func: 'addRecord' });
+ }
+ if (func === 'deleteRecord') {
+ window.postMessage({ msg: 'ping from content script', from: 'content-script', func: 'deleteRecord' });
+ }
+ console.log('[Demo] receive', func);
+ sendResponse({ response: '[Demo] pone-pone from content script' });
+});
diff --git a/app/index.html b/app/index.html
new file mode 100644
index 0000000..1715aa3
--- /dev/null
+++ b/app/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ WpsDbSheet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/index.js b/app/index.js
new file mode 100644
index 0000000..7026a25
--- /dev/null
+++ b/app/index.js
@@ -0,0 +1,86 @@
+const DYNAMIC_SCRIPT_ID = 'add-record-script';
+
+async function isDynamicContentScriptRegistered() {
+ const scripts = await chrome.scripting.getRegisteredContentScripts();
+ return scripts.some((s) => s.id === DYNAMIC_SCRIPT_ID);
+}
+
+async function getActiveTab() {
+ const [tab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
+ return tab;
+}
+
+
+document.querySelector('#addRecord').addEventListener('click', async () => {
+
+ console.log('[Demo] ==============================================');
+ console.log('[Demo] Test send message from popup script to content script');
+ const tab = await getActiveTab();
+ const ret = await chrome.tabs.sendMessage(tab.id, { msg: 'ping from popup script', func: 'addRecord' });
+ console.log('[Demo] receive', ret);
+
+});
+
+
+document.querySelector('#deleteRecord').addEventListener('click', async () => {
+
+ console.log('[Demo] ==============================================');
+ console.log('[Demo] Test send message from popup script to content script');
+ const tab = await getActiveTab();
+ const ret = await chrome.tabs.sendMessage(tab.id, { msg: 'ping from popup script', func: 'deleteRecord' });
+ console.log('[Demo] receive', ret);
+
+});
+
+
+var port = null;
+
+function appendMessage(text) {
+ document.getElementById('response').innerHTML += "" + text + "
";
+}
+
+function updateUiState() {
+ if (port) {
+ document.getElementById('connect-button').style.display = 'none';
+ document.getElementById('input-text').style.display = 'block';
+ document.getElementById('send-message-button').style.display = 'block';
+ } else {
+ document.getElementById('connect-button').style.display = 'block';
+ document.getElementById('input-text').style.display = 'none';
+ document.getElementById('send-message-button').style.display = 'none';
+ }
+}
+
+function sendNativeMessage() {
+ message = { "text": document.getElementById('input-text').value };
+ port.postMessage(message);
+ appendMessage("Sent message: " + JSON.stringify(message) + "");
+}
+
+function onNativeMessage(message) {
+ appendMessage("Received message: " + JSON.stringify(message) + "");
+}
+
+function onDisconnected() {
+ appendMessage("Failed to connect: " + chrome.runtime.lastError.message);
+ port = null;
+ updateUiState();
+}
+
+function connect() {
+ var hostName = "com.google.chrome.botext";
+ appendMessage("Connecting to native messaging host " + hostName + "")
+ port = chrome.runtime.connectNative(hostName);
+ port.onMessage.addListener(onNativeMessage);
+ port.onDisconnect.addListener(onDisconnected);
+ updateUiState();
+}
+
+document.addEventListener('DOMContentLoaded', function () {
+ document.getElementById('connect-button').addEventListener(
+ 'click', connect);
+ document.getElementById('send-message-button').addEventListener(
+ 'click', sendNativeMessage);
+ updateUiState();
+});
+
diff --git a/app/manifest.json b/app/manifest.json
new file mode 100644
index 0000000..0c3a06d
--- /dev/null
+++ b/app/manifest.json
@@ -0,0 +1,52 @@
+{
+ "name": "BotExt",
+ "version": "0.1.0",
+ "manifest_version": 3,
+ "background": {
+ "service_worker": "sw.js"
+ },
+ "content_scripts": [
+ {
+ "matches": [
+ "https://www.kdocs.cn/*"
+ ],
+ "js": [
+ "content-script.js"
+ ],
+ "run_at": "document_end"
+ },
+ {
+ "matches": [
+ ""
+ ],
+ "js": [
+ "wps.js"
+ ],
+ "run_at": "document_end",
+ "world": "MAIN"
+ }
+ ],
+ "permissions": [
+ "scripting",
+ "webNavigation",
+ "storage",
+ "activeTab",
+ "nativeMessaging"
+ ],
+ "host_permissions": [
+ "https://www.kdocs.cn/*"
+ ],
+ "action": {
+ "default_popup": "index.html"
+ },
+ "web_accessible_resources": [
+ {
+ "resources": [
+ "wps.js"
+ ],
+ "matches": [
+ ""
+ ]
+ }
+ ]
+}
diff --git a/app/sw.js b/app/sw.js
new file mode 100644
index 0000000..8e493ad
--- /dev/null
+++ b/app/sw.js
@@ -0,0 +1,24 @@
+function injectedFunction(color) {
+ document.body.style.backgroundColor = color;
+}
+
+
+chrome.runtime.onMessage.addListener(async ({ name, options }) => {
+ if (name === 'addRecord') {
+ console.log('Hello World!');
+
+ // get active tab
+ // const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
+ // chrome.scripting.executeScript({
+ // target: { tabId: tab.id },
+ // func: injectedFunction,
+ // args: ["orange"],
+ // });
+
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
+ const response = await chrome.tabs.sendMessage(tab.id, { greeting: "hello" });
+ // do something with response here, not outside the function
+ console.log(response);
+
+ }
+});
diff --git a/app/wps.js b/app/wps.js
new file mode 100644
index 0000000..91dca1c
--- /dev/null
+++ b/app/wps.js
@@ -0,0 +1,69 @@
+
+async function createApp() {
+ for (let i = 0; i < 10; i++) {
+
+ try {
+ window.$dbSheet = {};
+ // set dbsheet app 属性 为 WPSOpenApi.Application;
+ window.$dbSheet.app = WPSOpenApi.Application;
+
+ $dbSheet.createRecords = () => {
+ const records = $dbSheet.app.Record.CreateRecords({
+ SheetId: 1,
+ Records: [{ fields: { "名称": "demo", "数量": 1, "日期": "2022/1/1", "状态": "未开始" } }]
+ });
+ }
+
+ $dbSheet.deleteRecords = async () => {
+
+ const records = await $dbSheet.app.Record.GetRecords({ SheetId: 1 })
+ const deleteRcecordId = records.records[0].id
+ const result = $dbSheet.app.Record.DeleteRecords({
+ SheetId: 1,
+ RecordIds: [deleteRcecordId]
+ })
+ }
+ console.log(i);
+ } catch (error) {
+ // sleep 1s
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ console.log(i, error);
+ }
+ }
+}
+
+// 异步执行 createApp
+
+createApp().then(() => { });
+
+window.addEventListener('message', (event) => {
+ if (event.source === window && event.data.func === 'addRecord') {
+ // console.log('[Demo] receive', event.data);
+ addRecordOnMessage();
+ }
+
+ if (event.source === window && event.data.func === 'deleteRecord') {
+ // console.log('[Demo] receive', event.data);
+ deleteRecordOnMessage();
+ }
+});
+
+
+async function addRecordOnMessage() {
+ $dbSheet.createRecords();
+ window.postMessage({ msg: 'add record by inject script', from: 'inject-script' });
+}
+
+
+async function deleteRecordOnMessage() {
+ await $dbSheet.deleteRecords();
+ window.postMessage({ msg: 'delete record by inject script', from: 'inject-script' });
+}
+
+
+async function sendMsgToContentScript() {
+ console.log('[Demo] ==============================================');
+ console.log('[Demo] Test send message from inject script to content script');
+ $dbSheet.createRecords();
+ window.postMessage({ msg: 'ping from inject script', from: 'inject-script' });
+}
diff --git a/host/botext.bat b/host/botext.bat
new file mode 100644
index 0000000..13a64f1
--- /dev/null
+++ b/host/botext.bat
@@ -0,0 +1,4 @@
+@echo off
+
+
+python "%~dp0/native-messaging-example-host" %*
diff --git a/host/client.py b/host/client.py
new file mode 100644
index 0000000..634982e
--- /dev/null
+++ b/host/client.py
@@ -0,0 +1,19 @@
+import win32pipe
+import win32file
+
+# 连接到命名管道
+pipe_name = r'\\.\pipe\botext'
+pipe = win32file.CreateFile(
+ pipe_name,
+ win32file.GENERIC_READ | win32file.GENERIC_WRITE,
+ 0,
+ None,
+ win32file.OPEN_EXISTING,
+ 0,
+ None
+)
+
+win32file.WriteFile(pipe, b'close1')
+
+# 关闭管道
+win32file.CloseHandle(pipe)
diff --git a/host/com.google.chrome.botext.json b/host/com.google.chrome.botext.json
new file mode 100644
index 0000000..6bb7b9e
--- /dev/null
+++ b/host/com.google.chrome.botext.json
@@ -0,0 +1,9 @@
+{
+ "name": "com.google.chrome.botext",
+ "description": "botext",
+ "path": "D:\\rust\\botext\\target\\debug\\botext.exe",
+ "type": "stdio",
+ "allowed_origins": [
+ "chrome-extension://hbneoijjlheddhhonbkamdmgljmjcdom/"
+ ]
+}
diff --git a/host/install_host.bat b/host/install_host.bat
new file mode 100644
index 0000000..6b4de40
--- /dev/null
+++ b/host/install_host.bat
@@ -0,0 +1,7 @@
+:: 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.google.chrome.botext" /ve /t REG_SZ /d "%~dp0com.google.chrome.botext.json" /f
diff --git a/host/native-messaging-example-host b/host/native-messaging-example-host
new file mode 100644
index 0000000..f14e005
--- /dev/null
+++ b/host/native-messaging-example-host
@@ -0,0 +1,82 @@
+import sys
+import struct
+import ctypes
+import threading
+import win32pipe
+import win32file
+
+
+pipe_name = r"\\.\pipe\botext"
+pipe_access = win32pipe.PIPE_ACCESS_DUPLEX
+pipe_type =win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT | win32pipe.PIPE_READMODE_MESSAGE
+pipe_mode = win32pipe.PIPE_UNLIMITED_INSTANCES
+max_instances = 65536
+out_buffer_size = 65536
+default_time_out = 0
+security_attributes = None
+
+
+pipe = win32pipe.CreateNamedPipe(
+ pipe_name,
+ pipe_access,
+ pipe_type,
+ pipe_mode,
+ max_instances,
+ out_buffer_size,
+ default_time_out,
+ security_attributes,
+)
+
+
+def write_data(data):
+ msglen = len(data)
+ msglen_bytes = struct.pack("=I", msglen)
+ sys.stdout.buffer.write(msglen_bytes)
+ sys.stdout.buffer.write(data.encode())
+ sys.stdout.buffer.flush()
+
+
+def read_thread_func():
+ while True:
+ raw_msglen = sys.stdin.buffer.read(4)
+ if not raw_msglen:
+ sys.exit(0)
+ msglen = struct.unpack("=I", raw_msglen)[0]
+
+ # Read the message data
+ data = sys.stdin.buffer.read(msglen)
+ ctypes.windll.user32.MessageBoxW(0, data.decode(), "BotExt", 0)
+ write_data('{"msg": "bridge"}')
+
+
+def namepipe_server(pipe):
+ try:
+ while True:
+ win32pipe.ConnectNamedPipe(pipe, None)
+ _, data = win32file.ReadFile(pipe, 4096)
+ if data == b"close":
+ sys.exit(0)
+ print(data)
+ write_data('{"msg": "client"}')
+ # ctypes.windll.user32.MessageBoxW(0, "hi", "BotExt", 0)
+ win32pipe.DisconnectNamedPipe(pipe)
+ except Exception as e:
+ win32pipe.DisconnectNamedPipe(pipe)
+ finally:
+ win32file.CloseHandle(pipe)
+
+
+def namepipe_server_forver(pipe):
+ while True:
+ namepipe_server(pipe)
+
+
+if __name__ == "__main__":
+ thread = threading.Thread(target=read_thread_func)
+ thread2 = threading.Thread(target=namepipe_server_forver, args=(pipe,))
+ thread.daemon = True
+ thread2.daemon = True
+ thread.start()
+ thread2.start()
+ thread.join()
+ thread2.join()
diff --git a/host/native-messaging-example-host copy b/host/native-messaging-example-host copy
new file mode 100644
index 0000000..5543a4e
--- /dev/null
+++ b/host/native-messaging-example-host copy
@@ -0,0 +1,112 @@
+import struct
+import sys
+import threading
+from queue import Queue
+
+
+import tkinter as Tkinter
+from tkinter import messagebox as tkMessageBox
+
+if sys.platform == "win32":
+ import os, msvcrt
+
+ msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+
+
+def send_message(message):
+ sys.stdout.write(str(len(message)))
+ sys.stdout.write(message)
+ sys.stdout.flush()
+
+
+def read_thread_func(queue):
+ message_number = 0
+ while 1:
+ text_length_bytes = sys.stdin.read(4)
+ if len(text_length_bytes) == 0:
+ if queue:
+ queue.put(None)
+ sys.exit(0)
+
+ text_length = struct.unpack("i", text_length_bytes)[0]
+ text = sys.stdin.read(text_length).decode("utf-8")
+
+ if queue:
+ queue.put(text)
+ else:
+ 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()
+
+ 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)
+
+
+if __name__ == "__main__":
+ Main()
diff --git a/host/server.py b/host/server.py
new file mode 100644
index 0000000..f720306
--- /dev/null
+++ b/host/server.py
@@ -0,0 +1,55 @@
+# python windows namepipe serve
+
+import win32pipe, win32file
+import json
+import threading
+import sys
+import ctypes
+
+# 连接到命名管道
+pipe_name = r"\\.\pipe\botext"
+pipe_access = win32pipe.PIPE_ACCESS_DUPLEX
+pipe_type = win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT
+pipe_mode = 1
+max_instances = 65536
+out_buffer_size = 65536
+default_time_out = 0
+security_attributes = None
+
+pipe = win32pipe.CreateNamedPipe(
+ pipe_name,
+ win32pipe.PIPE_ACCESS_DUPLEX,
+ win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT | win32pipe.PIPE_READMODE_MESSAGE,
+ win32pipe.PIPE_UNLIMITED_INSTANCES,
+ 65535,
+ 65535,
+ 0,
+ None,
+)
+
+
+def namepipe_server(pipe):
+ try:
+ while True:
+ win32pipe.ConnectNamedPipe(pipe, None)
+ _, data = win32file.ReadFile(pipe, 4096)
+ if data == b'close':
+ sys.exit(0)
+ print(data)
+ ctypes.windll.user32.MessageBoxW(0, "hi", "BotExt", 0)
+ win32pipe.DisconnectNamedPipe(pipe)
+ except Exception as e:
+ win32pipe.DisconnectNamedPipe(pipe)
+ finally:
+ win32file.CloseHandle(pipe)
+
+def namepipe_server_forver(pipe):
+ while True:
+ namepipe_server(pipe)
+
+
+if __name__ == "__main__":
+ task = threading.Thread(target=namepipe_server, args=(pipe,))
+ task.daemon = True
+ task.start()
+ task.join()
diff --git a/host/uninstall_host.bat b/host/uninstall_host.bat
new file mode 100644
index 0000000..ca15585
--- /dev/null
+++ b/host/uninstall_host.bat
@@ -0,0 +1,7 @@
+:: 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.
+
+:: Deletes the entry created by install_host.bat
+REG DELETE "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.botext" /f
+REG DELETE "HKLM\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.botext" /f