Decoding a string to valid JSON - javascript

I am writing an add-on for Firefox. I'm catching a JSON file which should contain general user data which I need. To clarify this, the data is accessible without any security boundaries. Sometimes the caught string is a valid JSON (without any encoding at all).
And sometimes it looks like this:
Does anyone have an idea how to decode this with JavaScript or at least an idea which kind of encoding this is?
EDIT:
The correct data would be something like:
{"type":"success","message":"OK","data":{"myPersonas":[{"picture":"","personaId":"382046730","games":{"1":"3078"},"personaName":"Feirell","updatedAt":1423573314,"userId":"2832659177456727338","clanTag":"","originalPersona":{"picture":"","userId":"2832659177456727338","user":null,"updatedAt":1423573314,"firstPartyId":"","personaId":"382046730","personaName":"Feirell","gamesLegacy":"0","namespace":"cem_ea_id","gamesJson":"{\"1\":\"3078\"}","games":{"1":"3078"},"clanTag":""},"namespace":"cem_ea_id"}],"currentRankNeeded":{"name":"WARSAW_ID_P_RANK127_NAME","level":127,"pointsNeeded":20260000,"texture":"UI\/Art\/Persistence\/Ranks\/Rank127","iconImageConfig":{"category":"rank_icon","slug":"r127","texture":"UI\/Art\/Persistence\/ranks\/IconsScoreboard\/r127","versions":{"small":{"path":"warsaw\/gamedata\/rank_icon\/small.png","isSprite":true,"height":23,"name":"small","width":29},"smallns":{"path":"warsaw\/gamedata\/rank_icon\/smallns\/r127.png","isSprite":false,"height":23,"name":"smallns","width":29}}},"guid":"384D858D-8288-4B60-9C35-234B65157873","imageConfig":{"category":"rank","slug":"r127","texture":"UI\/Art\/Persistence\/Ranks\/Rank127","versions":{"large":{"path":"warsaw\/gamedata\/rank\/large\/r127.png","isSprite":false,"height":256,"name":"large","width":256},"smallinv":{"path":"warsaw\/gamedata\/rank\/smallinv.png","isSprite":true,"height":64,"name":"smallinv","width":64},"medium":{"path":"warsaw\/gamedata\/rank\/medium.png","isSprite":true,"height":128,"name":"medium","width":128},"tiny":{"path":"warsaw\/gamedata\/rank\/tiny.png","isSprite":true,"height":29,"name":"tiny","width":29},"tinyinv":{"path":"warsaw\/gamedata\/rank\/tinyinv.png","isSprite":true,"height":29,"name":"tinyinv","width":29},"small":{"path":"warsaw\/gamedata\/rank\/small.png","isSprite":true,"height":64,"name":"small","width":64},"mediumns":{"path":"warsaw\/gamedata\/rank\/mediumns\/r127.png","isSprite":false,"height":128,"name":"mediumns","width":128},"smallns":{"path":"warsaw\/gamedata\/rank\/smallns\/r127.png","isSprite":false,"height":64,"name":"smallns","width":64}}}},"generalPersonaStats":{"PDWHeadshots":0.0,"serviceStarsProgress":{"8":9.1730769231,"1":81.6516129032,"2":13.7603053435,"2048":38.81,"32":93.2388059701},"vehiclesDestroyed":2229,"mortarUser":null,"cs_kills":null,"rsScore":0,"PDWKills":0.0,"gameModesScore":{"32":"32800","1":"5274720","2":"184170","67108864":"12635","64":"5274720","68719476736":"5274720","524288":"21675","34359738368":"21410","2097152":"21675","8":"32800","8388608":"5790","512":0,"134217728":"12635","1024":"33840","33554432":"12635","16777216":"17000","137438953472":"21675"},"sc_hotwire":null,"gameModeServiceStarsGold":{},"rank":127,"rushWins":null,"sc_enforcer":null,"sc_vehicle":3337250,"cp_kills":null,"kitMaxMeleeKillsInRound":{},"cp_deaths":null,"motionSensorSpots":null,"cp_wins":null,"sniperRifleAccuracy":0.282155948,"sc_heist":null,"sc_team":532411,"skill":248,"nemesisKills":429,"heals":13978,"sc_operator":null,"kitMeleeKills":{},"longestHeadshot":694.02,"kills_assault":12436,"conquestWlr":null,"elo":0,"longestWinStreak":null,"sc_unlock":109000,"mcomDefendKills":9,"wlRatio":0.0,"sc_award":7289700,"cp_skill":null,"vehiclesDestroyedAssists":null,"revives":3866,"kitLosses":{},"squadDMWins":null,"rushWlr":null,"LMGKills":1494,"cashEarned":null,"kitKills":{},"rocketLauncherAccuracy":0.0,"kitMaxScoreInRound":{},"kills":23207,"sc_capturetheflag":null,"kdRatio":1.5,"sc_bonus":344311,"assaultRifleAccuracy":0.1521077163,"kitDeaths":{},"squadRushLosses":null,"PDWAccuracy":0.0,"flagDefend":3535,"LMGHeadshots":332,"kitWins":{},"nemesisStreak":18,"numWins":726,"flagrunner":null,"conquestWins":null,"scorePerMinuteDelta":0,"kitHeadshots":{},"rsKills":0,"sc_objective":0,"kitDeployments":{},"rsTimePlayed":0,"vehicleScores":{"32":"206936","1":0,"2":"1957700","4":"153005","8":"20374","16":"727908"},"antiGroundSoldier":162.0,"timeDead":null,"sc_bloodmoney":null,"kdRatioDelta":null,"quitPercentage":23.0852211435,"rsNumLosses":0,"sc_squad":1855100,"vehicleDamage":2523,"rsShotsHit":0,"sc_bountyhunter":null,"spm_engineer":null,"flagCaptures":5521,"kitKillStreak":{},"serviceStars":{"8":10,"1":42,"2":6,"2048":10,"32":7},"dogtagsTaken":185,"sc_turfwar":null,"scoreMultiplier":0,"kitLongestHeadshot":{},"deaths":15470,"reDeploys":null,"sc_professional":null,"clubRepution":null,"sniperRifleHeadshots":855,"killAssists":2259,"LMGAccuracy":0.120160849,"rsDeaths":0,"maxMeleeKillsInRound":null,"tdmWins":null,"gameModeServiceStarsSilver":{},"cashPerMinute":null,"rushLosses":null,"resupplies":2476,"totalScore":20500085,"sc_hacker":null,"headshots":4532,"repairs":618,"shotsFired":1099510,"avengerKills":2075,"squadRushWlr":null,"conquestLosses":null,"cs_deaths":null,"rsNumWins":0,"gameModeServiceStarsBronze":{},"squadDmWlr":null,"spm_support":null,"maxHeadshotsInRound":null,"score":20500085,"kills_recon":2451,"kitTimes":{"8":"210746","1":"708950","2":"118946","2048":"46278","32":"171331"},"timePlayedDelta":0,"squadRushWins":null,"sc_hit":null,"kitTimesInPercentage":{"8":16.7757876412,"1":56.4337859234,"2":9.4683307715,"2048":3.6838179631,"32":13.6382777009},"rankScore":20495300,"kitMaxKillsInRound":{},"accuracy":15.6488799556,"timePlayed":2171290,"sc_squadheist":null,"assaultRifleHeadshots":2450,"kitScores":{"8":"1049540","1":"6636560","2":"804026","2048":"207762","32":"1062940"},"suppressionAssists":1660,"scoreDelta":0,"kills_support":2848,"kitMaxHeadshotsInRound":{},"kills_engineer":1562,"cs_wins":null,"killsPerMinute":0.64,"sniperRifleKills":1880,"scorePerMinute":566,"timePlayedSinceLastReset":0,"winPercentage":null,"tdmWlr":null,"rsScorePerMinute":0.0,"combatScore":13098078,"tdmLosses":null,"sc_mechanic":null,"numRounds":1854,"antiAirSoldier":10.0,"sc_hostage":null,"sc_commander":null,"maxKillsInRound":null,"killStreakBonus":58,"lastReset":0,"sc_deathmatch":null,"cs_skill":null,"spm_recon":null,"rsShotsFired":0,"mcomDestroy":0.0,"shotsHit":172061,"serviceStarsGameModes":[{"serviceStars":251,"serviceStarsProgress":17.7142857143,"progressCodeNeeded":null,"actualValue":5274720,"codeNeeded":"sc_conquest","tier":null,"valueNeeded":5292000,"name":null},{"serviceStars":12,"serviceStarsProgress":27.8,"progressCodeNeeded":null,"actualValue":184170,"codeNeeded":"sc_rush","tier":null,"valueNeeded":195000,"name":null},{"serviceStars":5,"serviceStarsProgress":46.6666666667,"progressCodeNeeded":null,"actualValue":32800,"codeNeeded":"sc_deathmatch","tier":null,"valueNeeded":36000,"name":null},{"serviceStars":3,"serviceStarsProgress":77.7777777778,"progressCodeNeeded":null,"actualValue":17000,"codeNeeded":"sc_elimination","tier":null,"valueNeeded":18000,"name":null}],"numLosses":700,"spm_assault":null,"cp_loses":null,"sc_general":4577110,"saviorKills":1813,"cs_loses":null,"squadDMLosses":null,"maxScoreInRound":null,"meleeKills":null,"assaultRifleKills":11309},"rankNeeded":{"name":"WARSAW_ID_P_RANK128_NAME","level":128,"pointsNeeded":21030000,"texture":"UI\/Art\/Persistence\/Ranks\/Rank128","iconImageConfig":{"category":"rank_icon","slug":"r128","texture":"UI\/Art\/Persistence\/ranks\/IconsScoreboard\/r128","versions":{"small":{"path":"warsaw\/gamedata\/rank_icon\/small.png","isSprite":true,"height":23,"name":"small","width":29},"smallns":{"path":"warsaw\/gamedata\/rank_icon\/smallns\/r128.png","isSprite":false,"height":23,"name":"smallns","width":29}}},"guid":"9AC7B2DF-C736-4721-BE14-61F75A4AB816","imageConfig":{"category":"rank","slug":"r128","texture":"UI\/Art\/Persistence\/Ranks\/Rank128","versions":{"large":{"path":"warsaw\/gamedata\/rank\/large\/r128.png","isSprite":false,"height":256,"name":"large","width":256},"smallinv":{"path":"warsaw\/gamedata\/rank\/smallinv.png","isSprite":true,"height":64,"name":"smallinv","width":64},"medium":{"path":"warsaw\/gamedata\/rank\/medium.png","isSprite":true,"height":128,"name":"medium","width":128},"tiny":{"path":"warsaw\/gamedata\/rank\/tiny.png","isSprite":true,"height":29,"name":"tiny","width":29},"tinyinv":{"path":"warsaw\/gamedata\/rank\/tinyinv.png","isSprite":true,"height":29,"name":"tinyinv","width":29},"small":{"path":"warsaw\/gamedata\/rank\/small.png","isSprite":true,"height":64,"name":"small","width":64},"mediumns":{"path":"warsaw\/gamedata\/rank\/mediumns\/r128.png","isSprite":false,"height":128,"name":"mediumns","width":128},"smallns":{"path":"warsaw\/gamedata\/rank\/smallns\/r128.png","isSprite":false,"height":64,"name":"smallns","width":64}}}}}}
the code for the catching:
//CODE FROM: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/NsITraceableChannel#Example
let { CC, Ci, Cu } = require("chrome");
Cu.import('resource://gre/modules/Services.jsm');
var BinaryInputStream = CC('#mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream');
var BinaryOutputStream = CC('#mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream');
var StorageStream = CC('#mozilla.org/storagestream;1', 'nsIStorageStream', 'init');
function TracingListener() {
this.receivedChunks = []; // array for incoming data. holds chunks as they come, onStopRequest we join these junks to get the full source
this.responseBody; // we'll set this to the
this.responseStatusCode;
this.deferredDone = {
promise: null,
resolve: null,
reject: null
};
this.deferredDone.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this.deferredDone));
Object.freeze(this.deferredDone);
this.promiseDone = this.deferredDone.promise;
}
TracingListener.prototype = {
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
var iStream = new BinaryInputStream(aInputStream) // binaryaInputStream
var sStream = new StorageStream(8192, aCount, null); // storageStream // not sure why its 8192 but thats how eveyrone is doing it, we should ask why
var oStream = new BinaryOutputStream(sStream.getOutputStream(0)); // binaryOutputStream
// Copy received data as they come.
var data = iStream.readBytes(aCount);
this.receivedChunks.push(data);
oStream.writeBytes(data, aCount);
this.originalListener.onDataAvailable(aRequest, aContext, sStream.newInputStream(0), aOffset, aCount);
},
onStartRequest: function(aRequest, aContext) {
this.originalListener.onStartRequest(aRequest, aContext);
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
this.responseBody = this.receivedChunks.join("");
delete this.receivedChunks;
this.responseStatus = aStatusCode;
this.originalListener.onStopRequest(aRequest, aContext, aStatusCode);
this.deferredDone.resolve();
},
QueryInterface: function(aIID) {
if (aIID.equals(Ci.nsIStreamListener) || aIID.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
//my Battlereport Listener
function battlereportListener(callback){
got_battlereport = callback
}
battlereportListener.prototype.httpResponseObserver = {
observe: function(aSubject, aTopic, aData) {
aSubject.QueryInterface(Ci.nsIHttpChannel);
let url = aSubject.URI.spec;
if(url.indexOf("http://battlelog.battlefield.com/bf4/indexstats") != -1){
//console.log('Found a battlereport !!')
var newListener = new TracingListener();
aSubject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = aSubject.setNewListener(newListener);
newListener.promiseDone.then(
function() {
// no error happened
got_battlereport(newListener.responseBody)
},
function(aReason){
// promise was rejected, right now i didnt set up rejection, but i should listen to on abort or bad status code then reject maybe
}
).catch(
function(aCatch) {
console.error('something went wrong, a typo by dev probably:', aCatch);
}
);
}
}
};
battlereportListener.prototype.state = false
battlereportListener.prototype.start = function(){
if(this.state == false){
Services.obs.addObserver(this.httpResponseObserver, 'http-on-examine-response', false);
this.state = true;
}
};
battlereportListener.prototype.stop = function(){
if(this.state == true){
Services.obs.removeObserver(this.httpResponseObserver, 'http-on-examine-response');
this.state = false;
}
};
exports.battlereportListener = battlereportListener
I just tested it with Firefox and it works fine. However, with Firefox Developer Edition it comes to this binary code.

Related

WebRTC datachannel wont send?

Lately I've been trying to implement WebRTC datachannels in Haxe, but come across a great deal of difficulty. When I use
dataChannel.send();
there appears to be no effect, despite the data channel supposedly being successfully opened.
The (extremely inefficient and messy) code I'm using looks like this:
package arm;
import haxe.Json;
import js.html.rtc.*;
import js.html.Document;
import js.html.WebSocket;
import js.html.DataElement;
#:expose
class DataChannelManager extends iron.Trait {
var user = "gobbledygook";
var first = false;
var initiator = true;
public function new() {
super();
var document = new Document();
var ws:js.html.WebSocket;
var config = {"iceServers":[{"url":"stun:stun.l.google.com:19302"}]};//temporary arrangement
//var optional:Array<Dynamic> = [{'DtlsSrtpKeyAgreement': true}, {'RtcDataChannels': true }];
// var connection:Dynamic = {
// 'optional'://try changing this to mandatory some time
// optional
// };
var peerConnection = new PeerConnection(config);
var dataChannel:js.html.rtc.DataChannel;
var ready = false;
function sendNegotiation(type, sdp) {
var json = {user:user/*, theloc:myloc*/, action: type, data: sdp};
ws.send(Json.stringify(json));
trace("Negotiation of type "+json.action);
}
var sdpConstraints = {
offerToReceiveAudio: false,
offerToReceiveVideo: false
};
var dcOpen=false;
notifyOnInit(function() {
var optionalStruct:Dynamic = {reliable: true}
dataChannel = peerConnection.createDataChannel("datachannel", optionalStruct);
dataChannel.onmessage = function(e){trace("DC message:" +e.data);};
dataChannel.onopen = function(){trace("-DC OPENED");dcOpen=true;};
dataChannel.onclose = function(){trace("-DC closed!");};
dataChannel.onerror = function(){trace("DC ERROR");};
trace("intialization!");
});
var firstfirst=true;
notifyOnUpdate(function() {
if (dcOpen) {
dcOpen=false;
trace("sending...");
dataChannel.send("stuff!");
}
if (firstfirst&&object.properties['go']) {
user=object.properties['string'];
first=true;
firstfirst=false;
// if (initiator) {
// peerConnection.createOffer(sdpConstraints).then(function (sdp) {
// peerConnection.setLocalDescription(sdp);
// sendNegotiation("offer", sdp);
// trace("SEND OFFER");
// }, function (data) {
// trace("Offer creation failure,", data);
// });
// } else {
// peerConnection.createAnswer(sdpConstraints).then(function (sdp) {
// trace("Answer made.");
// peerConnection.setLocalDescription(sdp);
// sendNegotiation("answer", sdp);
// });
// }
}
if (first) {
first=false;
ws = new WebSocket("ws://----------/*yes, there's an ip here*/:8080");
ws.onopen = function() {
trace("ws opened!");
peerConnection.onicecandidate = function(event) {
trace("ICE offer ready");
if (peerConnection==null || event ==null || event.candidate == null) return;
sendNegotiation("candidate", event.candidate);
}
if (initiator) {
trace("initiating");
// var optionalStruct:Dynamic = {reliable: true}
// dataChannel = peerConnection.createDataChannel("datachannel", optionalStruct);
// dataChannel.onmessage = function(e){trace("DC message:" +e.data);};
// dataChannel.onopen = function(){trace("-DC OPENED");dcOpen=true;};
// dataChannel.onclose = function(){trace("-DC closed!");};
// dataChannel.onerror = function(){trace("DC ERROR");};
peerConnection.createOffer(/*sdpConstraints*/).then(function (sdp) {
peerConnection.setLocalDescription(sdp);
sendNegotiation("offer", sdp);
trace("SEND OFFER");
}, function (data) {
trace("Offer creation failure,", data);
});
}
ws.onmessage = function (data) {
//var info=data.data.split()
if (data.data=="connected!") {return;}
var adata = Json.parse(data.data.substring(5));
if (adata.action=="offer") {
trace("Offer recieved.");
// var optionalStruct:Dynamic = {reliable: true}
// dataChannel = peerConnection.createDataChannel("datachannel", optionalStruct);
// dataChannel.onmessage = function(e){trace("DC message:" +e.data);};
// dataChannel.onopen = function(){trace("DC OPENED");dcOpen=true;};
// dataChannel.onclose = function(){trace("DC CLOSED");};
// dataChannel.onerror = function(){trace("DC ERROR");};
peerConnection.setRemoteDescription(/*try variations here*/ adata.data);
peerConnection.createAnswer(sdpConstraints).then(function (sdp) {
trace("Answer made.");
peerConnection.setLocalDescription(sdp);
sendNegotiation("answer", sdp);
});
}
if (adata.action=="answer") {
trace("Answer recieved.");
peerConnection.setRemoteDescription(/*try variations here*/ adata.data);
}
if (adata.action=="candidate") {
trace("ICE candidate recieved, looks like:",adata);
var soItDoesntComplain:Dynamic = adata.data;
peerConnection.addIceCandidate(soItDoesntComplain);
}
}
}
}
if (ready) {
trace("connected to net");
}
});
// notifyOnRemove(function() {
// });
}
}
You will notice a great deal of code is commented out -- I was expirementing with moving the dataChannel creation around.
For a better idea of what the issue is, here is the console output for the recieving and initiating clients, respectively:
In case you are wondering, notifyOnInit gets a function that is executed once at the beginning, and notifyOnUpdate gets a function called at a regular interval. object.properties['go'] is set by a different class when the username is given.
The JS api is basically the same (as far as I can tell, I haven't used WebRTC at all in the past), I haven't noticed any differences yet and I'm very sure that my issue is my fault and not Haxe's.
Thank you to those who answer.
this is not answer.
Anxious point.
peerCoonection.createOffer()
peerCoonection.createAnswer()
peerCoonection.setLocalDescription()
peerCoonection.setRemoteDescription()
peerCoonection.addIceCandidate()
are await is required.

How can I get a variable from a JavaScript promises (python calls), avoiding the pending state in Odoo?

Original code from the Point of Sale module
In the point_of_sale module there is a list of objects as the following
module.PosModel = Backbone.Model.extend({
models: {
// [...]
{
model: 'pos.session',
fields: ['id', 'journal_ids','name','user_id','config_id','start_at','stop_at','sequence_number','login_number'],
domain: function(self){ return [['state','=','opened'],['user_id','=',self.session.uid]]; },
loaded: function(self,pos_sessions){
self.pos_session = pos_sessions[0];
var orders = self.db.get_orders();
for (var i = 0; i < orders.length; i++) {
self.pos_session.sequence_number = Math.max(self.pos_session.sequence_number, orders[i].data.sequence_number+1);
}
},
},
{
model: 'product.product',
fields: ['display_name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code',
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description',
'product_tmpl_id'],
domain: [['sale_ok','=',true],['available_in_pos','=',true]],
context: function(self){ return { pricelist: self.pricelist.id, display_default_code: false }; },
loaded: function(self, products){
self.db.add_products(products);
},
// [...]
}
And then the information of the data is loaded like this
load_server_data: function(){
var self = this;
var loaded = new $.Deferred();
var progress = 0;
var progress_step = 1.0 / self.models.length;
var tmp = {}; // this is used to share a temporary state between models loaders
function load_model(index){
if(index >= self.models.length){
loaded.resolve();
}else{
var model = self.models[index];
self.pos_widget.loading_message(_t('Loading')+' '+(model.label || model.model || ''), progress);
var fields = typeof model.fields === 'function' ? model.fields(self,tmp) : model.fields;
var domain = typeof model.domain === 'function' ? model.domain(self,tmp) : model.domain;
var context = typeof model.context === 'function' ? model.context(self,tmp) : model.context;
var ids = typeof model.ids === 'function' ? model.ids(self,tmp) : model.ids;
progress += progress_step;
if( model.model ){
if (model.ids) {
var records = new instance.web.Model(model.model).call('read',[ids,fields],context);
} else {
var records = new instance.web.Model(model.model).query(fields).filter(domain).context(context).all()
}
// [...]
What I have tried. First try
So, I would like to change the domain field of the product.product model. I am trying with this
if (typeof jQuery === 'undefined') { throw new Error('Product multi POS needs jQuery'); }
+function ($) {
'use strict';
openerp.pos_product_multi_shop = function(instance, module) {
var PosModelParent = instance.point_of_sale.PosModel;
instance.point_of_sale.PosModel = instance.point_of_sale.PosModel.extend({
load_server_data: function(){
console.log('-- LOAD SERVER DATA');
var self = this;
self.models.forEach(function(elem) {
if (elem.model == 'product.product') {
// return [['id', 'in', [2]]]; // if I return this domain it works well
domain_loaded = function() {
return new instance.web.Model('product.product').call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
)
}
elem.domain = $.when(domain_loaded);
}
})
var loaded = PosModelParent.prototype.load_server_data.apply(this, arguments);
return loaded;
},
});
}
}(jQuery);
If I return a domain directly it works. But if I replace it with a function that calls a python function with call, the domain is not loaded well: [['sale_ok','=',true],['available_in_pos','=',true]]. I've tried with $.when and without it and it does not work.
In addition elem.domain must be a function because self.pos_session only exists when all the previous model information is executed.
Second try
I have tried this following code as well:
if (elem.model == 'product.product') {
// return [['id', 'in', [2]]]; // if I return the domain like this it works
console.log('>> OLD DOMAIN')
console.log(elem.domain);
elem.domain = function() {
console.log('>>> PRODUCT SESSION');
console.log(self.pos_session);
var product_product_obj = new instance.web.Model('product.product');
return product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
)
}
console.log('>> NEW DOMAIN')
console.log(elem.domain);
}
So first '>> OLD DOMAIN' is printed, then '>> NEW DOMAIN' and, at last '>>> PRODUCT SESSION' is printed. So the function is executed. But the the domains is not being returned well.
Third try. With "then"
And I cannot use then because I need to do the variable assignation. But on the other hand the assignation is well done becase when I print the new domain the function appears in the log.
Even if I use then I am getting the result well from python
var domain_return = product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
).then(function(result) {
console.log('>> RESULT: ');
console.log(result)
});
I also tried with other promise, but I get a pending result that is ignored and all the products are shown
elem.domain = function() {
return new Promise(function next(resolve, reject) {
console.log('>>> PRODUCT SESSION');
console.log(self.pos_session);
var product_product_obj = new instance.web.Model('product.product');
var domain_return = product_product_obj.call(
'get_available_in_pos_ids',
[self.pos_session.config_id[0]],
).then(function(result) {
console.log('>> RETURN: ');
console.log(result);
resolve(result);
});
console.log('>> DOMAIN RETURN: ');
console.log(domain_return);
});
}
The rest of the domains of the object are calculated without calling python functions. So I can't copy an example from other place
So, is there a way to avoid the pending result? I cannot use async/await yet.
Maybe to make it syncronous will help but I know this should be avoided
Finally I found a workaround overriding the loaded function where all the products are already loaded
var PosModelParent = instance.point_of_sale.PosModel;
instance.point_of_sale.PosModel = instance.point_of_sale.PosModel.extend({
load_server_data: function(){
let self = this;
self.models.forEach(function(elem) {
if (elem.model == 'product.product') {
elem.fields = ['display_name', 'list_price','price','pos_categ_id', 'taxes_id', 'ean13', 'default_code',
'to_weight', 'uom_id', 'uos_id', 'uos_coeff', 'mes_type', 'description_sale', 'description',
'product_tmpl_id', 'available_in_pos_ids'];
elem.loaded = function(self, products){
console.log('>> PRODUCTS: ');
console.log(products);
var shop_id = self.pos_session.config_id[0];
var new_products = [];
products.forEach(function(prod) {
if (prod.available_in_pos_ids.includes(shop_id)) {
new_products.push(prod);
}
})
self.db.add_products(new_products);
}
}
})
var loaded = PosModelParent.prototype.load_server_data.apply(this, arguments);
return loaded;
},
});

Working example for signal protocol in js

Hi there i try to make i clientside message exchange with the signal protocol (only for tests). But i have trouble to the proccessPreKey.
Here is the test code
<script src="javascripts/libsignal-protocol.js"></script>
<script src="javascripts/InMemorySignalProtocolStore.js"></script>
<script>
var KeyHelperUser1 = libsignal.KeyHelper;
var KeyHelperUser2 = libsignal.KeyHelper;
var registrationId_User1 = KeyHelperUser1.generateRegistrationId();
var registrationId_User2 = KeyHelperUser2.generateRegistrationId();
// Store registrationId somewhere durable and safe.
var identityKeyPair_User1, identityKeyPair_User2;
var SignedPreKey_User1, SignedPreKey_User2;
// Test Store
var store_User1 = new SignalProtocolStore();
var store_User2 = new SignalProtocolStore();
var PreKey_User1, PreKey_User2;
// Build the session
var address_User1 = new libsignal.SignalProtocolAddress(1002, 0);
var address_User2 = new libsignal.SignalProtocolAddress(1001, 0);
var sessionBuilder_User1 = new libsignal.SessionBuilder(store_User1, address_User1);
var sessionBuilder_User2 = new libsignal.SessionBuilder(store_User2, address_User2);
KeyHelperUser1.generateIdentityKeyPair().then(function(identityKeyPair) {
// keyPair -> { pubKey: ArrayBuffer, privKey: ArrayBuffer }
// Store identityKeyPair somewhere durable and safe.
identityKeyPair_User1 = identityKeyPair;
KeyHelperUser1.generatePreKey(1001).then(function(preKey) {
//store.storePreKey(preKey.keyId, preKey.keyPair);
PreKey_User1 = preKey;
KeyHelperUser2.generatePreKey(1002).then(function(preKey) {
//store.storePreKey(preKey.keyId, preKey.keyPair);
PreKey_User2 = preKey;
KeyHelperUser1.generateSignedPreKey(identityKeyPair_User1, 1001).then(function(signedPreKey) {
store_User1.storeSignedPreKey(signedPreKey.keyId, signedPreKey.keyPair);
SignedPreKey_User1 = signedPreKey;
KeyHelperUser2.generateIdentityKeyPair().then(function(identityKeyPair) {
// keyPair -> { pubKey: ArrayBuffer, privKey: ArrayBuffer }
// Store identityKeyPair somewhere durable and safe.
identityKeyPair_User2 = identityKeyPair;
KeyHelperUser2.generateSignedPreKey(identityKeyPair_User2, 1002).then(function(signedPreKey) {
store_User2.storeSignedPreKey(signedPreKey.keyId, signedPreKey.keyPair);
SignedPreKey_User2 = signedPreKey;
var promise_User1 = sessionBuilder_User1.processPreKey({
registrationId: registrationId_User2,
identityKey: identityKeyPair_User2.pubKey,
signedPreKey: {
keyId : 1002,
publicKey : SignedPreKey_User2.pubKey,
signature : SignedPreKey_User2.signature
},
preKey: {
keyId : 1002,
publicKey : PreKey_User1.pubKey
}
});
promise_User1.catch(function onerror(error) {
// handle identity key conflict
//console.log(error);
});
});
});
});
});
});
});
</script>
I don't really know which parameters the processPreKey wanted. Can someone help?
Hey so this is something i put together, hope it helps.
var KeyHelper = libsignal.KeyHelper;
function generateIdentity(store) {
return Promise.all([
KeyHelper.generateIdentityKeyPair(),
KeyHelper.generateRegistrationId(),
]).then(function(result) {
store.put('identityKey', result[0]);
store.put('registrationId', result[1]);
});
}
function generatePreKeyBundle(store, preKeyId, signedPreKeyId) {
return Promise.all([
store.getIdentityKeyPair(),
store.getLocalRegistrationId()
]).then(function(result) {
var identity = result[0];
var registrationId = result[1];
return Promise.all([
KeyHelper.generatePreKey(preKeyId),
KeyHelper.generateSignedPreKey(identity, signedPreKeyId),
]).then(function(keys) {
var preKey = keys[0]
var signedPreKey = keys[1];
store.storePreKey(preKeyId, preKey.keyPair);
store.storeSignedPreKey(signedPreKeyId, signedPreKey.keyPair);
return {
identityKey: identity.pubKey,
registrationId : registrationId,
preKey: {
keyId : preKeyId,
publicKey : preKey.keyPair.pubKey
},
signedPreKey: {
keyId : signedPreKeyId,
publicKey : signedPreKey.keyPair.pubKey,
signature : signedPreKey.signature
}
};
});
});
}
var ALICE_ADDRESS = new libsignal.SignalProtocolAddress("xxxxxxxxx", 1);
var BOB_ADDRESS = new libsignal.SignalProtocolAddress("yyyyyyyyyyyyy", 1);
var aliceStore = new libsignal.SignalProtocolStore();
var bobStore = new libsignal.SignalProtocolStore();
var bobPreKeyId = 1337;
var bobSignedKeyId = 1;
var Curve = libsignal.Curve;
Promise.all([
generateIdentity(aliceStore),
generateIdentity(bobStore),
]).then(function() {
return generatePreKeyBundle(bobStore, bobPreKeyId, bobSignedKeyId);
}).then(function(preKeyBundle) {
var builder = new libsignal.SessionBuilder(aliceStore, BOB_ADDRESS);
return builder.processPreKey(preKeyBundle).then(function() {
var originalMessage = util.toArrayBuffer("my message ......");
var aliceSessionCipher = new libsignal.SessionCipher(aliceStore, BOB_ADDRESS);
var bobSessionCipher = new libsignal.SessionCipher(bobStore, ALICE_ADDRESS);
aliceSessionCipher.encrypt(originalMessage).then(function(ciphertext) {
// check for ciphertext.type to be 3 which includes the PREKEY_BUNDLE
return bobSessionCipher.decryptPreKeyWhisperMessage(ciphertext.body, 'binary');
}).then(function(plaintext) {
alert(plaintext);
});
bobSessionCipher.encrypt(originalMessage).then(function(ciphertext) {
return aliceSessionCipher.decryptWhisperMessage(ciphertext.body, 'binary');
}).then(function(plaintext) {
assertEqualArrayBuffers(plaintext, originalMessage);
});
});
});
Not enough rep to comment; just addressing the comments below the answer.
#Niczem Olaske, the util.toArrayBuffer([message]) can be removed. The returned ciphertext is already an arrayBuffer, and converting the message to an arrayBuffer prior to encryption creates the need to convert it back to a string at the end anyway. However, a global 'util' object must be declared in order for libsignal to work (at least in JavaScript). So you can just put: const util = {}; somewhere outside function bodies, or alternatively: Object.assign(window, { util: {} }); before using libsignal.
#Hasib Mahmud, this error is from Bob trying to encrypt a message to Alice when a session has not yet been established. If you use async/await instead of .then(() => etc...), you will avoid this problem. Bob must decrypt Alice's message first in order to establish a session with her, and then encrypt messages to her. Note that he needs to use the 'decryptPreKeyWhisperMessage' method in order to use her preKey to establish the session whilst calling the method. After the session has been established on both sides, he can use the 'decryptWhisperMessage' method.

Service worker SW-Toolbox cached api response gets deleted when navigated to other URL

I am using sw-precache module with sw-toolbox. When i navigate to the web app url, the api response is cached in the toolbox cache storage and then if i turn off the internet and refresh the url. Service worker loads the api with a 200OK response from Service Worker Cache but if i navigate to some other url and then come back to the main web app. All the dynamic cached api response of the toolbox cache storage gets deleted. I am using gulp to create the service worker file. The gulp code to generate the file is mentioned below:
gulp.task('generate-service-worker', function(callback) {
var path = require('path');
var swPrecache = require('sw-precache');
var rootDir = './src';
swPrecache.write(path.join(rootDir, 'sw.js'), {
staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif}'],
stripPrefix: rootDir,
importScripts: [
'sw-toolbox.js',
'toolbox-routes.js'
]
}, callback);
});
The sw-toolbox.js has the code generated from bower components of sw-toolbox library. The toolbox-routes.js has four calls as mentioned below:
toolbox.router.get(/^https:\/\/.*\/city/, toolbox.cacheFirst, {});
toolbox.router.get(/^https:\/\/.*\/splash/, toolbox.cacheFirst, {});
toolbox.router.get(/^https:\/\/.*amazonaws\.com\/.*/, toolbox.cacheFirst, {});
toolbox.router.get(/^https:\/\/.*\/api\/booking/, toolbox.networkFirst, {});
The city api looks something like this api for which i get a 404 error.
https://www.abcd.com/city?includes=venue,car
I also get a warning message in the console which says "The FetchEvent for "https://www.abcd.com/city?includes=venue,car" resulted in a network error response: the promise was rejected."
The service worker file is this
'use strict';
importScripts("sw-toolbox.js", "toolbox-routes.js");
/* eslint-disable quotes, comma-spacing */
var PrecacheConfig = [
["/app/directives/datepicker/datepicker.html", "fa21126be162d099882132226c9681d2"],
["/app/directives/datepicker/datepicker.js", "5ec9f32a36e10feeb03c40d984e74058"],
["/app/directives/map/map.js", "cfabf0230663391d8c78f46a2b198f89"],
["/index.html", "98b8890a31f58d2362953593bbda427f"],
["/index.notification.js", "0cf8aa857d28c309f7b37b97141c1853"],
["/sw-toolbox.js", "66531e5962e4dccb0526a2b4cd6364a4"],
["/toolbox-routes.js", "e7e168157a8afc939ecfb44da773270d"]
];
/* eslint-enable quotes, comma-spacing */
var CacheNamePrefix = 'sw-precache-v1--' + (self.registration ? self.registration.scope : '') + '-';
var IgnoreUrlParametersMatching = [/^utm_/];
var addDirectoryIndex = function(originalUrl, index) {
var url = new URL(originalUrl);
if (url.pathname.slice(-1) === '/') {
url.pathname += index;
}
return url.toString();
};
var getCacheBustedUrl = function(url, param) {
param = param || Date.now();
var urlWithCacheBusting = new URL(url);
urlWithCacheBusting.search += (urlWithCacheBusting.search ? '&' : '') +
'sw-precache=' + param;
return urlWithCacheBusting.toString();
};
var isPathWhitelisted = function(whitelist, absoluteUrlString) {
// If the whitelist is empty, then consider all URLs to be whitelisted.
if (whitelist.length === 0) {
return true;
}
// Otherwise compare each path regex to the path of the URL passed in.
var path = (new URL(absoluteUrlString)).pathname;
return whitelist.some(function(whitelistedPathRegex) {
return path.match(whitelistedPathRegex);
});
};
var populateCurrentCacheNames = function(precacheConfig,
cacheNamePrefix, baseUrl) {
var absoluteUrlToCacheName = {};
var currentCacheNamesToAbsoluteUrl = {};
precacheConfig.forEach(function(cacheOption) {
var absoluteUrl = new URL(cacheOption[0], baseUrl).toString();
var cacheName = cacheNamePrefix + absoluteUrl + '-' + cacheOption[1];
currentCacheNamesToAbsoluteUrl[cacheName] = absoluteUrl;
absoluteUrlToCacheName[absoluteUrl] = cacheName;
});
return {
absoluteUrlToCacheName: absoluteUrlToCacheName,
currentCacheNamesToAbsoluteUrl: currentCacheNamesToAbsoluteUrl
};
};
var stripIgnoredUrlParameters = function(originalUrl,
ignoreUrlParametersMatching) {
var url = new URL(originalUrl);
url.search = url.search.slice(1) // Exclude initial '?'
.split('&') // Split into an array of 'key=value' strings
.map(function(kv) {
return kv.split('='); // Split each 'key=value' string into a [key, value] array
})
.filter(function(kv) {
return ignoreUrlParametersMatching.every(function(ignoredRegex) {
return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes.
});
})
.map(function(kv) {
return kv.join('='); // Join each [key, value] array into a 'key=value' string
})
.join('&'); // Join the array of 'key=value' strings into a string with '&' in between each
return url.toString();
};
var mappings = populateCurrentCacheNames(PrecacheConfig, CacheNamePrefix, self.location);
var AbsoluteUrlToCacheName = mappings.absoluteUrlToCacheName;
var CurrentCacheNamesToAbsoluteUrl = mappings.currentCacheNamesToAbsoluteUrl;
function deleteAllCaches() {
return caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
return caches.delete(cacheName);
})
);
});
}
self.addEventListener('install', function(event) {
event.waitUntil(
// Take a look at each of the cache names we expect for this version.
Promise.all(Object.keys(CurrentCacheNamesToAbsoluteUrl).map(function(cacheName) {
return caches.open(cacheName).then(function(cache) {
// Get a list of all the entries in the specific named cache.
// For caches that are already populated for a given version of a
// resource, there should be 1 entry.
return cache.keys().then(function(keys) {
// If there are 0 entries, either because this is a brand new version
// of a resource or because the install step was interrupted the
// last time it ran, then we need to populate the cache.
if (keys.length === 0) {
// Use the last bit of the cache name, which contains the hash,
// as the cache-busting parameter.
// See https://github.com/GoogleChrome/sw-precache/issues/100
var cacheBustParam = cacheName.split('-').pop();
var urlWithCacheBusting = getCacheBustedUrl(
CurrentCacheNamesToAbsoluteUrl[cacheName], cacheBustParam);
var request = new Request(urlWithCacheBusting, {
credentials: 'same-origin'
});
return fetch(request).then(function(response) {
if (response.ok) {
return cache.put(CurrentCacheNamesToAbsoluteUrl[cacheName],
response);
}
console.error('Request for %s returned a response status %d, ' +
'so not attempting to cache it.',
urlWithCacheBusting, response.status);
// Get rid of the empty cache if we can't add a successful response to it.
return caches.delete(cacheName);
});
}
});
});
})).then(function() {
return caches.keys().then(function(allCacheNames) {
return Promise.all(allCacheNames.filter(function(cacheName) {
return cacheName.indexOf(CacheNamePrefix) === 0 &&
!(cacheName in CurrentCacheNamesToAbsoluteUrl);
}).map(function(cacheName) {
return caches.delete(cacheName);
}));
});
}).then(function() {
if (typeof self.skipWaiting === 'function') {
// Force the SW to transition from installing -> active state
self.skipWaiting();
}
})
);
});
if (self.clients && (typeof self.clients.claim === 'function')) {
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim());
});
}
self.addEventListener('message', function(event) {
if (event.data.command === 'delete_all') {
console.log('About to delete all caches...');
deleteAllCaches().then(function() {
console.log('Caches deleted.');
event.ports[0].postMessage({
error: null
});
}).catch(function(error) {
console.log('Caches not deleted:', error);
event.ports[0].postMessage({
error: error
});
});
}
});
self.addEventListener('fetch', function(event) {
if (event.request.method === 'GET') {
var urlWithoutIgnoredParameters = stripIgnoredUrlParameters(event.request.url,
IgnoreUrlParametersMatching);
var cacheName = AbsoluteUrlToCacheName[urlWithoutIgnoredParameters];
var directoryIndex = 'index.html';
if (!cacheName && directoryIndex) {
urlWithoutIgnoredParameters = addDirectoryIndex(urlWithoutIgnoredParameters, directoryIndex);
cacheName = AbsoluteUrlToCacheName[urlWithoutIgnoredParameters];
}
var navigateFallback = '';
// Ideally, this would check for event.request.mode === 'navigate', but that is not widely
// supported yet:
// https://code.google.com/p/chromium/issues/detail?id=540967
// https://bugzilla.mozilla.org/show_bug.cgi?id=1209081
if (!cacheName && navigateFallback && event.request.headers.has('accept') &&
event.request.headers.get('accept').includes('text/html') &&
/* eslint-disable quotes, comma-spacing */
isPathWhitelisted([], event.request.url)) {
/* eslint-enable quotes, comma-spacing */
var navigateFallbackUrl = new URL(navigateFallback, self.location);
cacheName = AbsoluteUrlToCacheName[navigateFallbackUrl.toString()];
}
if (cacheName) {
event.respondWith(
// Rely on the fact that each cache we manage should only have one entry, and return that.
caches.open(cacheName).then(function(cache) {
return cache.keys().then(function(keys) {
return cache.match(keys[0]).then(function(response) {
if (response) {
return response;
}
// If for some reason the response was deleted from the cache,
// raise and exception and fall back to the fetch() triggered in the catch().
throw Error('The cache ' + cacheName + ' is empty.');
});
});
}).catch(function(e) {
console.warn('Couldn\'t serve response for "%s" from cache: %O', event.request.url, e);
return fetch(event.request);
})
);
}
}
});
Thanks a tonnn in Advance!!!.

Global variable only accessible to first function?

I have an OK understanding of JS but am ultimately still learning. I'm trying to recreate a PHP/mySQL project over to IndexedDB and can't work out why I'm seeing an error here.
The IndexedDB connection works as expected. The first function (createItem) functions fine, however the second function (getItems) is returning an error claiming that the "db" variable is undefined. It's a global variable so should be accessible by the function's scope, and the createItem function has no problem using it. Can anyone help me see what I've missed here.
// GLOBAL DB VAR
var db;
// WAIT FOR DOM
document.addEventListener("DOMContentLoaded", function(){
// IF INDEXED DB CAPABLE
if("indexedDB" in window) {
// OPEN DB
var openRequest = indexedDB.open("newTabTest",1);
// CREATE NEW / UPDATE
openRequest.onupgradeneeded = function(e) {
// Notify user here: creating database (first time use)
var thisDB = e.target.result;
// Create "items" table if it doesn't already exist
if(!thisDB.objectStoreNames.contains("items")) {
var store = thisDB.createObjectStore("items", {keyPath: "id", autoIncrement: true});
store.createIndex("name","name", {unique:true});
store.createIndex("folder","folder", {unique:false});
store.createIndex("dial","dial", {unique:false});
}
}
openRequest.onsuccess = function(e) {
// Success- set db to target result.
db = e.target.result;
}
openRequest.onerror = function(e) {
// DB ERROR :-(
}
}
},false);
// CREATE ITEM FUNCTION
function createItem(n,u,f,c) {
var transaction = db.transaction(["items"],"readwrite");
var store = transaction.objectStore("items");
var item = {
name: n,
url: u,
folder: f,
colour: c,
dial: 0,
order: 100
}
var request = store.add(item);
request.onerror = function(e) {
console.log("An error occured.");
}
request.onsuccess = function(e) {
console.log("Successfully added.")
}
};
// GET ITEM(S) FUNCTION
// Specify index and key value OR omit for all
function getItems(callback, ind, key) {
var transaction = db.transaction(["items"],"readonly");
var store = transaction.objectStore("items");
var response = [];
// If args are omitted - grab all items
if(!ind | !key) {
var cursor = store.openCursor();
cursor.onsuccess = function(e) {
var res = e.target.result;
if(res) {
var r = {
"name": res.value['name'],
"url": res.value['url'],
"folder": res.value['folder'],
"colour": res.value['colour'],
"dial": res.value['dial'],
"order": res.value['order']
};
response.push(r);
res.continue();
}
}
cursor.oncomplete = function() {
callback(response);
}
} else {
// If both args are specified query specified index
store = store.index(ind);
var range = IDBKeyRange.bound(key, key);
store.openCursor(range).onsuccess = function(e) {
var res = e.target.result;
if(res) {
var r = {
"name": res.value['name'],
"url": res.value['url'],
"folder": res.value['folder'],
"colour": res.value['colour'],
"dial": res.value['dial'],
"order": res.value['order']
};
response.push(r);
res.continue();
}
}
cursor.oncomplete = function() {
callback(response);
}
}
};
As you've figured out in comments, you do have to stick the db-dependent actions inside a function called from a success handler.
This callback-based programming quickly becomes a pain, and a common solution for that is to use promises.
However, making IndexedDB work with promises is still work-in-progress (see https://github.com/inexorabletash/indexeddb-promises if you're interested).
If your goal is to get something done (and not to learn the bare IndexedDB APIs), perhaps you'd be better off finding a wrapper library for IndexedDB (can't recommend one though, since I've not tried working seriously with IDB yet).
I would not recommend using a variable like 'db' as you have in your example. If you are new to reading and writing asynchronous Javascript, you are just going to cause yourself a lot of pain. There are better ways to do it. It takes several pages to explain and is explained in many other questions on StackOverflow, so instead, very briefly, consider rewriting your code to do something like the following:
function createItem(db, ...) {
var tx = db.transaction(...);
// ...
}
function openIndexedDBThenCreateItem(...) {
var openRequest = indexedDB.open(...);
openRequest.onsuccess = function(event) {
var db = event.target.result;
createItem(db, ...);
};
}
function getItems(db, callback, ...) {
var tx = db.transaction(...);
var items = [];
tx.oncomplete = function(event) {
callback(items);
};
// ...
var request = store.openCursor(...);
request.onsuccess = function(event) {
var request = event.target;
var cursor = event.target.result;
if(cursor) {
var item = cursor.value;
items.push(item);
cursor.continue();
}
};
}
function openIndexedDBThenGetItems(db, callback, ...) {
var openRequest = indexedDB.open(...);
openRequest.onsuccess = function(event) {
var db = event.target.result;
getItems(db, callback, ...);
};
}
Also, you don't need to wait for DOMContentLoaded to start using indexedDB. It is immediately available.
If you get the above code, then you can consider a further improvement of adding a simple helper function:
function openIndexedDB(callback) {
var openRequest = indexedDB.open(...);
openRequest.onerror = callback;
openRequest.onsuccess = callback;
}
And then rewrite the examples like this:
function openIndexedDBThenCreateItem(...) {
openIndexedDB(function onOpen(event) {
if(event.type !== 'success') {
console.error(event);
} else {
var db = event.target.result;
createItem(db, ...);
}
});
}
function openIndexedDBThenGetItems(...) {
openIndexedDB(function onOpen(event) {
if(event.type !== 'success') {
console.error(event);
} else {
var db = event.target.result;
getItems(db, ...);
}
});
}

Categories