Trying connection mqtt in browser - javascript

I'm trying to get a mqtt connection on my browser with JS
I'm following this tutorial: https://emqx.medium.com/use-websocket-to-connect-to-mqtt-broker-9e7baf1aa773
So I've got this:
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script>
// Globally initializes an mqtt variable
const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)
const host = 'ws://broker.***.***.com:9883'
const options = {
keepalive: 60,
clientId: clientId,
username: '***',
password: '***',
protocolId: 'MQTT',
protocolVersion: 4,
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
will: {
topic: 'WillMsg',
payload: 'Connection Closed abnormally..!',
qos: 0,
retain: false
},
}
console.log('Connecting mqtt client')
const client = mqtt.connect(host, options)
client.on('connect', () => {
console.log('Client connected:' + clientId)
// Subscribe
})
</script>
And in my browser I've got this error:
After some research, some people say that need to use certificate: https://github.com/eclipse/paho.mqtt.javascript/issues/187
So, I've got this :
<script src="../browserMqtt.js"></script>
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script>
var options = {
keyPath: '../credentials/client-key.pem',
certPath: '../credentials/client-cert.pem',
rejectUnauthorized : false,
ca: ['../credentials/a-cert.pem'],
protocolId: 'MQTT',
username: '***',
password: '***',
clientId: 'mqttjs_' + Math.random().toString(16).substr(2, 8)
};
var client = mqtt.connect('ws://broker.***.***.com:9883',options);
client.on('connect', function(){
console.log('Connected');
});
</script>
I've got the same error in browser ...
The broker conguration for mosquitto, it's like this :
allow_anonymous false
password_file /mosquitto/config/passwd
#TCP
listener 1883
socket_domain ipv4
#SSL
listener 8883
socket_domain ipv4
cafile /mosquitto/config/tls/ca/ca-cert.pem
certfile /mosquitto/config/tls/server/server-cert.pem
keyfile /mosquitto/config/tls/server/server-key.pem
tls_version tlsv1.2
socket_domain ipv4
#WSS
listener 9883
socket_domain ipv4
protocol websockets
cafile /mosquitto/config/tls/ca/ca-cert.pem
certfile /mosquitto/config/tls/server/server-cert.pem
keyfile /mosquitto/config/tls/server/server-key.pem
tls_version tlsv1.2
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_timestamp_format %Y-%m-%dT%H:%M:%S
log_type all
I can't understand how can I solve it ? Thanks for your help

You can't use client side certs in the browser to authenticate the client (unless you load them into the browsers keystore, but even then I'm not convinced it will work unless there is only one cert/key for the browser to pick as javascript code won't normally prompt the user to pick the right one).
Also loading client certs over http from the server totally defeats the point of using a client cert as anybody can download them.
You need to remove all of the following from the options
keyPath: '../credentials/client-key.pem',
certPath: '../credentials/client-cert.pem',
rejectUnauthorized : false,
ca: ['../credentials/a-cert.pem'],
protocolId: 'MQTT',
Because the paths are meaningless in the browser (and for the reasons I mentioned earlier)
You should also be starting your broker URL with wss:// to make it clear you are trying to connect over secure WebSockets.

Related

Pusher error on server : 4009 Connection not authorized within timeout

I run Laravel 9 app with :
vue 3.2.37
vite 2.9.15
pusher/pusher-php-server 7.0
laravel-echo 1.14.0
All it's work nice on localhost, but on server I have this two events in devtools->network->ws when it try to connect to the channel :
1st : {"event":"pusher:connection_established","data":"{\"socket_id\":\"137307.1921357\",\"activity_timeout\":120}"}
and the 2nd : {"event":"pusher:error","data":{"code":4009,"message":"Connection not authorized within timeout"}}
I have already enable Authorised Connections in my Pusher App settings but I don't know from where this unauthorized error come. It occured just on server side, on localhost I have a subscribed event and there is a different between sockets shown in dev tools on localhost and on server :
localhost : two sockets are shown : ws://localhost:3000/ and wss://ws-eu.pusher.com/app/App_key?protocol=7&client=js&version=7.4.0&flash=false
but on server there is just one : wss://ws-eu.pusher.com/app/App_key?protocol=7&client=js&version=7.4.0&flash=false
bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
wsPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 80,
wssPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 443,
forceTLS: true, // (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
disableStats: true,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
enabledTransports: ['ws', 'wss'],
//authEndpoint: "https://support.demkit.fr/broadcasting/auth",
encrypted: true,
});
.env :
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=1******
PUSHER_APP_KEY=6******
PUSHER_APP_SECRET=8*********
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=eu
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
channels.php
Broadcast::channel('messages.{RoomId}', function ($user, $RoomId) {
//if(Auth::check())
//return ['id' => $RoomId];
return true; // I tried to return all time true to get authorization but it doesn't work :(
});
The error is occuring because your client is not subscribing to a private or presence channel within the timeout. When authorized connections are enabled then any connection that does not subscribe to such a channel will be terminated. https://pusher.com/docs/channels/using_channels/authorized-connections/
Either turn off this setting or subscribe to a private/presence channel to resolve.
Slution
I resolved this issue by adding customize the authorization endpoint check Customizing The Authorization Endpoint
docs from laravel
web.php :
Route::post('/pusher/user-auth', [PusherController::class, 'pusherAuth']);
PusherController :
/**
* Authenticates logged-in user in the Pusher JS app
* For private channels
*/
public function pusherAuth(Request $request)
{
$user = auth()->user();
$socket_id = $request['socket_id'];
$channel_name =$request['channel_name'];
$key = config('broadcasting.connections.pusher.key');
$secret = config('broadcasting.connections.pusher.secret');
$app_id = config('broadcasting.connections.pusher.app_id');
if ($user) {
$pusher = new Pusher($key, $secret, $app_id);
$auth = $pusher->socketAuth($channel_name, $socket_id);
return response($auth, 200);
} else {
header('', true, 403);
echo "Forbidden";
return;
}
}
and the bootstrap file :
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
wsPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 80,
wssPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 443,
forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
disableStats: true,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
enabledTransports: ['ws', 'wss'],
authEndpoint: "/pusher/user-auth", // this is the new endpoint for auth
encrypted: true,
});
and finaly don't froget to change the BROADCAST_DRIVER in .env file to pusher not log

How to use Windows authentication to connect to Sql express?

I have a .env file that contains the below and I am using tedious connection pool.
SQL_SERVER=localhost
SQL_UNAME=US\JENNY
SQL_PSWD=Windows password
SQL_DB=DatabaseName
But I am getting login failed error as shown below:
ConnectionError: Login failed for user 'US\JENNY'
Below is my dbconfig file
const dotenv = require('dotenv');
dotenv.config();
module.exports = {
userName: process.env.SQL_UNAME,
password: process.env.SQL_PSWD,
server: process.env.SQL_SERVER,
options: {
instanceName: 'SQLEXPRESS',
encrypt: false,
database: process.env.SQL_DB,
rowCollectionOnDone: true,
useColumnNames: true // for easier JSON formatting
}
};
Not sure what version of Tedious you're using. I bring it up because userName and password have been moved into an authentication section, so your current config would get you a deprecation warning.
But if you are using a current version, the authentication section also has an authentication.type setting that you can set to ntlm. See http://tediousjs.github.io/tedious/api-connection.html#function_newConnection for details.
The following connection config works for a windows based login for me:
module.exports = {
server: process.env.SQL_SERVER,
options: {
instanceName: 'SQLEXPRESS',
encrypt: false,
database: process.env.SQL_DB,
rowCollectionOnDone: true,
useColumnNames: true
},
authentication: {
type: 'ntlm',
options: {
userName: process.env.SQL_UNAME,
password: process.env.SQL_PSWD,
domain: process.env.SQL_DOMAIN
}
}
}

Making .local resolve to IP address AND port (mdns)

I'm using the multicast-dns node module to attempt making this work.
Looking up custom.local in the browser gives me the console message I setup, but I'm unable to see my actual server running (which is doing so at localhost:12345, where 12345 is a dynamic number). I want to be able to see my local server when visiting custom.local. Is this possible?
Here's some code:
mdns.on("query", query => {
if (query.questions[0] && query.questions[0].name === "custom.local") {
console.log(query);
mdns.respond({
answers: [
{
name: "custom.local",
type: "SRV",
data: {
port: n.get("p"), // dynamic port
weight: 0,
priority: 10,
target: ip // local IP
}
}, {
name: "custom.local",
type: "A",
data: ip,
ttl: 300
}
]
});
}
});
EDIT: I can connect to my local server just fine, that wasn't an issue.
Quoting cfreak:
You can't put port numbers in DNS. DNS is only for looking up an IP by name. For your browser to see it by the name alone you need a proxy program in front of your service or you need to run the service itself on port 80. Port numbers really shouldn't be dynamic. You should specify it in the setup of your service.
That answers my question and offers next steps. Thanks!
UPDATE: Figured out what I was trying to do. Here's some code!
FOUND A SOLUTION, WOOP WOOP!
I'm using this module, but tweaked the source a bit (only because I have dynamic ports, because I feel like it).
/* jshint undef: true, unused: true, esversion: 6, node: true */
"use strict";
//
// G E T
// P A C K A G E S
import express from "express";
import http from "http";
import local from "./server/local";
const n = express();
n.get("/", (req, res) => {
res.send("Welcome home");
});
//
// L A U N C H
const server = http.createServer(n);
server.listen(0, () => {
const port = server.address().port;
local.add(port, "custom.local");
});
Hope this helps you as well, future Internet searcher! :D
Don't let negative folks on other SE sites bring you down. :virtual fist bump:

socket.io-client on server to connect to another server

So I have been working on setting up redundant servers without a single point of failure. I have been looking through a lot of methods and I have settled on using socket.io-client on each server to handle passing messages back and forth between the 2 servers for redundant data. However, no matter what I do, I cannot get the server to connect to the other server. I even scrapped my entire project, started a new one, using extremely simplistic code, and still cannot get the 2 to talk to each other. I have seen multiple questions like this on SO, but none of them have resolved my issue, so I decided to ask and give code samples of my ridiculously simple setup and see if anyone can see why it doesn't connect. I'm telling you, if I didn't already shave my head, I would be ripping my hair out by now. So, here is my simplistic code that doesn't work....
SERVER 1
"use strict";
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const ioClient = require('socket.io-client');
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var client = ioClient('10.0.0.234:3000');
client.on('connect', () => {
console.log('connected to server');
});
io.on('connection', (socket) => {
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
SERVER 2 -- exactly the same except for the line...
var client = ioClient('10.211.55.7:3000');
To point it at the other server. These are both on my local network, and both of them are running at the same time. I even put a client page on each server with a simple connection string, one to the server on that same machine, and one to the server on the other machine, like so...
CLIENT 1 (the 10.0.0.234 machine):
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io("10.0.0.234:3000");
socket.on('connect', function() {
console.log('connected to main server');
})
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
</script>
CLIENT 2 (the 10.211.55.7 machine) - exactly the same except for the connection line which is...
var socket = io('10.211.55.7:3000');
Both of the clients work, and can connect to their servers. I even switched the IP addresses on the clients so that machine 10.0.0.234's client was using...
var socket = io('10.211.55.7:3000');
and it connected perfectly. So each client can connect to either server, and it works perfectly, but no matter what I do, I cannot get the server to ever log the 'connected to server' part.
Seriously, am I losing my mind here? IS there some random bug in socket.io-client that won't allow a server to connect to another server, even if it is running the socket.io as a client? I am so very...very... confused, annoyed, fed up, beat up... and all the other adjectives you can think of.
Just in case anyone needs it, here is my package.json file that I am running on both servers...
PACKAGE.JSON...
{
"name": "simple-socket",
"version": "0.0.1",
"description": "socket server to socket server test",
"dependencies": {
"express": "4.10.2",
"socket.io": "1.2.0",
"socket.io-client": "^1.4.5"
}
}
I know there are other ways of handling redundant backups within node.js,the actual server is much more complex running sticky-session, cluster, redis, socket.io-redis, and others. I just created a simplistic example (actually just kind of used the socket.io chat example as a base) to try to get both servers to talk to each other. No matter what though, it never actually connects to the other server. Yet, somehow both clients can connect to either server, it is just the server will not connect to the other server. Thank you for all the help, and I apologize for the novel here, I am just trying to give all the information I possibly can. Nothing more annoying than trying to help someone who won't give you anything in terms of information, and won't even do some basic research.
Here is a console.log(client); right after the "var client = ioClient('10.0.0.234:3000');
Socket {
io:
Manager {
nsps: { '/': [Circular] },
subs: [ [Object], [Object], [Object] ],
opts:
{ path: '/socket.io',
hostname: '10.0.0.234',
secure: false,
port: '3333' },
_reconnection: true,
_reconnectionAttempts: Infinity,
_reconnectionDelay: 1000,
_reconnectionDelayMax: 5000,
_randomizationFactor: 0.5,
backoff: Backoff { ms: 1000, max: 5000, factor: 2, jitter: 0.5, attempts: 0 },
_timeout: 20000,
readyState: 'opening',
uri: 'http://10.0.0.234:3333',
connecting: [ [Circular] ],
lastPing: null,
encoding: false,
packetBuffer: [],
encoder: Encoder {},
decoder: Decoder { reconstructor: null },
autoConnect: true,
engine:
Socket {
secure: false,
agent: false,
hostname: '10.0.0.234',
port: '3333',
query: {},
upgrade: true,
path: '/socket.io/',
forceJSONP: false,
jsonp: true,
forceBase64: false,
enablesXDR: false,
timestampParam: 't',
timestampRequests: undefined,
transports: [Object],
readyState: 'opening',
writeBuffer: [],
policyPort: 843,
rememberUpgrade: false,
binaryType: null,
onlyBinaryUpgrades: undefined,
perMessageDeflate: [Object],
pfx: null,
key: null,
passphrase: null,
cert: null,
ca: null,
ciphers: null,
rejectUnauthorized: null,
transport: [Object],
_callbacks: [Object] },
skipReconnect: false,
_callbacks: { '$open': [Object], '$packet': [Object], '$close': [Object] } },
nsp: '/',
json: [Circular],
ids: 0,
acks: {},
receiveBuffer: [],
sendBuffer: [],
connected: false,
disconnected: true,
subs:
[ { destroy: [Function] },
{ destroy: [Function] },
{ destroy: [Function] } ],
_callbacks:
{ '$connecting': [ [Function: onConnecting] ],
'$connect': [ [Function] ] } }

Getting error 406 while trying to send a file using socks5 with strophe.js

I am very much new to JavaScript and XMPP and need to implement Socks5 to transfer files with Strophe.js
when i call the method below:
sendS5BInitiation: function (from ,to, sid, jid, host, port, cb) {
var iq = $iq({
from: from,
id: sid,
to: to,
type: 'set'
}).c('query', {
xmlns: 'http://jabber.org/protocol/bytestreams',
sid: sid ,
mode: "tcp"
}).c('streamhost',{
jid: jid,
host: host,
port: port
});
connection.sendIQ(iq,onSuccess,onError,60*1000);
}
I get 406 error as
<iq id="4023b2c8" to="dummy#myserver/4023b2c8" from="xyz#myserver/Spark 2.6.3" type="error"><query xmlns="http://jabber.org/protocol/bytestreams" sid="4023b2c8" mode = "tcp"><streamhost jid="dummy#myserver" host="182.148.1.200" port="7777"/></query><error code="406" type="MODIFY"><not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>
Please help me to get out of this problem.

Categories