Strophe session attachment -- 403 forbidden - xmpp

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.

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()).

401 error using SparkPost with XHR

Hi I'm trying to send a POST call to the SparkPost API in a JavaScript web app. It works fine with curl and Postman, but as soon as I try sending from my localhost site I get a 401 Unauthorized error.
My current code looks like the below, but I've tried fetch as well with the same results.
sendEmail(subject, data) {
let textbody = "blah blah blah";
const url = "https://api.sparkpost.com/api/v1/transmissions";
const fetchbody = {
content: {
from: "sandbox#sparkpostbox.com",
subject: subject,
text: textbody
},
recipients: [{address: "myaddress#gmail.com"}]
};
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("authorization", creds);
xhr.setRequestHeader("cache-control", "no-cache");
xhr.send(JSON.stringify(fetchbody));
}
Is there something wrong with my credentials setup here? Note that creds is set to my secret API key string.
Figured it out after chatting with the Sparkpost devs a bit - the service only allows "strict CORS" i.e. requests from server-side, and I was sending the request from client-side code.

xmpp pubsub not delivering messages

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.

UPnP POST to Printers Data Sink URI

I have some other posts where I've been working with posting data to a UPnP printer. Basically creating a control point from scratch (this is still POC and I'll be implementing across multiple device types so I'm trying to get basic understanding first). So far I'm able to discover the printer, request a print job and get back a data sink url to post the content to be printed. At this point I attempt a POST with simple xhtml data, but the request seems to time out every time with the following exception:
The remote server returned an error: NotFound.
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
If I hit the url in the browser, I get back HTTP 405 Method Not Allowed
I'm wondering if the server is ignoring the post due to bad data, or I'm missing headers or something along these lines.
I've already gone through the docs on upnp.org for the Printer Basic service, along with SOAP 1.1 UPnP Profile, both of which greatly helped get as far as I have.
does anybody have any thoughts?
Here's a copy of my xhtml:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML-Print 1.0//EN\" \"http://www.w3.org/MarkUp/DTD/xhtml-print10.dtd\">
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
<title>test</title>
</head>
<body>
<div>hello world</div>
</body>
</html>
I'm using C# to create and send a HttpWebRequest. Here is the code that does that (I have a couple variations, another using WebClient)
private void SendToPrinter(string printUri, string content)
{
var request = WebRequest.Create(new Uri(printUri)) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/xml; charset=\"utf-8\"";
request.ContentLength = content.Length;
request.Headers[SoapHeaderName] = CreateJobHeader; // this probably isn't necessary
request.BeginGetRequestStream(ar =>
{
var requestStream = request.EndGetRequestStream(ar);
using (var sw = new StreamWriter(requestStream))
{
sw.Write(content);
sw.Close();
}
request.BeginGetResponse(a =>
{
var response = request.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var sr = new StreamReader(responseStream))
{
var results = sr.ReadToEnd();
}
}, null);
}, null);
}
raw post data from fiddler
POST http://10.20.201.90/upnp/print/1d153438-1e90-1f0b-8b54-984be15df0fe HTTP/1.1
Content-Type: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:device:Printer:1#SendDocument"
Host: 10.20.201.90
Content-Length: 482
Expect: 100-continue
<?xml version="1.0" encoding="UTF-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:SendDocument xmlns:u="urn:schemas-upnp-org:device:Printer:1"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>test</title></head><body><div>hello world</div></body></html></u:SendDocument></s:Body></s:Envelope>
One issue that kept me from printing was that the printer was set to ask which tray to print from. This blocked the message from being printed. Here's the final SOAP message. I did not escape it.
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">
<s:Body>
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head><title>test</title></head>
<body><div>hello world</div></body>
</html>
</s:Body>
</s:Envelope>

Facebook API: Where does this facebookredirect.axd come from?

So I've set up everything to invite users to the registration page on my site and track their invitation code, but now whenever a user accepts the invitation they end up getting the following error:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
And here's the URL:
http://www.facebook.com/dialog/oauth/?state=eyJyIjoiaHR0cDovL2FwcHMuZmFjZWJvb2suY29tL2Zpc2hhcndlLz9yZXF1ZXN0X2lkcz0xMDE1MDYzNzQzNDI4NTQ4NCwxMDE1MDYzNzU3NjA0MDQ4NCwxMDE1MDYzNzU4MDQ1NTQ4NCwxMDE1MDYzNzU5NzQ2MDQ4NCwxMDE1MDYzNzYxNDUyMDQ4NCwxMDE1MDYzNzYzMDg0NTQ4NCZyZWY9bm90aWYmbm90aWZfdD1hcHBfcmVxdWVzdCJ9&client_id=217174461634478&redirect_uri=http://www.fisharwe.com/facebookredirect.axd
Why is the redirect_uri http://www.fisharwe.com/facebookredirect.axd and not what I've set in my code using top.location.href="whatever.com"?
UPDATE:
Seems like that problem has been resolved somehow. But it still does not redirect to the registration page of my site! Here's the source code of the landing page:
<html><head><script type="text/javascript">
top.location = "http://www.facebook.com/dialog/oauth/?state=eyJyIjoiaHR0cDovL2FwcHMuZmFjZWJvb2suY29tL2Zpc2hhcndlLz90eXBlPWRpc2NvdmVyeSJ9&client_id=217174461634478&redirect_uri=http://www.fisharwe.com/facebookredirect.axd";
</script></head><body></body></html>
UPDATE2:
This is my C# code:
[CanvasAuthorize]
public ActionResult Index()
{
var fb = new FacebookWebClient(FacebookWebContext.Current);
dynamic requestInfo = fb.Get("/me/apprequests/");
var b = requestInfo.Count;
if (requestInfo.data.Count > 0)
{
var a = requestInfo["data"][0]["data"];
//ViewData.Add("TrackingData", a);
return Redirect(redirectUrl + "?code=" + a);
}
return RedirectToAction("Index", "Home");
}
have you setup the http handler in web.config?
<httpHandlers>
<add verb="*" path="facebookredirect.axd" type="Facebook.Web.FacebookAppRedirectHttpHandler, Facebook.Web" />
</httpHandlers>