ThunderBird WebSocket communication

38 views
Skip to first unread message

mari...@gmail.com

unread,
Mar 30, 2020, 12:32:45 PM3/30/20
to
Hi,

In my thunderbird add-on, I'm trying to create a websocket (using mqtt protocol). I'm getting an empty error when creating the webSocket.

__________________________________________
Exception

columnNumber: 0

data: null

filename: "moz-extension://6c9bc3bf-3b1d-41be-9559-04e08a120e2d/my_file.js"

lineNumber: 23

message: ""

name: ""

result: 2153644038

stack: "@moz-extension://6c9bc3bf-3b1d-41be-9559-04e08a120e2d/my_file.js:23:15\n" //
__________________________________________


I couldn't find anything about this problem on the internet. So I have no way to know what's wrong.
This is working on Firefox by the way :

__________________________________________

try {
var socket = new WebSocket(url, ["http"]); // line 23

} catch (error) {
console.log(error);
}

__________________________________________

Thanks for your time.

mari...@gmail.com

unread,
Mar 30, 2020, 12:34:59 PM3/30/20
to
I get this error even when I'm not giving any protocol in the constructor.

mari...@gmail.com

unread,
Mar 30, 2020, 12:36:10 PM3/30/20
to
(Thunderbird version is 68.6.0)

Tito

unread,
Mar 30, 2020, 1:16:53 PM3/30/20
to mari...@gmail.com, dev-apps-t...@lists.mozilla.org
You will need to post more then just that note that constructor
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket


const socket = new WebSocket('ws://1.2.3.4:8080');



are you accessing ws or wss ?

Post the exact code not just edited version of it. First try without
dns and make sure that direct ip is working. and then try again with dns.
> _______________________________________________
> dev-apps-thunderbird mailing list
> dev-apps-t...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-apps-thunderbird
>

mari...@gmail.com

unread,
Mar 31, 2020, 1:34:07 PM3/31/20
to
This is the exact line that ThunderBird doesn't like : "this.ws = new WebSocket(url, 'mqttv3.1');"

I'm using ws.

Already tried without dns, same result : exception is empty, has no name nor message.

(Note : I'm just using localhost)

mari...@gmail.com

unread,
Mar 31, 2020, 1:35:00 PM3/31/20
to
(changing the protocol doesn't change either)

Tito

unread,
Mar 31, 2020, 2:26:01 PM3/31/20
to mari...@gmail.com, dev-apps-t...@lists.mozilla.org
post the whole file

What's the value of the "url" variable. Try not specifying the mqtt
protocol. Which message broker are you using, maybe rabbitmq? or
something customer, does this constructor work with amqp or stomp for you?

since that is ws take a trace with the tcpdump using -s0 to capture the
whole length of the frame, if possible post the capture.

Geoff Lankow

unread,
Apr 1, 2020, 3:25:35 AM4/1/20
to
On 31/03/2020 05:32, mari...@gmail.com wrote:
> Hi,
>
> In my thunderbird add-on, I'm trying to create a websocket (using mqtt protocol). I'm getting an empty error when creating the webSocket.

Does your extension have the appropriate permissions? I'm not sure how
it works for a websocket but if you were trying to access something via
HTTP you'd have to list the domain in the manifest's permissions
section. It would be the same as for a Firefox extension, so maybe
search for somebody doing something similar there.

GL

mari...@gmail.com

unread,
Apr 1, 2020, 7:56:15 AM4/1/20
to
> Does your extension have the appropriate permissions? I'm not sure how
> it works for a websocket but if you were trying to access something via
> HTTP you'd have to list the domain in the manifest's permissions
> section. It would be the same as for a Firefox extension, so maybe
> search for somebody doing something similar there.
>
> GL

I guess I would have an error indicating it if I didn't specify the right permissions, wouldn't I ?
Again, this code is working well with firefox.


Thanks for taking the time to answer.

mari...@gmail.com

unread,
Apr 1, 2020, 8:12:10 AM4/1/20
to
> What's the value of the "url" variable. Try not specifying the mqtt
> protocol.
url variable is just localHost on port 8080.

I already tried not specifying the protocol. Same result/

> Which message broker are you using, maybe rabbitmq? Does this constructor work with amqp or stomp for you?
The message broker is MQTTnet. Why would it work with amqp or stomp ?

> since that is ws take a trace with the tcpdump using -s0 to capture the
> whole length of the frame, if possible post the capture.
What do you mean "using -s0"

Whole file (I don't know how to just upload it):



mosquitto.js :
________________________________

/*
Copyright (c) 2012 Roger Light <fdsf...@dfsfsfsdf.org>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of mosquitto nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

/* Mosquitto MQTT Javascript/Websocket client */
/* Provides complete support for QoS 0.
* Will not cause an error on QoS 1/2 packets.
*/

var CONNECT = 0x10;
var CONNACK = 0x20;
var PUBLISH = 0x30;
var PUBACK = 0x40;
var PUBREC = 0x50;
var PUBREL = 0x60;
var PUBCOMP = 0x70;
var SUBSCRIBE = 0x80;
var SUBACK = 0x90;
var UNSUBSCRIBE = 0xA0;
var UNSUBACK = 0xB0;
var PINGREQ = 0xC0;
var PINGRESP = 0xD0;
var DISCONNECT = 0xE0;

function AB2S(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for(var i=0; i<len; i++){
binary += String.fromCharCode(bytes[i]);
}
return binary;
}

function Mosquitto(clientId) {
this.ws = null;
this.onconnect = null;
this.ondisconnect = null;
this.onmessage = null;
this.clientId = clientId;
}

Mosquitto.prototype = {
mqtt_ping : function()
{
var buffer = new ArrayBuffer(2);
var i8V = new Int8Array(buffer);
i8V[0] = PINGREQ;
i8V[1] = 0;
if(this.ws.readyState == 1){
this.ws.send(buffer);
}else{
this.queue(buffer);
}
//setTimeout(function(_this){_this.mqtt_ping();}, 600000, this);
},

connect : function(url, keepalive){

this.url = url;
this.keepalive = keepalive;
this.mid = 1;
this.out_queue = new Array();

this.ws = new WebSocket(url, 'mqttv3.1');
this.ws.binaryType = "arraybuffer";
this.ws.onopen = this.ws_onopen;
this.ws.onclose = this.ws_onclose;
this.ws.onmessage = this.ws_onmessage;
this.ws.m = this;
this.ws.onerror = function(evt){
alert(evt.data);
}
},

disconnect : function(){
if(this.ws.readyState == 1){
var buffer = new ArrayBuffer(2);
var i8V = new Int8Array(buffer);

i8V[0] = DISCONNECT;
i8V[1] = 0;
this.ws.send(buffer);
this.ws.close();
}
},

ws_onopen : function(evt) {
var buffer = new ArrayBuffer(1+1+12+2+20);
var i8V = new Int8Array(buffer);

i=0;
i8V[i++] = CONNECT;
i8V[i++] = 12+2+20;
i8V[i++] = 0;
i8V[i++] = 6;
str = "MQIsdp";
for(var j=0; j<str.length; j++){
i8V[i++] = str.charCodeAt(j);
}
i8V[i++] = 3;
i8V[i++] = 2;
i8V[i++] = 0;
i8V[i++] = 255;
i8V[i++] = 0;
i8V[i++] = 20;

var str = this.m.clientId;
for(var j=0; j<str.length; j++){
i8V[i++] = str.charCodeAt(j);
}

this.send(buffer);
while(this.m.out_queue.length > 0){
this.send(this.m.out_queue.pop());
}
//setTimeout(function(_this){_this.mqtt_ping();}, 60000, this.m);
},

ws_onclose : function(evt) {
if(this.m.ondisconnect){
this.m.ondisconnect(evt.data);
}
},

ws_onmessage : function(evt) {
var i8V = new Int8Array(evt.data);
buffer = evt.data;
var q=0;
while(i8V.length > 0 && q < 1000){
q++;
switch(i8V[0] & 0xF0){
case CONNACK:
var rl = i8V[1];
var rc = i8V[2];
if(this.m.onconnect){
this.m.onconnect(rc);
}
buffer = buffer.slice(rl+2);
i8V = new Int8Array(buffer);
break;
case PUBLISH:
var i=1;
var mult = 1;
var rl = 0;
var count = 0;
var digit;
var qos = (i8V[0] & 0x06) >> 1;
var retain = (i8V[0] & 0x01);
var mid = 0;
do{
count++;
digit = i8V[i++];
rl += (digit & 127)*mult;
mult *= 128;
}while((digit & 128) != 0);

var topiclen = i8V[i++]*256 + i8V[i++];
var atopic = buffer.slice(i, i+topiclen);
i+=topiclen;
var topic = AB2S(atopic);
if(qos > 0){
mid = i8V[i++]*256 + i8V[i++];
}
var apayload = buffer.slice(i, rl+count+1);
var payload = AB2S(apayload);

buffer = buffer.slice(rl+1+count);
i8V = new Int8Array(buffer);

if(this.m.onmessage){
this.m.onmessage(topic, payload, qos, retain);
}
break;
case PUBREC:
case PUBREL:
case PUBACK:
case PUBCOMP:
case SUBACK:
case UNSUBACK:
case PINGRESP:
var rl = i8V[1];
buffer = buffer.slice(rl+2);
i8V = new Int8Array(buffer);
break;
}
}
},

get_remaining_count : function(remaining_length)
{
if(remaining_length >= 0 && remaining_length < 128){
return 1;
}else if(remaining_length >= 128 && remaining_length < 16384){
return 2;
}else if(remaining_length >= 16384 && remaining_length < 2097152){
return 3;
}else if(remaining_length >= 2097152 && remaining_length < 268435456){
return 4;
}else{
return -1;
}
},

generate_mid : function()
{
var mid = this.mid;
this.mid++;
if(this.mid == 256) this.mid = 0;
return mid;
},

queue : function(buffer)
{
this.out_queue.push(buffer);
},

send_cmd_with_mid : function(cmd, mid)
{
var buffer = new ArrayBuffer(4);
var i8V = new Int8Array(buffer);
i8V[0] = cmd;
i8V[1] = 2;
i8V[2] = mid%128;
i8V[3] = mid/128;
if(this.ws.readyState == 1){
this.ws.send(buffer);
}else{
this.queue(buffer);
}
},

unsubscribe : function(topic)
{
var rl = 2+2+topic.length;
var remaining_count = this.get_remaining_count(rl);
var buffer = new ArrayBuffer(1+remaining_count+rl);
var i8V = new Int8Array(buffer);

var i=0;
i8V[i++] = UNSUBSCRIBE | 0x02;
do{
digit = Math.floor(rl % 128);
rl = Math.floor(rl / 128);
if(rl > 0){
digit = digit | 0x80;
}
i8V[i++] = digit;
}while(rl > 0);
i8V[i++] = 0;
i8V[i++] = this.generate_mid();
i8V[i++] = 0;
i8V[i++] = topic.length;
for(var j=0; j<topic.length; j++){
i8V[i++] = topic.charCodeAt(j);
}

if(this.ws.readyState == 1){
this.ws.send(buffer);
}else{
this.queue(buffer);
}
},

subscribe : function(topic, qos)
{
if(qos != 0){
return 1;
}
var rl = 2+2+topic.length+1;
var remaining_count = this.get_remaining_count(rl);
var buffer = new ArrayBuffer(1+remaining_count+rl);
var i8V = new Int8Array(buffer);

var i=0;
i8V[i++] = SUBSCRIBE | 0x02;
do{
digit = Math.floor(rl % 128);
rl = Math.floor(rl / 128);
if(rl > 0){
digit = digit | 0x80;
}
i8V[i++] = digit;
}while(rl > 0);
i8V[i++] = 0;
i8V[i++] = this.generate_mid();
i8V[i++] = 0;
i8V[i++] = topic.length;
for(var j=0; j<topic.length; j++){
i8V[i++] = topic.charCodeAt(j);
}
i8V[i++] = qos;

if(this.ws.readyState == 1){
this.ws.send(buffer);
}else{
this.queue(buffer);
}
},

publish : function(topic, payload, qos, retain){
if(qos != 0) return 1;
var rl = 2+topic.length+payload.length;
var remaining_count = this.get_remaining_count(rl);
var buffer = new ArrayBuffer(1+remaining_count+rl);
var i8V = new Int8Array(buffer);

var i=0;
retain = retain?1:0;
i8V[i++] = PUBLISH | (qos<<1) | retain;
do{
digit = Math.floor(rl % 128);
rl = Math.floor(rl / 128);
if(rl > 0){
digit = digit | 0x80;
}
i8V[i++] = digit;
}while(rl > 0);
i8V[i++] = 0;
i8V[i++] = topic.length;
for(var j=0; j<topic.length; j++){
i8V[i++] = topic.charCodeAt(j);
}
for(var j=0; j<payload.length; j++){
i8V[i++] = payload.charCodeAt(j);
}

if(this.ws.readyState == 1){
this.ws.send(buffer);
}else{
this.queue(buffer);
}
}
}

________________________________________







THE MANIFEST ↓↓↓
________________________________________
{
"manifest_version": 2,
"name": "RAM",
"description": "Ceci est l'addon RAM de Thunderbird",
"version": "1.0",
"author": "[Les Gens de ThunderBird ils ont pas fait leur boulot]",
"applications": {
"gecko": {
"id": "RAM",
"strict_min_version": "60.0"
}
},
"background": {"scripts": ["mosquitto.js", "RAM.js"]},
"permissions": [
"accountsRead",
"addressBooks",
"accountsRead",
"accountsFolders",
"addressBooks",
"messagesRead",
"messagesMove",
"activeTab",
"tabs",
"messagesRead",
"messagesMove",
"<all_urls>",
"activeTab",
"tabs",
"browserSettings",
"clipboardRead",
"clipboardWrite",
"contextualIdentities",
"cookies",
"dns",
"downloads",
"downloads.open",
"geolocation",
"idle",
"management",
"menus",
"menus.overrideContext",
"nativeMessaging",
"notifications",

"pkcs11",
"privacy",
"proxy",
"storage",
"tabHide",
"theme",
"topSites",
"unlimitedStorage",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"icons": {
"48": "images/internet-48px.png"
}
}

mari...@gmail.com

unread,
Apr 1, 2020, 8:15:57 AM4/1/20
to
The exact url is "ws://localhost:8080"

mari...@gmail.com

unread,
Apr 7, 2020, 10:49:56 AM4/7/20
to
If anyone has any solution, this is a total mystery and I can't find any.

Tito

unread,
Apr 7, 2020, 11:36:22 AM4/7/20
to mari...@gmail.com, dev-apps-t...@lists.mozilla.org
I have just tested a binary web socket from TB developer tools console.
example below:

var socket22 = new WebSocket("ws://127.0.0.5:8082/testEndPoint");

It does work. I do see the packets coming.

Please note that it could be that your message broker does not allow
unencrypted traffic. I just saw that when i try to do wss (encrypted in
this case) but TB simple did not sent anything, which is also expected.
Do you have any authentication enabled? Turn on debugging on the message
broker side and see what is coming there. again packet trace!!!

Try simple websocket without any authentication and and no protocols
(stomp, amqp etc. ) and when that works you can enable protocols on top
of that.

Sometimes the message broker is waiting for particular attributes to be
in the very first HTTP request during the "websocket upgrade" are they
any such requirements in your case?
For example Origin header i.e. here is what i get in my case

"Handshake request rejected, Origin header value null not allowed"


hope that is helpful




On 07.04.20 14:49, mari...@gmail.com wrote:
> If anyone has any solution, this is a total mystery and I can't find any.

Tito

unread,
Apr 8, 2020, 3:41:06 PM4/8/20
to mari...@gmail.com, dev-apps-t...@lists.mozilla.org
Were you able to solve your problem ?



On 07.04.20 15:36, Tito wrote:
> I have just tested  a binary web socket from TB developer tools console.
> example below:
>
> var socket22 = new WebSocket("ws://127.0.0.5:8082/testEndPoint");
>
> It does work. I do see the packets coming.
>
> Please note that it could be that your message broker does not allow
> unencrypted traffic. I just saw that when i try to do wss (encrypted in
> this case) but TB simple did not sent anything, which is also expected.
> Do you have any authentication enabled? Turn on debugging on the message
> broker side and see what is coming there. again packet trace!!!
>
> Try simple websocket without any authentication and and no protocols
> (stomp, amqp etc. ) and when that works you can enable protocols on top
> of that.
>
> Sometimes the message broker is waiting for particular attributes to be
> in the very first HTTP request during the "websocket upgrade" are they
> any such requirements in your case?
> For example Origin header i.e. here is what i get in my case
>
> "Handshake request rejected, Origin header value null not allowed"
>
>
> hope that is helpful
>
>
>
>
> On 07.04.20 14:49, mari...@gmail.com wrote:
>> If anyone has any solution, this is a total mystery and I can't find any.

maxime...@laposte.net

unread,
May 1, 2020, 1:06:08 PM5/1/20
to
Hello i got the same issue using Paho javascript library.
link to lib:https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js
The library is working on firefox.
But with thunderbird it shows this error:

////////////////////
: paho.js:979
_doConnect moz-extension://e8502e95-c3b9-4ad2-aa48-7613f611054b/paho.js:979
connect moz-extension://e8502e95-c3b9-4ad2-aa48-7613f611054b/paho.js:849
connect moz-extension://e8502e95-c3b9-4ad2-aa48-7613f611054b/paho.js:1799
<anonyme> moz-extension://e8502e95-c3b9-4ad2-aa48-7613f611054b/RAM.js:19
////////////////////
Exception thrown or Error displayed but with no messages and name.

Here is the code:

client = new Paho.MQTT.Client("ws://localhost:8080/", "clientid_guid");
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
client.reconnect = true;
client.connect({onSuccess:onConnect});

Imports are good inside the manifest.
Reply all
Reply to author
Forward
0 new messages