I have a code with subscribe private channels, and when I try make a subscription I have the next message:
Pusher : Couldn't get auth info from your webapp : 404
Scenario:
Javascript(Sencha touch) and PHP(Laravel)
The subscription is in javascript:
Pusher.channel_auth_endpoint = "/pusher.php";
var APP_KEY = '4324523452435234523';
var pusher = new Pusher(APP_KEY);
var channel = pusher.subscribe('private-l2');
channel.bind('pusher:subscription_succeeded', function() {
alert("ahora siiii");
});
// for debugging purposes. Not required.
Pusher.log = function(msg) {
if(window.console && window.console.log) {
window.console.log("PUSHER LOG: "+msg);
}
}
AND the pusher.php / LARAVEL
$this->app_id = '66981';
$this->app_key = '4324523452435234523';
$this->app_secret = 'f34632459911e2670dcf';
$pusher = new Pusher($this->app_key, $this->app_secret, $this->app_id);
$auth = $pusher->socket_auth(Input::get('channel_name'), Input::get('socket_id'));
echo $auth;
The result is the error:
Pusher : State changed : connecting -> connected
Pusher : Couldn't get auth info from your webapp : 404
You should set up a route for the Pusher authentication
Route::post('pusher/auth', 'ApiController#pusherAuth');
In that method you should first disable php debugbar (if you're using it) authenticate the user and if authentication checks, then return the response.
I'll paste my controller code below.
public function pusherAuth()
{
\Debugbar::disable();
$user = auth()->user();
if ($user) {
$pusher = new \Pusher(config('broadcasting.connections.pusher.key'), config('broadcasting.connections.pusher.secret'), config('broadcasting.connections.pusher.app_id'));
echo $pusher->socket_auth(request()->input('channel_name'), request()->input('socket_id'));
return;
}else {
header('', true, 403);
echo "Forbidden";
return;
}
}
My JS code:
var pusher = new Pusher(project.pusherKey, {
cluster: 'eu',
encrypted: true,
authEndpoint: apiUrl(['pusher', 'auth']), // just a helper method to create a link
auth: {
headers: {
'X-CSRF-Token': project.token // CSRF token
}
}
});
var channelName = 'private-notifications-' + project.userId; // channel for the user id
var channel = pusher.subscribe(channelName);
channel.bind('new_notification', function (data)
{
app.addNotification(data); // send the notification in the JS app
});
I hope this helps.
Cheers!
Private Pusher channels require the client to authenticate for access. See http://pusher.com/docs/authenticating_users for details on configuring the client for authentication and setting up an authentication endpoint.
Change
Pusher.channel_auth_endpoint = "/pusher.php";
for:
Pusher.channel_auth_endpoint = "/public/broadcasting/auth";
I am not expert at laravel but I guess you have used get request to retrieve data(Socket id & channel name) while it's the post request from pusher server to your server endpoint. Use post to retrieve the data.
Related
I am new to PusherJS and developing a real-time chat app using PHP. Everything working fine but when I press enter to send message, it append it in sender's box and into receiver's box also. How I can differentiate it on the basis of session or user_id. See there are same message is sender and receiver's box:
Real-Time.php:
$options = array(
'cluster' => 'ap2',
'useTLS' => true
);
$pusher = new Pusher\Pusher(
'c575a7********edb87d',
'8fee27********57fdd2',
'7***6*',
$options
);
$pusher->trigger('channel', 'event', $data);
The .js file:
var pusher = new Pusher('c575a76********db87d', {
cluster: 'ap2',
forceTLS: true
});
var channel = pusher.subscribe('channel');
channel.bind('event', function(data) {
var msg_template = ``; //<-- Just removed template it's simple HTML
$("ul#messages").append(msg_template);
});
You need to restrict the message sender from receiving the broadcasted message. How to do so is documented at on the Pusher website.
First, you need to store the SocketID when connecting to Channels:
var pusher = new Pusher('APP_KEY');
var socketId = null;
pusher.connection.bind('connected', function() {
socketId = pusher.connection.socket_id;
});
Once this has been found, you can use it in the event sent to the server:
data: {
id: 'some_id',
updated_value: 'some_value',
socket_id: socketId // pass socket_id parameter to be used by server
}
This will then prevent the client with that socketId from receiving the message.
I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.
I am developing websites where I am using AngularJS in frontend and Laravel php framework in backend.
I have one simple form that is sending $http.post call to laravel backend and there are data processed and email is sended.
Everything works fine on my local Apache server but on online on webhosting server it returns 502 (bad gateway error) in developer console (see screenshot below).
Screenshot: http://s32.postimg.org/bwnxyps1x/502.jpg
And yet, when this error appears, script in backend is executed and email is sended. It is really weird.
In AngularJS I have simple factory that is sending $http.post call...
var sendForm = function sendForm($http) {
return {
sendForm: function($scope) {
return $http({
method: 'POST',
url: '/odeslat',
data: {titul: $scope.form.titul, jmeno: $scope.form.jmeno, prijmeni: $scope.form.prijmeni, email: $scope.form.email,
telefon: $scope.form.telefon, zprava: $scope.form.zprava, human: $scope.form.human}
});
}
}
};
module.exports = sendForm;
This is my controller.
var formularCtrl = function formularCtrl($scope, sendForm) {
$scope.form = {};
$scope.form.human = 'Jsem člověk.';
var odeslano = false;
$scope.submitForm = function submitForm(isValid) {
$scope.showErrorMessage = false;
$scope.errorMessage = "";
if((isValid) && (!odeslano))
{
sendForm.sendForm($scope).success(function(data){
if (!data.success) {
// if not successful, bind errors to error variables
$scope.errorMessage = data.message;
$scope.showErrorMessage = true;
} else {
// if successful, bind success message to message
$scope.message = data.message;
$scope.showMessage = true;
odeslano = true;
}
});
}
else
{
$scope.showErrorMessage = true;
$scope.errorMessage = "Doplňte prosím všechny povinné údaje. ";
}
}
};
module.exports = formularCtrl;
And finally this is just simple method in laravel controller.
public function sendForm(Request $request) {
$v = Validator::make($request->all(), [
'jmeno' => 'required'
]);
if($v->passes()) {
$input = $request->all();
$this->sendMessage($input);
return response()->json(['success' => true, 'message' => 'Formulář byl odeslán. Jakmile to bude možné, budete kontaktováni.']);
}
elseif($v->fails())
{
$input = $request->all();
return response()->json(['success' => false, 'message' => 'Musíte doplnit povinné údaje']);
}
}
private function sendMessage($input)
{
Mail::send('emails.formular', $input, function($message)
{
$message->from(self::FROM, self::SUBJECT);
$message->to(self::TO);
});
}
I am not expert on AngularJS and I am really confused by this error. Do you have any suggestions – what can be the cause?
Thank you very much! All tips are appreciated.
502 indicates the server could not complete something properly. So it is sending out an e-mail, but maybe it tries to something after that script like update a DB. As your local is working OK and your remote is working partially OK this boils down to some server issue, is it possible there is more logging on this server that can tell us why the 502 is being issued. Perhaps the e-mail program returns this after attempting to send the e-mail?
It seems just like backend doesn't send anything back to your angular app. It should response with OK (200 for example) HTTP status.
Okay. So I have contacted webhosting provider and they turned off OPcache in htaccess and it is working now... :)
I generate my JWT, if my token is correct why dont work ? in Google Developers Console i enabled gmail plus youtube and other API, in credentials generate and download json
{
"private_key_id": "22dcf",
"private_key": "-----BEGIN PRIVATE KEY-----(remove)-----END PRIVATE KEY-----\n",
"client_email": "vgfjjc6#developer.gserviceaccount.com",
"client_id": "jc6.apps.googleusercontent.com",
"type": "service_account"
}
first generate token
var sHead=JSON.stringify({"alg":"RS256","typ":"JWT"});
var iat=timeStampf();
var exp=iat+3600;
var sPayload=JSON.stringify({
"iss":client_email,
"scope":scope,//gmail scope https://mail.google.com/
"aud":"https://www.googleapis.com/oauth2/v3/token",
"exp":exp,
"iat":iat
});
var sJWS = KJUR.jws.JWS.sign("RS256", sHead,sPayload, private_key);
var paramstoken="grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-ty
pe%3Ajwt-bearer&assertion="+sJWS
getToken("POST","/oauth2/v3/token",paramstoken,jsonData,replier);
/*rest petition return 200 OK
{
"access_token" : "1bHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
"token_type" : "Bearer",
"expires_in" : 3600
}*/
next i test my token
function testToken(accessToken,replier)
{
// /gmail/v1/users/me/messages /plus/v1/people/me
var client = vertx.createHttpClient().host(urlbase).port(443).ssl(true).maxPoolSize(10);
var request = client.request("GET", "/gmail/v1/users/me/messages", function(resp) {
console.log('server returned status code: ' + resp.statusCode());
console.log('server returned status message: ' + resp.statusMessage());
resp.bodyHandler(function(body) {
replier(JSON.parse(body.toString()));
});
});
request.headers()
.set("Content-type", contentType)
.set("Authorization", "Bearer "+accessToken);
request.end();
client.close();
}
if i use google+ scope and this petition the answer is 200 ok
https://www.googleapis.com/auth/plus.me /plus/v1/people/me
{
"kind":"plus#person",
"etag":"\"LR9iFZQGXELLHS07eQ\"",
"objectType":"person","id":"1149981343","displayName":"","name":{"familyName":"","givenName":""},"image":{"url":"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg?sz=50","isDefault":true},"isPlusUser":false,"language":"en_US","circledByCount":0,"verified":false}
but if i try with gmail
{"error":{"errors":[{"domain":"global","reason":"failedPrecondition","message":"Bad Request"}],"code":400,"message":"Bad Request"}}
In case of GMail, you are accessing a particular user's data, so when creating the JWT, you need to specify the user whom you are trying to impersonate, i.e. the user whose mailbox you want to access.
You can do this using the sub:"User's email address parameter" when forming the JWT Claim set
var sPayload=JSON.stringify({
"iss":client_email,
"sub":USER_EMAIL_ADDRESS
"scope":scope,//gmail scope https://mail.google.com/
"aud":"https://www.googleapis.com/oauth2/v3/token",
"exp":exp,
"iat":iat
});
I need to test a protractor test case in which a user signs up, receives an email, goes to the link provided in the email and fills up his/her details in activation signup form.
The problem is how can I get the redeem token from the email. My email has a link to the activation page which has the auth token like following:
http://127.0.0.1:3000/#/signup/redeem/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJlOTRhYzY3MC1kYTNlLTQyYTUtODVkZS02NDU4ZjVmZGMwYjAiLCJzdWIiOiJ0ZXN0QGNvZWYuY28iLCJpYXQiOjE0Mjc0OTM5MDMsImV4cCI6MTQyODA5ODcwM30.
But how do I fetch that token so that I can build the url or how can I click that button in my email so that I can complete the flow ? I am using mailcatcher to simulate email.
This is something I've solved recently. Hope the solution would also apply for your use-case.
Prerequisites:
mail-listener2 package
understanding of the concept of promises
Step by step instructions:
Install mail-listener2:
npm install mail-listener2 --save-dev
In your protractor config initialize Mail Listener and make it available globally:
onPrepare: function () {
var MailListener = require("mail-listener2");
// here goes your email connection configuration
var mailListener = new MailListener({
username: "imap-username",
password: "imap-password",
host: "imap-host",
port: 993, // imap port
tls: true,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved
markSeen: true, // all fetched email willbe marked as seen and not fetched next time
fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,
mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib.
attachments: true, // download attachments as they are encountered to the project directory
attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments
});
mailListener.start();
mailListener.on("server:connected", function(){
console.log("Mail listener initialized");
});
global.mailListener = mailListener;
}),
onCleanUp: function () {
mailListener.stop();
},
Create a helper getLastEmail() function which would wait for an email to be retrieved:
function getLastEmail() {
var deferred = protractor.promise.defer();
console.log("Waiting for an email...");
mailListener.on("mail", function(mail){
deferred.fulfill(mail);
});
return deferred.promise;
};
Example test case:
describe("Sample test case", function () {
beforeEach(function () {
browser.get("/#login");
browser.waitForAngular();
});
it("should login with a registration code sent to an email", function () {
element(by.id("username")).sendKeys("MyUserName");
element(by.id("password")).sendKeys("MyPassword");
element(by.id("loginButton")).click();
browser.controlFlow().await(getLastEmail()).then(function (email) {
expect(email.subject).toEqual("New Registration Code");
expect(email.headers.to).toEqual("myemail#email.com");
// extract registration code from the email message
var pattern = /Registration code is: (\w+)/g;
var regCode = pattern.exec(email.text)[1];
console.log(regCode);
});
});
});
The solution I implemented was using mailcatcher API, if you scroll down a bit you'll find the following about the API:
A fairly RESTful URL schema means you can download a list of messages
in JSON from /messages, each message's metadata with
/messages/:id.json, and then the pertinent parts with
/messages/:id.html and /messages/:id.plain for the default HTML and
plain text version, /messages/:id/:cid for individual attachments by
CID, or the whole message with /messages/:id.source.
So we first fetched the whole json response, parse it and fetch the latest email id:
// Returns the last email id
function(emails, user) {
var email, recipient;
for(var i = emails.length - 1; i >= 0; i--) {
email = emails[i];
for(var j = 0; j < email.recipients.length ; j++) {
recipient = email.recipients[j];
if(recipient == "<"+user+">") {
return email.id;
}
}
}
};
using that email id we can get the body of the email by hitting /messages/:id.plain(of course there are more variants like fetching the email source code or email rendered html, we only needed the message) then we can just parse the body to fetch what we want, following is the code:
browser.driver.get(mailcatcherUrl+"/messages");
browser.driver.findElement(by.tagName('body')).getText().then(function(response) {
var emails, lastEmailId, partialTokens ;
emails = JSON.parse(response);
lastEmailId = getLastEmailId(emails, user);
browser.driver.get(mailcatcherUrl+"/messages/"+lastEmailId+".plain");
browser.driver.findElement(by.tagName('body')).getText().then(function(lastEmail) {
// use latestEmail to get what you want.
});
});
And Cheers!
I had to do the same thing but the mail testing server we were using did not have imap support.
So in case anyone runs into the same issue, I achieved a similar solution as alecxe using mailpop3 npm library.
The thing with the pop3 client, however, was that it doesn't act as a listener so we had to define a helper function that would connect, login and fetch the latest email when we needed to test the latest email.
Something like this:
function getLastEmail() {
var deferred = protractor.promise.defer();
var POP3Client = require("mailpop3");
var client = new POP3Client(port, host, {
tlserrs: false,
enabletls: true,
debug: false
});
client.on("connect", function() {
console.log("CONNECT success");
client.login(username, password);
});
client.on("login", function(status, rawdata) {
if (status) {
console.log("LOGIN/PASS success");
client.retr(1);
} else {
console.log("LOGIN/PASS failed");
client.quit();
}
});
client.on("retr", function(status, msgnumber, data, rawdata) {
if (status === true) {
console.log("RETR success for msgnumber " + msgnumber);
deferred.fulfill(data);
} else {
console.log("RETR failed for msgnumber " + msgnumber);
}
client.quit();
});
return deferred.promise;
}