Sending byte[] array to Host using Chrome Native Messaging - streamreader

I am trying to send a JSON object that contains a byte[] to a "Console Application" using a Chrome Extention by NativeMessaging.
I have no problems with some of the calls, but I get a problem when I try to send a byte array.
Behavior is following:
ChromeExtention creates a JSON object that contains a list and a byte[].
NativeApp receives it but remains somehow blocked.
reader.Read(buffer, 0, buffer.Length);
I will post here a version of code that I hope it helps.
Native App.
Program.cs
public static void Main(string[] args)
{
m_Logger = LogManager.Setup().GetCurrentClassLogger();
m_Logger.Info("App Started!");
try
{
JObject command = Read();
if (command != null)
{
var ceCommand = command.ToObject<CommandModel>();
if (ceCommand == null)
{
m_Logger.Warn("Could not deserialize command from extention");
return;
}
//do other things
}
}
}
catch (Exception ex)
{
throw;
}
}
public static JObject Read()
{
try
{
m_Logger.Debug("Read started");
var stdin = Console.OpenStandardInput();
m_Logger.Debug("StDin initialized");
var length = 0;
var lengthBytes = new byte[4];
stdin.Read(lengthBytes, 0, 4);
length = BitConverter.ToInt32(lengthBytes, 0);
m_Logger.Debug($"Message length: {length}");
var buffer = new char[length];
m_Logger.Debug($"Buffer lenght: {buffer.Length}");
using (var reader = new StreamReader(stdin))
{
m_Logger.Debug("Reading from stream...");
while (reader.Peek() >= 0)
{
m_Logger.Debug("We are in reading process...please wait");
int result = reader.Read(buffer, 0, buffer.Length);
m_Logger.Debug($"Read {result} numer of chars");
}
m_Logger.Debug("Read finished");
}
var stringMessage = new string(buffer);
m_Logger.Info($"Recieved from CE {stringMessage}");
return JsonConvert.DeserializeObject<JObject>(stringMessage);
}
catch (Exception ex)
{
m_Logger.Error(ex, $"Error at reading input data");
return null;
}
}
public static void Write(JToken data)
{
var json = new JObject();
json["data"] = data;
var bytes = System.Text.Encoding.UTF8.GetBytes(json.ToString(Formatting.None));
var stdout = Console.OpenStandardOutput();
stdout.WriteByte((byte)((bytes.Length >> 0) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 8) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 16) & 0xFF));
stdout.WriteByte((byte)((bytes.Length >> 24) & 0xFF));
stdout.Write(bytes, 0, bytes.Length);
stdout.Flush();
}
/// <summary>
/// Copies the contents of input to output. Doesn't close either stream.
/// </summary>
public static string ByteToString(byte[] array, int count)
{
char[] chars = Encoding.UTF8.GetChars(array, 0, count);
return new string(chars);
}
I deducted that the problem is at reader.Read(buffer, 0, buffer.Length); based on logs that look like this
2022-11-17 16:34:14.9604 INFO App Started!
2022-11-17 16:34:15.0837 DEBUG Read started
2022-11-17 16:34:15.0837 DEBUG StDin initialized
2022-11-17 16:34:15.0837 DEBUG Message length: 1862
2022-11-17 16:34:15.0837 DEBUG Buffer lenght: 1862
2022-11-17 16:34:15.0837 DEBUG Reading from stream...
2022-11-17 16:34:15.0837 DEBUG We are in reading process...please wait
2022-11-17 16:34:15.0837 DEBUG Read 1862 numer of chars
2022-11-17 16:34:44.2786 DEBUG Read finished
2022-11-17 16:34:44.2787 DEBUG Message length: 0
2022-11-17 16:34:44.2787 DEBUG Buffer lenght: 0
2022-11-17 16:34:44.2786 INFO Recieved from CE {"CommandId":2,"CommandValue":"{\"ImportCertificates\":[],\"byteArray\":\"MIIKWAIBAzCCChQGCSqGSIb3DQEHAaCCCgUEggoBMIIJ/TCCBe4GCSqGSIb3DQEHAaCCBd8EggXbMIIF1zCCBdMGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAjslY0EWPiyRwICB9AEggTItTgbudKRaEBCdOn1rMgGUoGjVIOxTgT/5Oo5D0gfBe/0yorvQKenVimcfDmWCXZGlsvou5Km7g3yjmK7PTZh3IUuX86bJeyECrJBZa+4ZXyrbkVV7R2GEwy99ACOkevHxBZ7H6deVKdRFDsCSC+cdLpsSGoNNi3Coowqw8i7lzXDPzph64L2Rre7cky/QJdkXKIEUGjxKYUR4cpOOmlLXfbQMR3fOChT5FrxbOnTRTAvVELtwFTh8Gxq55Et8rLgIktQ2eL8FIx43sGspukhZvm5bH05aEwVz5df0T3e3cMsZ13t4oc72phNKx9HiZmPvmi4lUdBwn6qXEJSRg+P5MWGD41StCAoZ/pDtMTPSV5DalLpDpKF6XfxByOSXfn27KYWFZoiEdxCmabS7eomqeD03uWEzWbgPW1hha69Bg1DcmSYZgDfISugtow6p+ozQSjaNnELlbz1SsiBMPbkoNj944IxSKkHgfiqwOyQm3JqHGjDH6Hp9OB3RyuQHoeWLrW9ulmWvnT/Dn+LC0T26YHeVeTO30U86r9ElBiv4iXa5JdflWqFecbjQC1Xs29yBkkFRNrfgJ4Txd/xOz0rhzFxZmcIwiJsQgh+WxSWLG3em02xmtyO7Rcxc6g+onVpEFXKiaYDqTWNDKE2wDSDPZauheyiiluj42gi5A086rSjuqqyidzWQb6FKYs73ZUM8drnYK36RT7zG8TFpV3RdrXbnui8eFRZ4bFHNlptHTwvqpZY/sDDP1R1q1EgrckMbZhOpHhKW/1GRd95eHlSGJPdTROtR3uEARZD0+1zBarw68p1k650DWua88cMrOQPKH1X8Ce++KIdFG2RtfI2P3lhPsD0gdpet0gDEC1peUXfrZVQYD3G8IfEjpYgDpgPa6zjblScidem628MPz4dnTnWrp1S7P2ILlGYinb9uCzSR17IvPoVITQvXk9KpTp1uzuWTnRQHMfUyNvgjHSAOwt3bmx5kEyC/04ujhUvQkiyPMCrDtiO/fLYkrWuqOLNr74l/VAJYU06YR7yNMfG1kEpRYkf96v0s3XK1tZEQBt26lZFPIMl/NOHYpbCfxCGZkpOGIFDojjo72p4VUuyGD/MZ41B99jcNVB2/Sqmc9XwALl/jjkJz6+aCmvLUePeLmhg2Bxrjkmf8iDfDnKByXM5lam3D\"}","SessionKey":"QXCUUKNB0T"}
2022-11-17 16:34:44.2787 DEBUG Reading from stream...
2022-11-17 16:34:44.2787 DEBUG Read finished
2022-11-17 16:34:44.2787 INFO Recieved from CE
However this is not a problem if
byteArray property is smaller in size
2022-11-17 16:32:49.7558 INFO App Started!
2022-11-17 16:32:49.8809 DEBUG Read started
2022-11-17 16:32:49.8809 DEBUG StDin initialized
2022-11-17 16:32:49.8809 DEBUG Message length: 546
2022-11-17 16:32:49.8809 DEBUG Buffer lenght: 546
2022-11-17 16:32:49.8809 DEBUG Reading from stream...
2022-11-17 16:32:49.8809 DEBUG We are in reading process...please wait
2022-11-17 16:32:49.8809 DEBUG Read 546 numer of chars
2022-11-17 16:32:49.8809 DEBUG Read finished
2022-11-17 16:32:49.8809 INFO Recieved from CE {"CommandId":2,"CommandValue":"{\"ImportCertificates\":[],\"byteArray\":\"test/wqewq+./qweqeq//eqwq\"}","SessionKey":"0SZFlRVrQR"}
As you can see here from logs app does the full flow without a problem from Starting and reading and parsing my message.
I suspected that is something regarding the size of the array, but from what I've read you can send up to 1mb of data in one NativeMessage call, data that I want to send is about 4Kb.
Not even close to the max allowed size.
Any ideas on what I am doing wrong?
I will post here also the Javascript code that send this, but I don't believe problem relies in Javascript code.
export const syncCertificates = async () => {
var requestToHost = await api.getInfo();
var responsefromHost = await nativeService.syncCertificates(requestToHost);
return certUploadResponse;
}
export const syncCertificates = async (certs) => {
var command = commands[1];
await sendNativeMessageV2(command.Id, certs);
}
async function sendNativeMessageV2(command, commandValue) {
commandInProgress = command;
var sessionKey = await storage.getSessionKey();
var message =
{
"CommandId": command,
"CommandValue": JSON.stringify(commandValue),
"SessionKey": sessionKey
}
return new Promise((resolve, reject) => {
chrome.runtime.sendNativeMessage('com.allianz.usercertificateautoenrollment', message,
async function (result) {
var response = await onNativeMessage(result);
resolve(response);
}
);
});
}

After more investigations I found this Why is my C# native messaging host hanging when reading a message sent by a Firefox browser extension?
Changing the loop as answered here did the trick.
Change the loop as follows:
using (var reader = new StreamReader(stdin))
{
var offset = 0;
while (offset < length && reader.Peek() >= 0)
{
offset += reader.Read(buffer, offset, length - offset);
}
}

Related

Native Messaging stops working after receiving chunked response

I made two extensions, one for firefox and one for chrome(will post only firefox code here, if it is necessary to post Chrome code, let me know, but it is extremely similar) that has some actions, calls to native host app. One of this calls returns a message with > 1 mb. According to https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging, "The maximum size of a single message from the application is 1 MB". According to chrome native messaging: how to receive > 1MB, data > 1mb must be chunked into less than 1 mb data and sent as many chunks. I Made a Java host app, and made a solution to chunk data. The data is chunked and many responses are sent, each with a chunk in a json string. The sending and responses worked ok, the messages are joined in an input of the web page, and the action works. However, after making this action, any other call fail. If I go to windows task manager, and kill the native host process, everything works again. If I do the action that gets chunked response, it works again, but next calls fail silently, firefox browser console gives me nothing. I guess there is something wrong with my solution. The actions work. When I do the action that receives more than 1 mb, the action works, but after that no other action work again. Any help is appreciated. Tell me if the question is not clear, or is a big mess, I will improve it. I did everythink I could to make it work, and it works, but oddly only one time, then it fails and do nothing. Sorry, but I can't say what the actions are, i mean, what im tryng to do, if it is realy necessary to know, I will ask my manager to explain it here.
Background.js
function sendNativeMessage(message) {
port.postMessage(message);
}
function onDisconnected() {
msg = '{"message": "Failed to connect: '+browser.runtime.lastError+'"}';
browser.tabs.query({active: true, currentWindow: true}, function(tabs){
browser.tabs.sendMessage(tabs[0].id, msg, function(response) {});
});
port = null;
}
function connect() {
var hostName = "com.companyname.hostname";
port = browser.runtime.connectNative(hostName);
port.onMessage.addListener(function(msg) {
browser.tabs.query({active: true, currentWindow: true}, function(tabs){
browser.tabs.sendMessage(tabs[0].id, JSON.stringify(msg), function(response) {});
});
});
port.onDisconnect.addListener(onDisconnected);
}
browser.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (port == null) {
connect();
}
sendNativeMessage(request);
});
Inject.js
//Prevent code being injected twice(probably because of click listeners on web page)
if (document.readyState !== "complete") {
browser.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
var obj = JSON.parse(msg);
if (!obj.success) {
(...)
}
if (obj.action == "doSomething") {
if (obj.last == "true") {
do something
}else {
var value = $("#input").val().trim() + obj.value.trim();
$("#input").val(value.trim());
}
}
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = browser.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
}
script.js
class extensionName{
getValues() {
window.postMessage({ type: "FROM_PAGE", text: {action: "getValues"} }, "*");
}
//This is the function that returns more than 1 mb.
dosomething(parameter1,parameter2,parameter3,parameter4) {
window.postMessage({ type: "FROM_PAGE", text: {action: "dosomething",parameter1Key:parameter1,parameter2Key:parameter2,parameter3Key:parameter3,parameter4Key:parameter4} }, "*");
}
}
Native app in Java (aux is an instance of an auxiliary class that has a sendMessage function that sends messages according to the native messaging protocol)
switch (parameter1) {
case "getValues":
json = functions.getValues();
aux.sendMessage(json);
break;
case "doSomething":
funcoes.doSomething(...);
break;
(...)
public String doSomething(...) {
(...)
Matcher m = Pattern.compile(".{1,565048}").matcher(valueMoreThan1Mb);
String chunk = "";
while(m.find()) {
System.setOut(originalStream);//let stream output values
chunk = newSignatureBase64.substring(m.start(), m.end());
//a json is done here, with needed parameters, action, chunked value.
json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"false\",\"value\":\""+chunk+"\"}";/Sorry for this. This code will be improved when everything is working.
aux.sendMessage(json);//auxiliar class sends message according to native messaging protocol.
System.setOut(dummyStream);//avoid 3rd party library output contents and mess native messaging port.
}
System.setOut(originalStream);//let stream output values
json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"true\"}";//Sorry for this. This code will be improved when everything is working.
aux.sendMessage(json);
System.setOut(dummyStream);
return "";
}
Auxiliar.java
public class Auxiliar {
public int getInt(byte[] bytes) {
return (bytes[3] << 24) & 0xff000000 | (bytes[2] << 16) & 0x00ff0000
| (bytes[1] << 8) & 0x0000ff00 | (bytes[0] << 0) & 0x000000ff;
}
public String readMessage(InputStream in) throws IOException {
byte[] b = new byte[4];
in.read(b);
int size = getInt(b);
//log(String.format("The size is %d", size));
if (size == 0) {
throw new InterruptedIOException("Blocked communication");
}
b = new byte[size];
in.read(b);
return new String(b, "UTF-8");
}
public boolean sendMessage(String message) {
try {
System.out.write(getBytes(message.length()));
System.out.write(message.getBytes("UTF-8"));
System.out.flush();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
//Use this in case the other method get deprecated
public byte[] getBytes(int length) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (length & 0xFF);
bytes[1] = (byte) ((length >> 8) & 0xFF);
bytes[2] = (byte) ((length >> 16) & 0xFF);
bytes[3] = (byte) ((length >> 24) & 0xFF);
return bytes;
}
}

Send packets to Source Dedicated Server

I'm trying to write an RCON Client in dart, but I'm getting stuck at this point:
The server recives the packet but seems like it cannot read it properly as reply I'm getting:
Rcon auth failed from rcon whitelist address 2.xxx.xxx.169:52672
Even tough the password is right:
"rcon_password" = "foo" ( def. "" ) - remote console password.
I've provided links to the valve's wiki within the code comments.
This is my code at the moment:
Socket socket;
int _id = 1;
const int SERVERDATA_AUTH = 3;
const int SERVERDATA_AUTH_RESPONSE = 2;
const int SERVERDATA_EXECCOMMAND = 2;
const int SERVERDATA_RESPONSE_VALUE = 0;
void main() async {
socket = await Socket.connect('hexah.net', 27015);
await socket.listen(onSocketData, onError: onError, onDone: onDone);
await _write(SERVERDATA_AUTH, 'foo');
}
void _write(int type, String body) async {
var bodyASCII = ascii.encode(body); //Get ASCII string with Null terminator
// Should I use this or the other way? ??
var size = bodyASCII.length + 14;
var buffer = new Int8List(size).buffer;
var bdata = new ByteData.view(buffer);
bdata.setInt32(0, size - 4, Endian.little); //Byte requests length (32bit le signed int).
bdata.setInt32(4, _id, Endian.little); //Any integer (32bit le signed int).
bdata.setInt32(8, type, Endian.little); //Valid values: SERVERDATA_* (32bit le signed int).
int writepos = 12;
await bodyASCII.forEach((element) {
bdata.setInt8(writepos, element);
writepos +=1;
});
bdata.setInt16(size-2, 0, Endian.little); //Write the null terminators
await socket.write(bdata);
_id++;
}
void onSocketData(var data){
print(data);
}
void onError(var data, StackTrace stack){
print(stack);
}
void onDone(){
print('Connection terminated');
}
Here is also a small example with nodejs:
var size = Buffer.byteLength(body) + 14,
buffer = new Buffer(size);
buffer.writeInt32LE(size - 4, 0);
buffer.writeInt32LE(id, 4);
buffer.writeInt32LE(type, 8);
buffer.write(body, 12, size - 2, "ascii");
buffer.writeInt16LE(0, size - 2);
Do you have any ideas?
especially about getting properly the lengths.
This is how the packet payload should be
Using a RawSocket I get this as reply:
RawSocketEvent.write
RawSocketEvent.readClosed
EDIT:
I'm seeing that the same packet sent from nodejs resulted in a successful authentication but Dart failes, any ideas why this is happening? (converting the packets from nodejs & dart to an array they resulted the same)
Solved!
The issue was that I had to use a RawSocket and write something like this:
var packet = bdata.buffer.asInt8List();
await socket.write(packet, 0, packet.length);

C#: WPD - Downloading a Picture with meta tags

I am running the Portable Device API to automatically get Photos from a connected Smart Phone. I have it all transferring correctly. The code that i use is that Standard DownloadFile() routine:
public PortableDownloadInfo DownloadFile(PortableDeviceFile file, string saveToPath)
{
IPortableDeviceContent content;
_device.Content(out content);
IPortableDeviceResources resources;
content.Transfer(out resources);
PortableDeviceApiLib.IStream wpdStream;
uint optimalTransferSize = 0;
var property = new _tagpropertykey
{
fmtid = new Guid(0xE81E79BE, 0x34F0, 0x41BF, 0xB5, 0x3F, 0xF1, 0xA0, 0x6A, 0xE8, 0x78, 0x42),
pid = 0
};
resources.GetStream(file.Id, ref property, 0, ref optimalTransferSize, out wpdStream);
System.Runtime.InteropServices.ComTypes.IStream sourceStream =
// ReSharper disable once SuspiciousTypeConversion.Global
(System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
var filename = Path.GetFileName(file.Name);
if (string.IsNullOrEmpty(filename))
return null;
FileStream targetStream = new FileStream(Path.Combine(saveToPath, filename),
FileMode.Create, FileAccess.Write);
try
{
unsafe
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, 1024);
} while (bytesRead > 0);
targetStream.Close();
}
}
finally
{
Marshal.ReleaseComObject(sourceStream);
Marshal.ReleaseComObject(wpdStream);
}
return pdi;
}
}
There are two problems with this standard code:
1) - when the images are saves to the windows machine, there is no EXIF information. this information is what i need. how do i preserve it?
2) the saved files are very bloated. for example, the source jpeg is 1,045,807 bytes, whilst the downloaded file is 3,942,840 bytes!. it is similar to all of the other files. I would of thought that the some inside the unsafe{} section would output it byte for byte? Is there a better way to transfer the data? (a safe way?)
Sorry about this. it works fine.. it is something else that is causing these issues

c# Using SslStream.WriteAsync at high speeds

i am facing an annoying problem with SslStream.WriteAsync
here is the code
public void Send(PacketWriter writer)
{
var buffer = writer.GetWorkspace();
_sslStream.WriteAsync(buffer, 0, buffer.Length);
}
When writing the data at extremely high speed it tells me
The beginwrite method cannot be called when another write operation is pending
[NOTE] : I mean by high speed something like this
for (var i = 0 ; i <= 1000; i++)
{
Send(somedata);
}
You must wait until the previous asynchronous write has finished.
Change your send method to return a Task:
public Task Send(PacketWriter writer)
{
var buffer = writer.GetWorkspace();
return _sslStream.WriteAsync(buffer, 0, buffer.Length);
}
Make the calling method async, then await until each send operation completes:
for (var i = 0 ; i <= 1000; i++)
{
await Send(somedata);
}
May be try this-
private static void send_data(SslStream socket_stream, byte[] data)
{
Task task = new Task(() => { socket_stream.Write(data, 0, data.Length); });
task.RunSynchronously();
task.Wait();
}
This will make sure all the messaages are sent in oderly manner without any exception

JList updating with live captured packets info (using jNetPcap) is causing list blanking

I am coding app which is capturing packet from 2 NI Cards at the same time in specific thread for them.
I am using jnetPcap and I am getting captured packet in jpackethanler's method nextPacket i need to show info from the current packet in JList but when I use simply defaultListModel and i write model1.addElement(packetinfo) then JList randomly goes in blank.
My code :
new Thread(){
#Override
public void run(){
StringBuilder errbuf = new StringBuilder(); // For any error msgs
int snaplen = 64 * 1024; // Capture all packets, no trucation
int flags = Pcap.MODE_PROMISCUOUS; // capture all packets
int timeout = 10 * 1000; // 10 seconds in millis
Pcap pcap1 =
Pcap.openLive(Variables.getDevice1().getName(), snaplen, flags, timeout, errbuf);
if (pcap1 == null) {
System.err.printf("Error while opening device for capture: "
+ errbuf.toString());
return;
}
PcapPacketHandler<String> jpacketHandler1 = new PcapPacketHandler<String>() {
int count = 1;
#Override
public void nextPacket(PcapPacket packet, String user) {
// ALL PACKETS FROM DEVICE 1 HERE
int packetSize = packet.size();
int packetCount = count++;
String desc = String.format("No.: %15d | HDRSize : %-4d", packetCount,packetSize);
device1Model.addElement(desc); // this adds desc to JLIST
}
};
pcap1.loop(Pcap.LOOP_INFINITE, jpacketHandler1, "");
pcap1.close();
}
}.start();
What do change to be more smooth and at the same time there will be no packet looses. Because i need to catch every packet for right function of app.
Thank You.

Resources