Writing a native messaging host in GJS - glib

I'm trying to write a native messaging host for a chrome/firefox extension in GJS (since it will rely on code already written in GJS) but encountering some hurdles. I'm using chrome-gnome-shell as a rough template since it also uses GLib/Gio instrospection and GApplication, but it has the advantage of python struct that I don't have.
Quickly, native messaging hosts exchange messages through stdin/stdout which are an Int32 (4-bytes) length following by a string of utf-8 encoded JSON.
chrome-gnome-shell uses GLib.IOChannel with set_encoding('utf-8') and struct to handle int32 bytes. I've had trouble using that class in GJS and don't have struct so have been trying Gio.UnixInputStream wrapped in Gio.DataInputStream (and output counterparts), with put_int32()/read_int32() and put_string()/read_string().
Apparently I'm mightily confused about what I'm doing. If I call Gio.DataInputStream.read_int32() it returns a number 369098752, so I'm guessing the int32 is not being converted to a regular Number. If I call Gio.DataInputStream.read_bytes(4, null).unref_to_array() to get a ByteArray; ByteArray.toString() returns '\u0016' while ByteArray[0] returns '22' which appears to be the actual length.
Some pointers on reading/writing int32's to a datastream and would be much appreciated.
chrome-gnome-shell references:
on_input()
send_message()

I don't know if this is the best way to solve this, but here's what I came up with.
Two functions using the ByteArray import (modified from somewhere on SO):
const ByteArray = imports.byteArray;
function fromInt32 (byteArray) {
var value = 0;
for (var i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
return value;
};
function toInt32 (num) {
var byteArray = [0, 0, 0, 0];
for (var index_ = 0; index_ < byteArray.length; index_++) {
var byte = num & 0xff;
byteArray [index_] = byte;
num = (num - byte) / 256 ;
}
return ByteArray.fromArray(byteArray);
};
For receiving/sending:
const Gio = imports.gi.Gio;
// Receiving
let stdin = new Gio.DataInputStream({
base_stream: new Gio.UnixInputStream({ fd: 0 })
});
let int32 = stdin.read_bytes(4, null).toArray();
let length = fromInt32(int32);
let data = stdin.read_bytes(length, null).toArray().toString();
let message = JSON.parse(data);
// Sending
let stdout = new Gio.DataOutputStream({
base_stream: new Gio.UnixOutputStream({ fd: 1 })
});
let data = JSON.stringify(message);
let int32 = toInt32(data.length);
stdout.write(int32, null);
stdout.put_string(data, null);
Of course, you should wrap these in try-catch as appropriate and you'll probably want to connect a source to the input (you can use the Gio.UnixInputStream):
let source = stdin.base_stream.create_source(null);
source.set_callback(onReceiveFunc);
source.attach(null);

You may be able to use Gio.DataOutputStream.put_int32() and Gio.DataInputStream.read_int32() the same way as you use read_bytes() and put_string().

Related

How to do encryption like android's "PBEWithMD5AndDES" in flutter dart?

I'm trying to recreate an existing mobile apps into flutter but struggling in the "PBEWithMD5AndDES" encryption on android which I can't seem to find similar way in dart.
This is so far what I've tried to achieve the same using Flutter_Des.dart, Password_Hash.dart and Crypto.dart library but still can't get the same output.
encryptPassword(String keyStr, String passwordStr) async {
if (keyStr.length == 0 || passwordStr.length == 0) {
return "";
}
var generator = new PBKDF2(hashAlgorithm: md5);
String saltStr = generateSaltBase64String();
var hash = generator.generateBase64Key(keyStr, saltStr, round, keyLength);
var encryptBase64 = await FlutterDes.encryptToBase64(passwordStr, hash.toString());
return encryptBase64;
}
Below is what I have currently on Android.
KeySpec keySpec = new PBEKeySpec(str.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
ecipher = Cipher.getInstance("PBEWithMD5AndDES");
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
byte[] utf8 = password.getBytes("UTF8");
byte[] enc = ecipher.doFinal(utf8);
enc = Base64.encode(enc, Base64.DEFAULT);
return new String(enc);
I'm expecting the same output as android so my backend able to decrypt it.
PBEWithMD5AndDES uses PBKDF1 to generate the key material (not PBKDF2). This gives you 128 bits of key material that you then use as two 64 bit halves as the key and the IV for DES.
Derive the key and IV as follows - I've plugged in some arbitrary values for iteration, password and salt and confirmed against JCrypto.
int iterations = 31;
List<int> salt = [0x21, 0x21, 0xf0, 0x55, 0xc3, 0x9f, 0x5a, 0x75];
List<int> password = utf8.encode('test');
List<int> saltedKey = password + salt;
Digest d = md5.convert(saltedKey);
for (int i = 1; i < iterations; i++) {
d = md5.convert(d.bytes);
}
print(d);
List<int> key = d.bytes.sublist(0, 8);
List<int> iv = d.bytes.sublist(8, 16);
print(key);
print(iv);
I can't find a Dart implementation of DES which takes a key and IV as bytes. triple_des wants them as strings - i.e. it's dumbed down. Pointy castle doesn't do DES. FlutterDes also seems to want strings. You might be able to modify triple_des to take binary keys and IVs. Or use a different cipher.
Solved by using flutter's methodchannel and call platform specific code to do the encryption and its working now. Thanks

Writing a string to disk without any character conversion in Groovy

I have a String object, now because it comes a diff of a folder containing different file types, not everything in it is encoded in the same character set.
The correct codes are in the string, but whenever I try to access the string, groovy tries to be helpful and decode the string, which messes things up.
Now the following seems to do what I need
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
max_block_size = 1024 * 1024
char[] char_buffer = new char[max_block_size]
block_start = 0
patch_length = decoded_diff.length()
while (true) {
block_size = Math.min(patch_length - block_start, max_block_size)
decoded_diff.getChars(block_start, block_start + block_size, char_buffer, 0)
block_start += block_size
byte[] byte_buffer = new byte[block_size]
for (int i = 0; i < block_size; i++) {
byte_buffer[i] = (int) char_buffer[i]
}
patch_file.append(byte_buffer)
if (block_start == patch_length) break
}
However, it is sloooow
Is there a faster way to achieve the same thing? The final patch file must be identical to the original diff to work. Unfortunately I can't send the file itself (jenkins currently doesn't support file parameters in pipeline jobs) so I have to escape it and send it as part of a json parameter list, hence this painful rigmarole on the receiving end.
Why not:
String decoded_diff = "String that contains codes from different character encodings"
patch_file_name = 'changes.patch'
patch_file = new File(pwd(), patch_file_name)
patch_file.delete()
patchFile.withOutputStream { os ->
os << decoded_diff.bytes
}

Swift/iOS: How to use address (reference, pointer) in swift?

Like what you can do with inout parameters, or like what you can do with * and & in C++. For example:
#include <iostream>
using namespace std;
int main ()
{
int firstvalue, secondvalue;
int * mypointer;
mypointer = &firstvalue;
*mypointer = 10;
mypointer = &secondvalue;
*mypointer = 20;
cout << "firstvalue is " << firstvalue << '\n';
cout << "secondvalue is " << secondvalue << '\n';
return 0;
}
and the result is:
firstvalue is 10
secondvalue is 20
Can I do something similar to this in Swift?
As a general rule, no. Swift, like most modern programming languages, does not give you direct access to pointers most of the time.
There are special pointer types you can use if you need them. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html. However, if you find yourself wanting to use these, except in special cases, I suspect that you are still thinking in C/Objective-C/C++ terms.
The inout parameter allows you to pass by reference not value.
Example:
func test1(inout a : Int) { a = 5 }
func test2(a : Int) { a = 5 }
Here the 1st function (because of the inout parameter) will modify whatever is passed in to it.
The second function will receive a copy of the variable so when you are done
var a = 4;
var b = 4;
test1(&a);
test2(b);
print(a);
print(b):
will print out
5
4
Because swift gives you full access to C stuff you can use the type unsafePointer and unsafeMutablePointer for doing funky stuff.
Check out this post for more details: http://chris.eidhof.nl/posts/swift-c-interop.html
When I want to manipulate individual bytes in a NSData type i do the following:
var rawData: NSMutableData
/* Using unsafeMutablePointers allows for raw data manipulation */
var ptr: UnsafeMutablePointer<UInt8>; // = UnsafePointer<UInt8>(rawData.bytes)
var bytes: UnsafeMutableBufferPointer<UInt8>; // = UnsafeBufferPointer<UInt8>
self.rawData = NSMutableData(data: initData)
ptr = UnsafeMutablePointer<UInt8>(rawData.mutableBytes)
bytes = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: rawData.length)
Then i can access individual bytes with:
bytes[i]
this uses pointers.

Swift - converting from ConstUnsafePointer<()>

I'm on beta 3. Consider the following Objective-C line:
const uint8_t *reportData = [data bytes];
where data is a NSData object.
How would this line be re-written in Swift?
data.bytes is of type ConstUnsafePointer<()>, and while there's plenty of documentation on how to create a pointer type in Swift, there isn't much info on how to work with them.
edit:
To add some context, I'm trying to port Apple's HeartRateMonitor sample code to Swift. This code interacts with BLE heart rate monitors. This code I'm working on translates the data received by the Bluetooth system into an int for use in the UI. The data received from BT is expected to be an array of uints, element 0 is used to check for a flag and element 1 contains the value.
Here's the same Objective-C line in context:
const uint8_t *reportData = [data bytes];
uint16_t bpm = 0;
if ((reportData[0] & 0x01) == 0)
{
/* uint8 bpm */
bpm = reportData[1];
}
What you were looking for was how to convert NSData to an array of UInt8. Here's how.
import Foundation
let path = "/etc/csh.cshrc" // something existent
let data = NSData(contentsOfFile: path)
var aofb = [UInt8](count:data.length, repeatedValue:0)
data.getBytes(&aofb, length:data.length)
for c in aofb {
let s = UnicodeScalar(Int(c)).escape(asASCII:true)
println("\(c):\(s)")
}
Just built following code (Note code below works on Beta 3, ConstUnsafePointer<()> needs to be changed to COpaquePointer in order to work on Beta 2, please see edit history for more information)
var dataPath = NSBundle.mainBundle().pathForResource("TestData", ofType: "") // What I have in TestData is "GREETINGS WORLD"
var originalData = NSData(contentsOfFile: dataPath)
var dataLength = originalData.length
println("original data: \(originalData)") // Output original data
// Data to bytes
var reportBytes: ConstUnsafePointer<()> = originalData.bytes
var bytesToString = NSString(bytes: reportBytes, length: dataLength, encoding: NSUTF8StringEncoding)
println("string from bytes: \(bytesToString)")
// Bytes to data
var bytesToData = NSData(bytes: reportBytes, length: dataLength)
println("data from bytes: \(bytesToData)")
Console log
original data: <47524545 54494e47 5320574f 524c44>
string from bytes: GREETINGS WORLD
data from bytes: <47524545 54494e47 5320574f 524c44>
Also found this may help
ConstUnsafePointer<T>
/// This type stores a pointer to an object of type T. It provides no
/// automated memory management, and therefore the user must take care
/// to allocate and free memory appropriately.
Hope this shed light.
Looking at handling bluetooth heart rate monitors in Swift now I found the simplest way to get the NSData byte values to UInt8 format:
let bytes = UnsafePointer<UInt8>(data.bytes)
if bytes[0] & 0x01 == 0 {
NSLog("BPM \(bytes[1]")
}

Actionscript ByteArray (from NFC) to String

I'm reading an NFC tag in my Adobe AIR mobile app. The data is read as a ByteArray, but I'm having difficulty pulling the full text. The sample text on the tag is "http://www.google.com"
Using this method, I get a portion of the String "http://www.goog", but not all of it. I'm assuming because each character is not a single byte:
private static function convertToString(byte_array : ByteArray) : String {
var arr : Array = [];
for (var i : Number = 1 ; i <= byte_array.bytesAvailable; i++) {
arr.push(byte_array.readUTFBytes(i));
}
var finalString : String = "";
for (var t : Number = 0; t < arr.length;t++) {
finalString = finalString + arr[t].toString();
}
return finalString;
}
I've also tried the method below, but it returns null:
bytes.readUTF();
I'm wondering if I need to convert the byteArray to a base64 string and then decode that. It seems like an extra step, but that's how I've done it before when sending data to/from a server using AMFPHP.
Thanks in advance for any input.
You could even simplify this code by simply calling
private static function convertToString(bytes:ByteArray):String {
bytes.position = 0;
var str:String = bytes.readUTFBytes(bytes.length);
return str;
}
This way you will read all contents of the bytearray in one single method call into your destination string.
Figured it out in the code below.
There were 2 errors, plus some cleanup:
private static function convertToString(bytes : ByteArray) : String {
bytes.position = 0;
var str : String = '';
while (bytes.bytesAvailable > 0) {
str += bytes.readUTFBytes(1);
}
return str;
}
the "bytesAvailable" property decreases as you read from the ByteArray. Here, I'm checking if the bytes > 0 instead of the length
the "readUTFBytes" method takes a length parameter (not position). Position is automatically updated as you read from the ByteArray. I'm passing in "1" instead of "i"

Resources