Decoding a device payload sent to the Helium Console - javascript

So I have defined an integration in the Helium Console (i.e. - an IoT LoRaWAN networking service). When I test out sending data from my IoT device to my Helium Console integration endpoint, I can see the payload. And I can manually decode it back to the JSON request body that's correct. But am having trouble defining a custom function in the Helium Console that will automate this for the integration. My IoT device is serializing a MsgPack payload of environmental data that's then sent to the Helium Console integration endpoint. And the Helium Console custom function allows Javascript, although just bare-bones without any requires, imports, etc.
Below is the Python script that can manually decode the payload. If anyone is familiar with this area I'd be interested as to suggestions. There are pre-defined decoders available for Helium, although none that match exactly my hardware.
If anyone has created custom decoding functions for Helium Console integrations I'd be curious as to how I could knock this out. Here is some info about this --> https://docs.helium.com/use-the-network/console/functions/.
import ssl, sys, json, base64
import msgpack
payload = "haJiVspAozMzo3RfQxilZWNfbVMWonBoB6NvcnAC"
# decode the payload from base64 and unpack
b64 = base64.b64decode(payload)
mp_dict = msgpack.unpackb(b64)
print(mp_dict) # output is {'bV': 5.099999904632568, 't_C': 24, 'orp': 2, 'ph': 7, 'ec_mS': 22}

Rather than reinvent the wheel, I modified the Arduino code running on my device. Pulling in the CayenneLPP library I manually encode what I need, so that the Helium Console's canned CayenneLPP decoding function can correctly parse the data.
Arduino code snippet below.
#include <CayenneLPP.h>
...
/*CayenneLPP variable*/
CayenneLPP lpp(51);
...
static void prepareTxFrame( uint8_t port )
{
appDataSize = lpp.getSize();
uint8_t lppBuffer[128];
memcpy(lppBuffer, lpp.getBuffer(), 128);
memcpy(appData, lppBuffer, lpp.getSize());
}
...
// The loop function is called in an endless loop
void loop()
{
lpp.reset();
lpp.addTemperature(1, 22.5);
lpp.addBarometricPressure(2, 1073.21);
lpp.addGPS(3, 52.37365, 4.88650, 2);
...
LoRaWAN.displaySending();
prepareTxFrame( appPort );
LoRaWAN.send(loraWanClass);
...
}

https://github.com/helium/console-decoders/blob/master/debugDecodeBase64.js
// LoRaWan devices automatically base64 encode data sent
// Sometimes nice just to view what original payload was sent
//
// This can help when writing your own decoder
//
//
function Decoder(bytes, port, uplink_info) {
var decoded={};
try{
var result = String.fromCharCode.apply(null, bytes);
decoded.value = result;
return decoded;
} catch (err) {
return 'Decoder: ' + err.name + " : " + err.message;;
}
}
// And in the integration section of the Helium console use this JSON
// For an Adafruit.io integration which is expecting JSON like { "value" : "56" }
//
// { "value": {{decoded.payload.value}} }
Create account on https://app.datacake.de/
Create integration to Datacake in here: https://console.helium.com/integrations
integrations
Link the flow in here:
https://console.helium.com/flows
flows
Create project and add device to DataCake, as decoder function use modified above (as is - it will receive a string)

Related

How do I decode a BASE64, PCKS-8 representation of a private key in NetSuite or javascript?

I'm working on a suitescript to integrate NetSuite with the Walmart Marketplace APIs. And, as the another OP here says it right their documentation pretty much says if you don't use Java you're on your own.
I'm looking for a way to do the same either in suitescript or javascript.
Instruction from Walmart's API documentation:
Sign the byte array representation of this data by:
Decoding the Base 64, PKCS-8 representation of your private key. Note that the key is encoded using PKCS-8. Libraries in various languages offer the ability to specify that the key is in this format and not in other conflicting formats such as PKCS-1. Use this byte representation of your key to sign the data using SHA-256 With RSA. Encode the resulting signature using Base 64.
And, a java code from their documentation to do the same:
public static String signData(String stringToBeSigned, String encodedPrivateKey) {
String signatureString = null;
try {
byte[] encodedKeyBytes = Base64.decodeBase64(encodedPrivateKey);
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(encodedKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey myPrivateKey = kf.generatePrivate(privSpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(myPrivateKey);
byte[] data = stringToBeSigned.getBytes("UTF-8");
signature.update(data);
byte[] signedBytes = signature.sign();
signatureString = Base64.encodeBase64String(signedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return signatureString;
}
For reference, here's the similar thing asked for dot net. Any help would be appreciated.
I tried developing a SAML connector in Javascript once and found several libraries that deal with different key file formats etc. I got fairly far along but the time to run some of the scripts was incredible (imagine trying to login but the process taking two minutes to decide your login was valid)
At that point I switched to an external system and managed the SSO with Netsuite's inbound SSO.
It doesn't look like things have improved that much with NS in the crypto department even with SS 2.0.
I'd tend to package this into two parts. Generate your files in Suitescript and pass them through a java based web service that handles the signing requirements. Minimizes the amount of Java you have to write and keeps your transaction extraction/formatting scripts under easy control.
I found a library (jsrsasign) that will do the Walmart signature from NetSuite server side in under 4 seconds! (Marketplace has gone to OAuth2, but I'm stuck with signing as a Drop Ship Vendor)
/**
*#NApiVersion 2.x
*#NScriptType ScheduledScript
*/
define(['N/log', 'N/https', '../lib/jsrsasign-master/jsrsasign-all-min'],
function(log, https) {
function execute(context) {
var pkcs8Der = {Your Walmart Private Key};
var pkcs8Pem = [
'-----BEGIN PRIVATE KEY-----',
pkcs8Der.match(/.{0,64}/g).join('\n'),
'-----END PRIVATE KEY-----'
].join('\n');
var tStamp = Date.now()
var stringToSign = [
tStamp,
{Your Walmart Comsumer Id},
{Request URL},
{Request Method (All Caps)}
].join('\n') + '\n';
var sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
sig.init(pkcs8Pem);
var sigVal = hextob64(sig.signString(stringToSign));
log.audit({title: 'Signature', details: sigVal});
log.audit({title: 'Timestamp', details: tStamp});
}
return {
execute: execute,
};
}
);
I had to add the following code to the jsrsasign-all-min.js library file for the Scheduled Script to load the module:
var navigator = {}, window = undefined;

Golang: dealing with binary data

I have application client(javascript)-server(golang) and the connection between them are all over websocket. I'm planing using binary messages and i want to create my own protocol for messaging like in this page protocol.
I'm already figure it out in javascript by using DataView but not in golang. Event the primitive data type are similar like they have int8, uint8, int16, uint16 etc, i can't figure it out.
This is the message frame:
1 Uint8 opcode
2 Uint16 msg
This is the example of javascript code handling the incoming message form websocket with message frame above:
websocket.onmessage = function(evt) {
var data = new DataView(evt.data);
var opcode = data.getUint8(0);
var msg = data.getUint16(1);
}
Can you show me how to do it in golang? i'm using gorilla websocket. I know that read message are in []byte, but i don't know how to slice it like javascript does with DataView.
Thanks
For the uint16 you'll need the binary package. Double-check if LittleEndian is what you want.
package main
import (
"encoding/binary"
)
func main() {
a := []byte("yak")
/* opcode */ _ = uint8(a[0])
/* message */ _ = binary.LittleEndian.Uint16(a[1:3])
}
https://play.golang.org/p/HRu7C5h2a5

IPC on Terminal Server with C/C++ an nw.js/node.js/node-native-module (C++)?

I have a Win32-DLL (C++) which is loaded as a plugin in another application. The DLL starts a nw.js instance (ShellExecuteEx and SEE_MASK_NOCLOSEPROCESS) and ends it at DLL unloading (by the hInstance of ShellExecuteEx). I need a way to send a string (plain ansi) to the nw-process and retrieve an answer (also string). The old way was a simple http-request with the response in the body. But the environment changes during the development, the "package" app-dll-nw runs multiple times by the same user and multiple users run on the same machine (terminal server). So port listing is "impossible" (yeah random ports or singleton nw, but no).
I found different ways:
socket - port listing problem
wm_copydata/wm_... - need a custom nw-plugin with hidden window (no native nw way); no request-response-system
RPC - port listing problem
DDE - no native javascript way (found a module, which uses .net); In my old delphi days DDE was a not so simple task and it failed multiple times with no logic.
shared memory - no experience; expectations: asynchronous, trigger?, no native javascript way
shared file - no experience; expectations: asynchronous, trigger (watcher on file change) but problems with synchronization, native js way possible
named pipe - no experience; expectations: win32-api and like a chat system (in-pipe [send broadcast] and out-pipe [receive broadcast], or both in one)? If yes, I can use one name about all instances and use unique identifiers and wait for the right answer.
What is a nice and simple way to communicate like the http-way but w/o networking?
Update 1: The node module "net" is able to create a server for a named pipe. The first test, sending a string from the dll to nw, was successful.
var server = net.createServer(function(stream) {
stream.on('data', function(c) {
console.log('data:', c.toString());
});
stream.on('end', function() {
//server.close();
});
});
server.listen('\\\\.\\pipe\\MyAppDynamicGUID');
Update 2 - My Solution
With named pipe and a simplified version of https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx I found a working methode.
Server in nw.js:
var server = net.createServer(function(req) {
req.on('data', function(c) {
console.log(c.toString());
req.write('123|Hello World', 'ascii');
});
});
server.listen('\\\\.\\pipe\\MyAppDynamicGUID');
The client in C++ (no permanent connection, strange string handling, simplified error handling):
static std::string PipenameA = "\\\\.\\pipe\\MyAppDynamicGUID";
#define BUFSIZE 512
std::string SendPipeRequestA(std::string sRequest) {
DWORD dwToWrite, dwWritten, dwRead;
BOOL bSuccess;
char chBuf[BUFSIZE];
std::vector<char> buffer;
HANDLE hPipe = CreateFileA(PipenameA.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hPipe == INVALID_HANDLE_VALUE)
return "-1|Pipe-Error 1 (connect)";
dwToWrite = (lstrlenA(sRequest.c_str())+1)*sizeof(char);
bSuccess = WriteFile(hPipe, sRequest.c_str(), dwToWrite, &dwWritten, NULL);
if (!bSuccess)
return "-1|Pipe-Error 2 (write)";
do {
bSuccess = ReadFile(hPipe, chBuf, BUFSIZE*sizeof(char), &dwRead, NULL);
if (!bSuccess && GetLastError() != ERROR_MORE_DATA)
break;
buffer.insert(buffer.end(), chBuf, chBuf + dwRead);
} while (!bSuccess);
std::string sResponse(&buffer[0]);
CloseHandle(hPipe);
return sResponse.c_str();
}
// Jonny
The answers you will get will be opinion based, be aware of that.
you can inject the data into the JS module as command line argument
for example
start nw.js MyData
and get it insinde the JS with process.argv.
now, sending the data back to the C++ executables/DLLs is a bit tricky.
if you shell-execute the process, you can have the handle to it.
you can print the data into the stdout from the JS part , and read it in the native app by getting the STDOUT handle from the process handle.
Register your nw.js app with a custom url should be an elegant way.
Such as "github://", "thunder://", "twitter://"
On windows you may have a look at:
https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
With custom url you can take simple arguments to nw.js at single-instance mode. See:
https://github.com/nwjs/nw.js/wiki/Handling-files-and-arguments#open-file-with-existing-app
If more data required maybe base64 can help, or even more by LZ-String compress method.

Send Base64 encoded image as string to Chromecast

The problem is to send local image from phone as encoded Base64 string to Chromecast. And decode it using my Custom Receiver. I was following this guide which is based on this project sample.
I suggest the problem might be in:
Custom Receiver is not proper (I'm not strong in JS).
Chromecast didn't load that Receiver (I don't know how to check that).
Image was encoded wrong on device or decoded on Chromecast.
You see, it seems like I coded everithing right since the status of Chromecast when I send photo is:
statusCode 0 (success),
application name: Default Media Receiver,
status: Ready To Cast,
sessionId: 34D6CE75-4798-4294-BF45-2F4701CE4782,
wasLaunched: true.
This is how I send image as String:
mCastManager.castImage(mCastManager.getEncodedImage(currentEntryPictureByPoint.getPath()));
Methods used:
public void castImage(String encodedImage)
{
Log.d(TAG, "castImage()");
String image_string = createJsonMessage(MessageType.image, encodedImage);
sendMessage(image_string);
}
private static String createJsonMessage(MessageType type, String message)
{
return String.format("{\"type\":\"%s\", \"data\":\"%s\"}", type.toString(), message);
}
/**
* Convert Image to encoded String
* */
public String getEncodedImage(String path){
Bitmap bm = BitmapFactory.decodeFile(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] byteArrayImage = baos.toByteArray();
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
return encodedImage;
}
/**
* Send a text message to the receiver
*
* #param message
*/
private void sendMessage(String message) {
if (mApiClient != null && mCustomImageChannel != null) {
try {
Cast.CastApi.sendMessage(mApiClient,
mCustomImageChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result) {
if (!result.isSuccess()) {
//ALWAYS REACHING HERE :(
Log.e(TAG, "Sending message failed");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Exception while sending message", e);
}
} else {
Toast.makeText(mContext, message, Toast.LENGTH_SHORT)
.show();
}
}
If the sending process is correct then the Receiver is wrong and don't know how to decode this message properly.
The way I uploaded it (well, at least I think that its uploaded...)
Registered new Custom Receiver on Google Cast Console and received Application ID.
Created cast_receiver.js file. The code inside this file is supposed to decode Base64 string into image.
Copied the code for Receiver from guide to .js file and changed NAMESPACE inside to my one: urn:x-cast:com.it.innovations.smartbus
Uploaded file on Google Drive and modified its access visibility to full public
Copied the link to file to URL field in Cast Console. This link is direct download of file.
Restarted Chromecast. Seems like it tried to download something but not sure if succeed
If anyone faced this problem, please point me out what I am doing wrong. Appreciate any help.
P.S. tell if some more code needed...
I very strongly suggest to avoid using the sendMessage() for sending any large data set; those channels are meant to be used as control channels and not as a way to send a chunk of data. A much much simpler and more robust approach is to embed a tiny dumb web server in your local app (on the sender side) and "serve" your images to your chromecast. There is a number of ready-to-use embedded web servers that you can put in your app and requires almost no configuration; then you can serve all sorts of media, including images, to your chromecast with even the default or styled receiver.

Deconstruct/decode Websocket frames like Google Chrome does

I'm connecting to a website via websocket connection (client to server), I know how to encode the data and write it to the server (using the net module in node.js) but when I'm reading the data back I get odd characters in front of the important data, like if I'm suppose to get:
// Data needed on the left and data I'm receiving from websocket on the right
'inited\r\n' -> '�inited\r\n'
'n:2\r\n' -> '�n:2\r\n'
This is how I am getting the data from the server
Klass.prototype.connect = function(){
// this.port is equal to 8080 and the exact server varys, but it's not that important anyways since the problem is decoding the data properly.
var that = this;
var buffer = "";
this.socket = new net.createConnection(this.port, this.server);
this.socket
.on("connect", function(){
that.sendHandshake(); // just sends a standard client to server handshake
})
.on("data", function(recv){
// .split('\r\n\r\n').join('\r\n') needed to separate the server handshake from the data I am trying to parse
buffer += recv.toString('utf-8').split('\r\n\r\n').join('\r\n');
while (buffer){
var offset = buffer.indexOf('\r\n');
if (offset < 0)
return;
var msg = buffer.slice(0, offset);
// parseMsg(msg)
buffer = buffer.slice(offset + 3);
}
});
};
I am probably doing a lot of things improperly in the code above, but I'm not quite sure how to do it exactly so that is the best I got for now.
Problem is I don't know how to remove the mystery/special characters. Sometimes there is only 1 mystery/special character, but other times there is multiple ones depending on the data but they are never after the important data I need to check.
When I use Google Chrome and view the data on through tools->JavaScript console->network tab and find the websocket stream I'm looking for Google parses it correctly. I know it's possible since Google Chrome shows the correct frames, how do I deconstruct/decode the data so I can view the correct frames on the terminal?
I don't really need it in a particular language as long as it works I should be able to port it, but I would prefer examples/answers in node.js since that is the programming language I am using to connect to the server.

Categories

Resources