xmpp pubsub not delivering messages - xmpp

I'm building a simple web tool with the lattest Strophe.js to handle pubsub messages. I can create nodes, subscribe, see forms... but when I publish (with ok response from server) messages are never forwarded to subscribed clients
I'm using ejabberd server with docker rroemhild/docker-ejabberd It has BOSH, pubsub, admin... and seems to be very complete. I have tried also with an standard jabber ubuntu installation with the same results.
I log in with two users and in the first I can create a node, see subscriptions.
$('#create-node').bind('click', function () {
var pub = $iq({ type: 'set', to: pubsubUrl })
.c('pubsub', { xmlns: 'http://jabber.org/protocol/pubsub' })
.c('create', { node: nodeName() });
connection.sendIQ(pub, pubSuccess, pubError, 5000);
});
$('#list-subscriptions-node').bind('click', function () {
var pub = $iq({ type: 'get', to: pubsubUrl, from: jid() })
.c('pubsub', { xmlns: 'http://jabber.org/protocol/pubsub#owner' })
.c('subscriptions', { node: nodeName() });
connection.sendIQ(pub.tree(), pubSuccess, pubError, 5000);
});
With the second user I subscribe to a recently created node and I efectively see the second user subscribed.
$('#subscribe-node').bind('click', function () {
var pub = $iq({ type: 'set', to: pubsubUrl })
.c('pubsub', { xmlns: 'http://jabber.org/protocol/pubsub' })
.c('subscribe', { node: nodeName(), jid : jid() });
connection.sendIQ(pub, pubSuccess, pubError, 5000);
});
Finally I publish some message. I get an OK response from the server.
$('#publish-node').bind('click', function () {
var pub = $iq({ type: 'set', to: pubsubUrl, from: jid() })
.c('pubsub', { xmlns: 'http://jabber.org/protocol/pubsub' })
.c('publish', { node: nodeName() })
.c('item')
.c('x', {xmlns :'jabber:x:data', type: 'result'})
.c('field', {var : 'title'})
.c('value').t($('#node-event').val());
connection.sendIQ(pub, pubSuccess, pubError, 5000);
});
My full code app is this github repo in case you want to play/see all the code.
Now the question is, despite everything seems to be fine I cannot see any message from the server to subscribed clients to a pubsub node... I tested with MUC conversations and everything is fine. When I publish node messages those are never sent as messages to clients.
I've Checked with several examples and books and I cannot understand if I'm doing something wrong or it's a server configuration thing.
Any idea? Is there somewhere in the server where I can check what's going on under the hoods?
Some examples from my server calls. Confirming that a user is subscribed
<body xmlns='http://jabber.org/protocol/httpbind'>
<iq xmlns='jabber:client' from='pubsub.example.com' to='guillem#example.com/13675173711451438137658982' id='3:sendIQ' type='result'>
<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
<subscriptions node='4193886472'>
<subscription jid='admin#example.com' subscription='subscribed' subid='5AB6AF973AC7E'/>
</subscriptions>
</pubsub>
</iq>
</body>
And here a succesfully published message
<body xmlns='http://jabber.org/protocol/httpbind'>
<iq xmlns='jabber:client' from='pubsub.example.com' to='guillem#example.com/13675173711451438137658982' id='5:sendIQ' type='result'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='4193886472'>
<item id='5AB6AFAB19CFD'/>
</publish>
</pubsub>
</iq>
</body>

It turns out that messages are not delivered to a connected user until it has not showed his presence.
<presence xmlns='jabber:client'>
<priority>1</priority>
</presence>
Presence has to be a positive value.

Related

SOLVED-How do I fix error with access control in web.config file?

Im getting this error and I don´t know how to fix it.The site is live so therefor I don´t want to test a lot of stuff, breaking it wile testing.
I guess the problem is in my web.config file and that its related to the service worker that I use to cache files since that is using "fetch".
The error Im getting.
Fetch API cannot load https://www.google-analytics.com/j/collect?... due to access control checks.
[Error] Failed to load resource: Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.
And the web.config file looks like this.
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="public, max-age=365000000" />
<!--<add name="Access-Control-Allow-Origin" value="['https://mydomain.se','http://dibspayment.eu','https://checkout.dibspayment.eu','https://www.google-analytics.com']" />-->
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="'HEAD,OPTIONS, GET, POST, PUT, PATCH, DELETE'" />
<add name="Access-Control-Allow-Headers" value="'X-Requested-With, Origin, Content-Type, X-Auth-Token, Accept, Authorization, Content-Length,Access-Control-Allow-Origin, Access-Control-Allow-Methods,Cache-Control'" />
</customHeaders>
</httpProtocol>
My service worker looks like this.
self.addEventListener('install', function(event) {
self.skipWaiting()
event.waitUntil(
caches.open('v19').then(function(cache) {
return cache.addAll([
'/js/jquery.cookie.js',
'/js/jquery.sumoselect.min.js',
'/js/wookmark.min.js',
'/js/imagesloaded.pkgd.min.js',
'/js/exif/exif.min.js',
'/js/exif/load-image.min.js',
'/js/exif/load-image-scale.min.js',
'/js/exif/load-image-orientation.min.js',
'/fonts/Framework7Icons-Regular.woff2',
'/fonts/Framework7Icons-Regular.woff',
'/fonts/Framework7Icons-Regular.ttf',
'/fonts/Framework7Icons-Regular.eot',
]);
//caches.open(v2)
//.then( cache = cache.match('/js/v5/framework7.bundle.min.js'))
//.then( res =res.text())
//.then( js = console.log(js))
})
);
});
self.addEventListener('fetch', function(event) {
if (event.request.clone().method === 'GET') {
event.respondWith(
caches.open("v19").then(function (cache) {
return fetch(event.request).then(function (res) {
cache.put(event.request, res.clone());
return res;
})
})
)
} else if (event.request.clone().method === 'POST') {
// attempt to send request normally
event.respondWith(fetch(event.request.clone()).catch(function
(error) {
// only save post requests in browser, if an error occurs
//savePostRequests(event.request.clone().url, form_data)
}))
}
});
self.addEventListener('activate', function(event) {
var cacheKeeplist = ['v19'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheKeeplist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
How should I do with the Access-Control-Allow-Origin? I guess that´s where the problem is, or?
Any input really appreciated, thanks.
Solution:
Ok so I changed it to this so it is not caching google.analytis and the error went away.
self.addEventListener('fetch', function(event) {
if (( event.request.url.indexOf( 'analytics' ) !== -1 ) || ( event.request.url.indexOf( 'checkout' ) !== -1 )){
}else{
if (event.request.clone().method === 'GET') {
event.respondWith(
caches.open("v19").then(function (cache) {
return fetch(event.request).then(function (res) {
cache.put(event.request, res.clone());
return res;
})
})
)
} else if (event.request.clone().method === 'POST') {
// attempt to send request normally
event.respondWith(fetch(event.request.clone()).catch(function
(error) {
// only save post requests in browser, if an error occurs
//savePostRequests(event.request.clone().url, form_data)
}))
}
}
});
It's not the issue with yours web.config, but Google Analytics (GA) server's. So you have to adjust requests to meet GA requirements.
GA responses do not want to be cached (underlined in green). All transfer of statistics is done in the send request, the answer is only confirmation of delivery (the text like 1gfr).
GA do not accept requests with credentials (underlined in red) because of:
- presents of wildcard * in Access-Control-Allow-Origin response header
- absent of Access-Control-Allow-Credentials: true in responce header
Hence GA wait cross-origin requests with no credentials (no auth cookies should not be sent). The feth() uses mode: 'cors', credentials: 'same-origin' by default (send credentials only to same-origin requests), therefore all should be OK.
But if you still have got CORS error above, it means some browsers send credentials. Try to set Request.credentials to "omit" as recommended by Mozilla.
Or may be it's possible to exclude GA from caching and let process GA requests native way (GA natively use XMLHttpRequest with withCredentials = false option, not fetch()).

Openfire XMPP Client Connection via Ionic App

In order to test the client side connectivity with our Openfire XMPP server, the following test script (nodejs) was initially tested, which ran successfully.
async function connectX() {
try {
const keyPair = await XmppUser.generateKeys()
XmppUser.connect(username, password, keyPairs).then(
async user => {
user.getFriends().then(friends => {
console.log("List of Friends: ");
console.log(friends);
user.getChatHistory().then(history => {
console.log("Chat History: ")
console.log(history);
user.closeConnection();
}).catch(e => console.log(e));
}).catch(e => console.log(e));
}
).catch(e => console.log(e));
} catch(e) {
console.log(e)
}
}
connectX()
Output:
List of Friends:
[ 'test1.test#chat.company.io', 'test2.test#chat.company.io' ]
Chat History:
{ messages:
[ { date: 2020-08-11T12:18:34.314Z,
from: 'test1.test#chat.company.io',
to: 'test6.test#chat.company.io',
message: 'Hello! Received.',
id: 'D255Q-132' }
] }
lastId: '1',
firstId: '1',
count: '1' }
However, when I run the script in an ionic angular app using the same ChatService class it leads me to the following CORS error.
Access to fetch at 'https://chat.company.io/.well-known/host-meta' from origin 'http://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
For information, https://chat.company.io/.well-known/host-meta exists and has the following content:
<?xml version='1.0' encoding='utf-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
<Link rel="urn:xmpp:alt-connections:httppoll"
href="https://chat.company.io:443" />
</XRD>
The backend infrastructure includes an Nginx server and the chat server runs behind it with the following open ports: 443, 7070, 5222, 5223.
Please help in figuring out what the issue might be.
Possible CORS issue,
enable support for CORS in Openfire, server -> server settings -> http binding -> CORS section.

flutter socket.io chat app using nodejs as backend

i am currently working on chat app using socket.io..i have two funtion send and subscribe by send function i can send new message to anther user and by subscribe i add that message to the list...i have a database for storing these conversation....
Now my question is that how can i show all the conversation in list as well as the new message that is added to the list???
i tried by adding conversation messages and new message to the same class but it does not show me anything
Hope it will be enough explaination..
You can achieve this using stomp_dart_client library
For connection :
StompClient client = StompClient(
config: StompConfig(
url: 'wss://yourserver',
onConnect: onConnectCallback
)
);
client.activate();
For subscribe:
client.subscribe(destination: '<subscribe path>', headers: {}, callback: (data) {
print(data.body);
})
For Send:
client.send(destination: '<subscribe path>', body: 'Message body', headers: {});

RabbitMQ Publish to Exchange Confirmation

I would like to return a retrieve a confirmation that the message was successfully published to the exchange before closing the AMQP connection. At the moment, I am using a timeout function to allow for the message to be published before closing the connection. This is not the right way. Can someone please help to retrieve a confirmation so I can close the connection based on a successful publish?
The code I am using is below:
function toExchange(msg)
{
amqp.connect('amqp://localhost:5672', function(err, conn) //local connection
{
conn.createChannel(function(err, ch)
{
var exchange = 'MessageExchange';
ch.assertExchange(exchange, 'fanout', {durable: true});
ch.publish(exchange, '', new Buffer(msg));
console.log("Sent to Exchange: %s", msg);
});
setTimeout(function() { conn.close(); }, 5000);
});
}
You can use a RabbitMQ extension called "Publisher confirms". Here is more information: https://www.rabbitmq.com/confirms.html#publisher-confirms.
You are not notified when the message is published to the exchange, but when it is published and routed to all queues: https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed
In your case using amqplib in nodeJS you can use this snippet of code: https://www.squaremobius.net/amqp.node/channel_api.html#confirmchannel
It uses the callback #waitForConfirms(function(err) {...}) that triggers when all published messages have been confirmed.

Strophe session attachment -- 403 forbidden

I am working on an XMPP web application which need to include session attachment. I am using Openfire XMPP server. I have successfully implemented the server side attachments where the session is created and I get the sid and rid of a session. Unfortunately, I am stuck in the next part.
As I know, after getting the sid and rid, I need to use the Strophe.Connection.attach() to attach strphe to the existing session. After that I am making an IQ request which gets the correct response from the server. However, I am not getting any changes in the status i.e. the app is neither connected nor attached and hence I am not able to do anything.
After the IQ request, the server responds on time with the normal message and then in the next request, I get a 403 forbidden error and the connection is terminated.
Here is the code:
var BOSH_SERVICE = 'http://localhost/cosys-rtw/';
var connection = null;
var sid = "";
var rid = 0;
function notifyUser(msg)
{
if (msg.getAttribute('from') == "testuser1#ghost/pingstream") {
var elems = msg.getElementsByTagName('body');
var body = elems[0];
$('#notifications').append(Strophe.getText(body));
}
return true;
}
function onConnect(status)
{
console.log("Connect")
console.log(status)
if (status == Strophe.Status.ATTACHED) {
$('#notifications').html('<p class="welcome">Hello! Any new posts will appear below.</p>');
connection.addHandler(notifyUser, null, 'message', null, null, null);
connection.send($pres().tree());
}
}
$(document).ready(function () {
$.ajax({'url':'http://localhost/x',
'method':'get',
'success':function(response){
console.log(response);
console.log(jQuery.parseJSON(response));
resp = jQuery.parseJSON(response);
window.sid = resp.sid;
window.rid = resp.rid;
prepareStrophe();
}});
});
function prepareStrophe(){
console.log(BOSH_SERVICE);
jid = "testuser1#ghost";
connection = new Strophe.Connection(BOSH_SERVICE);
console.log(window.rid);
console.log(window.sid);
connection.attach( jid,window.sid,window.rid,null);
connection.sendIQ( $iq({to:Strophe.getDomainFromJid(jid),type:"get"})
.c('query',{xmlns:'http://jabber.org/protocol/disco#info'}),
function(){
if (status == Strophe.Status.ATTACHED) {
connection.send($pres().tree());}
});}
I get the follwoing response to the IQ request:
<body xmlns="http://jabber.org/protocol/httpbind">
<iq id="6173:sendIQ" xmlns="jabber:client" type="result" from="ghost" to="testuser1#ghost/6b8bfe07">
<query xmlns="http://jabber.org/protocol/disco#info">
<identity category="server" name="Openfire Server" type="im"></identity>
<identity category="pubsub" type="pep"></identity>
<feature var="http://jabber.org/protocol/pubsub#delete-nodes"></feature>
.
.
.
<feature var="http://jabber.org/protocol/pubsub#purge-nodes"></feature>
<feature var="http://jabber.org/protocol/disco#info"></feature>
<feature var="http://jabber.org/protocol/rsm"></feature>
</query>
</iq>
</body>
This response does say that the session is valid. Am I right?
I am not able to figure this thing so now I am handing this to the community.
By the way -- Merry Christmas
I think that I have got something here that I would like to share if anyone has the same problem. This thread on ignite realtime http://community.igniterealtime.org/thread/33004 discusses about this issue. The settings mentioned there did work for me.