The Strophe onMessage handler that I added to the connection doesn't seem to trigger whenever a message gets send. I can't seem to find the problem. I can't find a lot of other info either and the info I do find seems to suggest my code is correct. I can send messages, so I know the connection works, but I cannot receive messages.
I create the connection like this, and then call the login function if a new connection is made:
XMPPChatConnection() {
if (this.#connection === undefined) {
this.#connection = new XMPPHelper.Strophe.Connection(
"wss://xxxxxxxxxxxxxxxxxxxxxxx",
{protocol: "wss"}
);
this.login();
}
return this.#connection;
}
The login function calls the chatListeners function which should setup all the listeners that are required when the user is logged in:
login() {
let jid = this.composeJabberIdentifier();
let token = this.getXMPPToken();
this.#connection.connect(jid, token, (status) => {
if (status === XMPPHelper.Strophe.Status.CONNECTED) {
this.chatListeners();
}
});
}
The messageListener is an imported function and currently only contains a console log:
import messageListener from "../classes/listeners/xmpp/chat/messageListener";
chatListeners() {
this.XMPPChatConnection().addHandler(messageListener, null, 'message', 'chat');
}
messageListener:
export default function messageListener(message) {
console.log(message);
}
What did I do wrong?
So I found the cause of my problems. I was using the Xabber client to send messages back, but it turned out Xabber sent the messages to the wrong resource.
On top of that I should have set my presence after login with a priority of >= 0.
this.XMPPChatConnection().send($pres().c("priority").t("0"));
Related
I'm trying to add access control to my Angular app and running into some puzzling troubles...
On the front-end, the authentication function is being called repeatedly until it is stopped for being too large of a call stack. Each time, the $http request within the function is triggering the errorCallback function. The expected behavior is for the auth function to fire once every time ui-router's state changes, changing $rootScope values that indicate the browser's level of authentication.
First, the factory responsible for making the GET request:
.factory ('authRequest', function ($http) {
return {
authStatus : function() {
$http.get('/auth', {'withCredentials' : true}).then(function successCallback(response) {
console.log("Successful authorization check.");
return response.status;
}, function errorCallback(response) {
if (response.status) {
console.log("Failed to authenticate.");
return response.status;
}
console.log("Failed to receive a response.");
return 'errNoResponse';
});
}
}
})
Then, the ng-controller for processing the factory's response:
//Navbar controller, set to fire upon each state change and verify authorization.
.controller('navCtrl', function ($rootScope, $state, authRequest) {
$rootScope.$on('$stateChangeStart', function (event, toState) {
console.log('authRequest value: ' + [authRequest]);
if (authRequest.authStatus === 202) {
console.log('Auth check succeeded, assigned user privileges.');
$rootScope.loggedIn = true;
$rootScope.loggedInAdmin = false;
if (toState = 'users' || 'login') {
event.preventDefault();
}
} else if (authRequest.authStatus === 222) {
console.log('Auth check succeeded, assigned admin privileges.');
$rootScope.loggedIn = true;
$rootScope.loggedInAdmin = true;
if (toState = 'login') {
event.preventDefault();
}
} else {
console.log('Auth check failed.');
$rootScope.loggedIn = false;
$rootScope.loggedInAdmin = false;
event.preventDefault();
$state.go('login');
}
});
})
Meanwhile, on the back-end, I'm not seeing evidence of the /auth Express route being reached with any of the requests. I have a console log set to go off when /auth receives a GET request, but I'm not seeing any activity in the console. Every other Express route is being accessed without issue. The expected behavior is to receive the request, decode the request's JWT cookie header, then send a response code back according to what sort of user privileges are listed. Here's the Express route for /auth:
// GET /auth. Fired every time the app state changes. Verifies JWT authenticity and sends a response based on the user's privileges. 202 is an auth'd user, 222 is an auth'd admin. 401 is no token or error.
app.get('/auth', function (req, res, next) {
console.log('Authorization request received.')
var decoded = jwt.verify(req.cookie, [JWTAuthSecret]);
if (decoded) {
if (decoded.admin === true) {
return res.status(222).send(res.status);
console.log(decoded.sub + ' is an admin, responded with code 222');
} else {
return res.status(202).send(res.status);
console.log(decoded.sub + ' is not an admin, responded with code 202');
}
} else {
return res.status(401).send(res.status);
console.log('Decode failed, responded with code 401');
};
});
With the current setup, the app is hanging indefinitely. As mentioned earlier, a ton of auth requests are being produced upon each state change. Each one logs an "authRequest value: [object Object]" then "Auth check failed." Eventually I get the following error:
angular.js:13550RangeError: Maximum call stack size exceeded
at angular.js:10225
at n.$broadcast (angular.js:17554)
at Object.transitionTo (angular-ui-router.js:3273)
at Object.go (angular-ui-router.js:3108)
at app.js:275
at n.$broadcast (angular.js:17552)
at Object.transitionTo (angular-ui-router.js:3273)
at Object.go (angular-ui-router.js:3108)
at app.js:275
at n.$broadcast (angular.js:17552)
So there seems to be a problem with the frequency of the calls on the front end, as well as a problem with actually getting the data sent to the /auth route.
This is my first time working with Angular factories, so my instinct is to assume my factory implementation is wonky... I haven't figured out how it might be fixed on my own, though.
Thanks for reading, hope I can get some advice on what to change to make this work.
I see a couple issues. This might not solve everything, but will hopefully help narrow things down.
One is that authRequest.authStatus is a function but you're never calling it. In your controller, you need to call the function. That's part of the reason nothing's pinging the backend.
authRequest.authStatus().then(function(status) {
if (status === 202) {
//do stuff
} else if (status === 222) {
//do other stuff
}
});
Now, in your factory, you're not returning anything to the function, so make sure you do that.
.factory ('authRequest', function ($http) {
return {
authStatus : function() {
return $http.get('url').then(callbacks);
}
}
})
The accepted answer provided me with solutions to the front-end troubles I was facing. The GET request to /auth was successfully being sent to Express as intended, but was still responding with an error code despite a valid authentication cookie.
Checking the backend logs, I was receiving an error saying JsonWebTokenError: jwt must be provided when trying to decode the JWT. Turns out req.cookie isn't the correct syntax to check the request's cookie - req.cookies is.
After changing that, my cookie output went from being undefined to [object Object]. The error I was getting changed as well to TypeError: jwtString.split is not a function.
After double checking the way cookies are referenced in the Express docs, I realized I wasn't calling the JWT cookie by name. The updated code is:
app.get('/auth', function (req, res, next) {
console.log('Authorization request received.')
console.log ('Cookie Data: ' + req.cookies.CookieName);
var decoded = jwt.verify(req.cookies.CookieName, [JWTAuthSecret]);
if (decoded) {
if (decoded.admin === true) {
return res.status(222).send(res.status);
console.log(decoded.sub + ' is an admin, responded with code 222');
} else {
return res.status(202).send(res.status);
console.log(decoded.sub + ' is not an admin, responded with code 202');
}
} else {
return res.status(401).send(res.status);
console.log('Decode failed, responded with code 401');
};
});
With this change and the front-end changes, the app's authentication and authorization are working as intended.
I followed this tutorial ,to make Push notification on Google Chrome by using GCM. My problem is I'm unable to complete the operation! i have no idea why.
In subscribe function, it breaks out the function whenever it tries to execute
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// ...
};
});
It has no console error and no console warning and it doesn't enter the catch! Here is what I did:
function subscribe() {
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// The subscription was successful
isPushEnabled = true;
pushButton.textContent = 'Disable Push Messages';
pushButton.disabled = false;
console.log("sending sub");
sendSubscriptionToServer(subscription);
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function(e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
pushButton.disabled = true;
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
}
});
});
}
The only thing that did work for me is the 'getRegistration' method, used as the following code
navigator.serviceWorker.getRegistration('/Workers/').then( r => subscribe( r ) );
where '/Workers/' is the path where the ServiceWorker.js is
I have implemented the browser push notification functionality and its working fine. I used this guide as the reference https://developers.google.com/web/fundamentals/getting-started/push-notifications/step-01?hl=en
However as payload is still not supported, I decided to query my server to get the notification data for each user which is also working fine.
There is one issue though. For some cases, after getting data from the server, I want to control whether to show the notification or not. I am not able to figure out how to do this. I tried returning false, throwing errors etc. But is always shows the default notification even if I don't call showNotification method. Let me know how to solve this. Following is the relevant code
self.addEventListener('push', function(event) {
event.waitUntil(
fetch('/getPushNotificationData/').then(function(response){
if (response.status !== 200) {
// I don't want to show any notification in this case
console.log('Looks like there was a problem. Status Code: ' + response.status);
throw new Error();
}
return response.json().then(function(data){
var shouldDisplay = data.shouldDisplay;
if (shouldDisplay=='1'){
var title = data.title;
var message = data.message;
var url = data.url;
return self.registration.showNotification(title, {
body: message,
data: url
});
}
else{
// I don't want to show any notification in this case also
return true;
}
});
})
);
});
I have implemented quickblox chat in my web application. Now I want to show status of my messages as delivered in case when they are just sent to user and as read when they have seen the message.
In your Javascript SDK I have found two functions QB.chat.sendDeliveredMessage and QB.chat.sendReadMessage but every time I call this function as :
QB.chat.sendDeliveredMessage(
QBChatHelpers.getJID(chatUser.id),
"5600f885a28f9ac7e801048c" //this is just a sample msg-id
);
It calls ajax with POST request over url http://chat.quickblox.com:8080/ while chat is running over http://chat.quickblox.com:5280/.
Also within library, I changed the port to 5280 in place of 8080 so that it can call url with port 8080 and it calls http://chat.quickblox.com:5280/ which then gives error code 405: Invalid Hostname.
Please let me know what's wrong am I doing while calling this function. If further information is required then do let me know.
We are working on this feature, in the new version of QuickBlox JS SDK messages will be sent with the markable status.
sendDeliveredStatus(params)-will be sent automatically after receiving a message with markable status, which will signalize via the function of Listener QB.chat.onDeliveredStatusListener(messageId, dialogId, userId);
sendReadStatus(params)-will be possible to send it according to an event (for example, you set up a processor, which will notice that a message has already appeared on yours monitor, after receiving a message with markable status, which will signalize via the function of Listener QB.chat.onReadStatusListener(messageId, dialogId, userId);)
parameters for status sending:
params = {
messageId: messageId,
userId: userId,
dialogId: dialogId
};
Thanks guys, this page helped me a lot.
When a message is sent could be 2 options:
A. You are the sender and another user is the addressee: YOU --> ANOTHER-USER
B. You are the addressee and another user is the sender: ANOTHER-USER --> YOU
OPTION A:
Send your message to the addressee with "markable=1" flag.
For example:
var params = {
chat_dialog_id: "56b20540f583bb7bcb00rrr6",
message: msg),
send_to_chat: 1,
markable: 1,
extension: {
save_to_history: 1
}
};
// SEND THE MESSAGE
QB.chat.message.create(params, function (err, res) {});
Add QB listener to be trigger after the addressee user had read the message:
QB.chat.onReadStatusListener = updateReadersList;
And then add such a function with this signature:
function updateReadersList(messageId, dialogId, userId){
console.log('userId has read your messageId that in dialogId');
}
OPTION B:
Add QB listener to handle new incoming messages:
QB.chat.onMessageListener = showMessage;
Add such a listener function with this signature:
In that listener you can notify the sender that his message was recived an d read (by you):
function showMessage(userId, msg) {
console.log('userId sent you this msg');
//notify sender: message was read:
if(userId != "MY-USER") {
sendReadSignalToSender(msg, userId);
console.log("You notified userId that his msg was read.");
}
}
Adding a simple function for just passing params to QB.chat.sendReadStatus function:
function sendReadSignalToSender(dialogMsg, senderId){
var params = {
messageId: (dialogMsg.id || dialogMsg._id),
userId: senderId,
dialogId: (dialogMsg.dialog_id || dialogMsg.chat_dialog_id)
};
QB.chat.sendReadStatus(params);
console.log("senderId was notified that his dialogMsg was read.");
}
Another quickblox question - I am getting the following error when trying to run my application:
Uncaught TypeError: Cannot read property 'sigBytes' of undefinedquickblox.js:10707 c.HMAC.i.extend.initquickblox.js:10703 i.Hasher.a.extend._createHmacHelperquickblox.js:101 signMessagequickblox.js:35 createSessionquickblox.js:867 QuickBlox.createSessionchat.html:122 (anonymous function)
This error prevents successful authentication of the user. The code being executed is below(insecure as hell - proof of concept only!):
var chatToUser = window.localStorage.getItem("chatToUser");
var username = window.localStorage.getItem("user");
var password = window.localStorage.getItem("pwd");
var params = {login:username,password:password};
console.log("PARAMS: ",params);
$(document).ready(function(){
var chatService = new QBChat(params);
});
// JavaScript SDK initialization
QB.init(QBAPP.appID, QBAPP.authKey, QBAPP.authSecret);
// QuickBlox session creation
QB.createSession(params, function(err, result) {
if (err) {
console.log("ERROR:", err.detail);
} else {
chatUser = {
id: result.user_id,
pass: params.password
};
connectChat();
}
});
function connectChat() {
chatService = new QBChat({
onConnectFailed: onConnectFailed,
onConnectSuccess: onConnectSuccess,
onConnectClosed: onConnectClosed,
onChatMessage: onChatMessage
});
console.log("Chat Service: ", chatService);
console.log("Chat User: ", chatuser);
// connect to QB chat service
chatService.connect(chatUser);
}
/* Callbacks
------------------------------------------------------*/
// Connection is failed
function onConnectFailed() {
alert("We're having some difficulty talking to the server. Please try again later, or get in touch if th eproblem persists.")
}
// Connection is success
function onConnectSuccess() {
//green dot - live - status
alert("Connected.")
}
// Connection is closed
function onConnectClosed() {}
What do i need to do differently in order to successfully log the user in for chat?
If it helps, I have previously generated a session for them based on their 'user' credentials (username/password). Is it possible to simply reuse this session instead of creating a fresh one?
It just hit me! (adding a few console.logs helped...)
The app is looking for QBAPP.(etc) and the case/underscore formatting of those parameters did not line up after copying from an examples, hence the 'undefined'-s coming back and the sigbytes thingy falling over itself. So note to anyone else having this error - check your code carefully, for case and style before nagging the community with stupid questions!
I hope someone might learn from this.