问题
I'm trying to write a simple parental control app for my university project, but I'm a newbie in browser addons. I want to use Chrome addon to send hosts viewed by the user in real-time to Qt app, which will analyze the user behavior. The problem is, that sometimes chrome's sending a correct host, another time it's sending trash with an empty string or enormously long message, which my Qt app filter. But these 'wrong' messages are sent in an endless loop, and to make it working again, I have to restart extension or chrome or even whole PC.
Chrome addon manifest:
{
"name": "AM Chrome addon",
"version": "0.7",
"description": "Get your activity supervised!",
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"permissions": [
"tabs",
"nativeMessaging",
"background"
],
"manifest_version": 2
}
Addon background.js file:
var current = undefined;
var port = null;
tryConnectagain();
function tryConnectagain() {
port = chrome.runtime.connectNative('<Native host app-name>');
port.onDisconnect.addListener(onDisconnect);
}
function onDisconnect() {
port = null;
console.log("last error: ", chrome.runtime.lastError.message);
setTimeout(tryConnectagain, 1000);
}
function sendMessageToNativeApp(message) {
if (port != null) port.postMessage({ message: message });
}
function newUrl(u) {
if (u != undefined && !u.includes(current) && !u.includes("chrome-extension://") && u.includes('.')) {
var u = new URL(u);
var domain = u.hostname.replace("www.", "");
if (domain != current) {
current = domain;
sendMessageToNativeApp(current);
console.log(current);
}
}
else if (current != "NotURL") {
current = "NotURL";
sendMessageToNativeApp(current);
console.log(current);
}
}
// Here I'm trying to intercept all URL change situations
chrome.tabs.onActivated.addListener(function (activeInfo) {
chrome.tabs.get(activeInfo.tabId, function (tab) {
if (tab.active && tab.highlighted) newUrl(tab.url);
});
});
chrome.tabs.onAttached.addListener(function (tabId, attachInfo) {
chrome.tabs.get(tabId, function (tab) {
if (tab.active && tab.highlighted) newUrl(tab.url);
});
});
chrome.tabs.onReplaced.addListener(function (addedTabId, removedTabId) {
chrome.tabs.get(addedTabId, function (tab) {
if (tab.active && tab.highlighted) newUrl(tab.url);
});
});
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.url && tab.active && tab.highlighted) newUrl(changeInfo.url);
});
chrome.windows.onFocusChanged.addListener(function (windowId) {
if (windowId > -1) {
var getInfo = { populate: true, windowTypes: ['normal'] };
chrome.windows.getLastFocused(getInfo, function (window) {
for (var t = 0; t < window.tabs.length; t++) {
if (window.tabs[t].active && window.tabs[t].highlighted) {
newUrl(window.tabs[t].url);
break;
}
}
})
}
});
Native host app manifest:
{
"name": "<Native host app-name>",
"description": "Hostname Identifier",
"path": "<Hostname app Path>",
"type": "stdio",
"allowed_origins": [
"chrome-extension://<extension-ID>/"
]
}
And a fragment of c++ qt code that receive data from addon: addonmessagereceiver.h:
#ifndef ADDONMESSAGERECEIVER_H
#define ADDONMESSAGERECEIVER_H
#include <qthread.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <iostream>
#include <string>
class AddonMessageReceiver : public QThread
{
Q_OBJECT
public:
void run();
signals:
void UpdateMessage(const QString &);
};
#endif // ADDONMESSAGERECEIVER_H
addonmessagereceiver.cpp:
#include "addonmessagereceiver.h"
#include <qdebug.h>
using namespace std;
void AddonMessageReceiver::run()
{
do{
char nextMessageLen[4];
cin.read(nextMessageLen, 4);
unsigned long int messageLength = *reinterpret_cast<unsigned long int *>(nextMessageLen);
qDebug() << messageLength << static_cast<int>(nextMessageLen[0]) << static_cast<int>(nextMessageLen[1]) << static_cast<int>(nextMessageLen[2]) << static_cast<int>(nextMessageLen[3]);
if(messageLength<1024 && messageLength>1)
{
char *incomingMessage = new char[messageLength+1];
memset(incomingMessage,'\0',messageLength+1);
cin.read(incomingMessage, messageLength);
QString message = QString::fromLatin1(incomingMessage);
delete[] incomingMessage;
qDebug() << messageLength << message;
if(message.length()>5)
{
QJsonDocument json = QJsonDocument::fromJson(message.toLatin1());
QJsonObject obj = json.object();
QString host = obj.value("message").toString();
emit UpdateMessage(host);
}
}
QThread::msleep(100);
}while(true);
}
Example of qDebug wrong nextMessageLen in loop:
And an example of good input that turns into wrong in a loop:
Can you please tell me what is going on with that extension or chrome, or what I f... up with native app? Thank you for your answer.
回答1:
Based on this answer I have built a class that monitors "stdin", get the text and decode it using QFile:
nativemessenger.h
#ifndef NATIVEMESSENGER_H
#define NATIVEMESSENGER_H
#include <QObject>
#include <QFile>
class NativeMessenger : public QObject
{
Q_OBJECT
public:
explicit NativeMessenger(QObject *parent = nullptr);
public Q_SLOTS:
void sendMessage(const QByteArray & message);
Q_SIGNALS:
void messageChanged(const QByteArray & message);
private Q_SLOTS:
void readyRead();
private:
QFile m_qin;
QFile m_qout;
};
#endif // NATIVEMESSENGER_H
nativemessenger.cpp
#include "nativemessenger.h"
#include <QCoreApplication>
#ifdef Q_OS_WIN
#include <QWinEventNotifier>
#include <windows.h>
#else
#include <QSocketNotifier>
#endif
NativeMessenger::NativeMessenger(QObject *parent) : QObject(parent)
{
#ifdef Q_OS_WIN
// https://developer.chrome.com/apps/nativeMessaging#native-messaging-debugging
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
#endif
m_qin.open(stdin, QIODevice::ReadOnly | QIODevice::Unbuffered);
m_qout.open(stdout, QIODevice::WriteOnly);
#ifdef Q_OS_WIN
QWinEventNotifier *m_notifier = new QWinEventNotifier(GetStdHandle(STD_INPUT_HANDLE));
connect(m_notifier, &QWinEventNotifier::activated, this, &NativeMessenger::readyRead);
#else
QSocketNotifier *m_notifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated, this, &NativeMessenger::readyRead);
#endif
}
void NativeMessenger::sendMessage(const QByteArray &message){
quint32 len = message.length();
m_qout.write(reinterpret_cast<char *>(&len), sizeof(len));
m_qout.write(message);
m_qout.flush();
}
void NativeMessenger::readyRead(){
m_qin.startTransaction();
quint32 length = 0;
qint64 rc = m_qin.read(reinterpret_cast<char *>(&length), sizeof(quint32));
if (rc == -1) {
m_qin.rollbackTransaction();
return;
}
QByteArray message = m_qin.read(length);
if (message.length() != int(length)) {
m_qin.rollbackTransaction();
return;
}
if (message.isEmpty()) {
m_qin.rollbackTransaction();
return;
}
m_qin.commitTransaction();
Q_EMIT messageChanged(message);
}
main.cpp
#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
#include "nativemessenger.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
NativeMessenger listener;
QObject::connect(&listener, &NativeMessenger::messageChanged,
[&listener]
(const QByteArray & message){
// decode message
QJsonParseError error;
QJsonDocument json = QJsonDocument::fromJson(message, &error);
if(error.error != QJsonParseError::NoError){
qDebug() << error.errorString();
}
// build response
QJsonObject object
{
{"data", json.object()},
{"name", QCoreApplication::applicationName()}
};
QByteArray response = QJsonDocument(object).toJson(QJsonDocument::Compact);
// send response
listener.sendMessage(response);
});
return a.exec();
}
A complete example can be found here.
来源:https://stackoverflow.com/questions/59336957/chrome-addon-is-randomly-sending-trash-to-my-c-native-host-application