Ngrok errors 502 bad gateway Twilio - php

Hi evreyone Im using twilio voice javascript sdk with ngrok that i found their repository in github
the installation went good when i try to click on start up the divice to get the client name from my name generator js an error has showed and i can not get the cleint client name or make any calls
i have set up my index js with all my account sid and phone number and twiml app sid and Twilio api secret key
cmd error
Error: identity is required to be specified in options
at new AccessToken (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\twilio\lib\jwt\AccessToken.js:202:19)
at tokenGenerator (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\src\handler.js:13:23)
at C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\src\router.js:7:12
at Layer.handle [as handle_request] (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\layer.js:95:5) at next (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\route.js:144:13)
at Route.dispatch (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\route.js:114:3)
at Layer.handle [as handle_request] (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\layer.js:95:5) at C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\index.js:284:15
at Function.process_params (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\index.js:346:12)
at next (C:\xampp\htdocs\voice-javascript-sdk-quickstart-node\node_modules\express\lib\router\index.js:280:10)
ngrok error when i click on start up the device
HTTP Requests
-------------
GET /quickstart.js 200 OK
GET /twilio.min.js 200 OK
GET /site.css 200 OK
GET / 200 OK
GET / 502 Bad Gateway
config.js
const dotenv = require("dotenv");
const cfg = {};
if (process.env.NODE_ENV !== "test") {
dotenv.config({ path: ".env" });
} else {
dotenv.config({ path: ".env.example", silent: true });
}
// HTTP Port to run our web application
cfg.port = process.env.PORT || 3000;
// Your Twilio account SID and auth token, both found at:
// https://www.twilio.com/user/account
//
// A good practice is to store these string values as system environment
// variables, and load them from there as we are doing below. Alternately,
// you could hard code these values here as strings.
cfg.accountSid = process.env.TWILIO_ACCOUNT_SID;
cfg.twimlAppSid = process.env.TWILIO_TWIML_APP_SID;
cfg.callerId = process.env.TWILIO_CALLER_ID;
cfg.apiKey = process.env.TWILIO_API_KEY;
cfg.apiSecret = process.env.TWILIO_API_SECRET;
// Export configuration object
module.exports = cfg;

Related

socket.io read browser cookies already set by php [duplicate]

I am trying to use Socket.IO in Node.js, and am trying to allow the server to give an identity to each of the Socket.IO clients. As the socket code is outside the scope of the http server code, it doesn't have easy access to the request information sent, so I'm assuming it will need to be sent up during the connection. What is the best way to
1) get the information to the server about who is connecting via Socket.IO
2) authenticate who they say they are (I'm currently using Express, if that makes things any easier)
Use connect-redis and have redis as your session store for all authenticated users. Make sure on authentication you send the key (normally req.sessionID) to the client. Have the client store this key in a cookie.
On socket connect (or anytime later) fetch this key from the cookie and send it back to the server. Fetch the session information in redis using this key. (GET key)
Eg:
Server side (with redis as session store):
req.session.regenerate...
res.send({rediskey: req.sessionID});
Client side:
//store the key in a cookie
SetCookie('rediskey', <%= rediskey %>); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
//then when socket is connected, fetch the rediskey from the document.cookie and send it back to server
var socket = new io.Socket();
socket.on('connect', function() {
var rediskey = GetCookie('rediskey'); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
socket.send({rediskey: rediskey});
});
Server side:
//in io.on('connection')
io.on('connection', function(client) {
client.on('message', function(message) {
if(message.rediskey) {
//fetch session info from redis
redisclient.get(message.rediskey, function(e, c) {
client.user_logged_in = c.username;
});
}
});
});
I also liked the way pusherapp does private channels.
A unique socket id is generated and
sent to the browser by Pusher. This is
sent to your application (1) via an
AJAX request which authorizes the user
to access the channel against your
existing authentication system. If
successful your application returns an
authorization string to the browser
signed with you Pusher secret. This is
sent to Pusher over the WebSocket,
which completes the authorization (2)
if the authorization string matches.
Because also socket.io has unique socket_id for every socket.
socket.on('connect', function() {
console.log(socket.transport.sessionid);
});
They used signed authorization strings to authorize users.
I haven't yet mirrored this to socket.io, but I think it could be pretty interesting concept.
I know this is bit old, but for future readers in addition to the approach of parsing cookie and retrieving the session from the storage (eg. passport.socketio ) you might also consider a token based approach.
In this example I use JSON Web Tokens which are pretty standard. You have to give to the client page the token, in this example imagine an authentication endpoint that returns JWT:
var jwt = require('jsonwebtoken');
// other requires
app.post('/login', function (req, res) {
// TODO: validate the actual user user
var profile = {
first_name: 'John',
last_name: 'Doe',
email: 'john#doe.com',
id: 123
};
// we are sending the profile in the token
var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });
res.json({token: token});
});
Now, your socket.io server can be configured as follows:
var socketioJwt = require('socketio-jwt');
var sio = socketIo.listen(server);
sio.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
sio.sockets
.on('connection', function (socket) {
console.log(socket.handshake.decoded_token.email, 'has joined');
//socket.on('event');
});
The socket.io-jwt middleware expects the token in a query string, so from the client you only have to attach it when connecting:
var socket = io.connect('', {
query: 'token=' + token
});
I wrote a more detailed explanation about this method and cookies here.
Here is my attempt to have the following working:
express: 4.14
socket.io: 1.5
passport (using sessions): 0.3
redis: 2.6 (Really fast data structure to handle sessions; but you can use others like MongoDB too. However, I encourage you to use this for session data + MongoDB to store other persistent data like Users)
Since you might want to add some API requests as well, we'll also use http package to have both HTTP and Web socket working in the same port.
server.js
The following extract only includes everything you need to set the previous technologies up. You can see the complete server.js version which I used in one of my projects here.
import http from 'http';
import express from 'express';
import passport from 'passport';
import { createClient as createRedisClient } from 'redis';
import connectRedis from 'connect-redis';
import Socketio from 'socket.io';
// Your own socket handler file, it's optional. Explained below.
import socketConnectionHandler from './sockets';
// Configuration about your Redis session data structure.
const redisClient = createRedisClient();
const RedisStore = connectRedis(Session);
const dbSession = new RedisStore({
client: redisClient,
host: 'localhost',
port: 27017,
prefix: 'stackoverflow_',
disableTTL: true
});
// Let's configure Express to use our Redis storage to handle
// sessions as well. You'll probably want Express to handle your
// sessions as well and share the same storage as your socket.io
// does (i.e. for handling AJAX logins).
const session = Session({
resave: true,
saveUninitialized: true,
key: 'SID', // this will be used for the session cookie identifier
secret: 'secret key',
store: dbSession
});
app.use(session);
// Let's initialize passport by using their middlewares, which do
//everything pretty much automatically. (you have to configure login
// / register strategies on your own though (see reference 1)
app.use(passport.initialize());
app.use(passport.session());
// Socket.IO
const io = Socketio(server);
io.use((socket, next) => {
session(socket.handshake, {}, next);
});
io.on('connection', socketConnectionHandler);
// socket.io is ready; remember that ^this^ variable is just the
// name that we gave to our own socket.io handler file (explained
// just after this).
// Start server. This will start both socket.io and our optional
// AJAX API in the given port.
const port = 3000; // Move this onto an environment variable,
// it'll look more professional.
server.listen(port);
console.info(`🌐 API listening on port ${port}`);
console.info(`🗲 Socket listening on port ${port}`);
sockets/index.js
Our socketConnectionHandler, I just don't like putting everything inside server.js (even though you perfectly could), especially since this file can end up containing quite a lot of code pretty quickly.
export default function connectionHandler(socket) {
const userId = socket.handshake.session.passport &&
socket.handshake.session.passport.user;
// If the user is not logged in, you might find ^this^
// socket.handshake.session.passport variable undefined.
// Give the user a warm welcome.
console.info(`⚡︎ New connection: ${userId}`);
socket.emit('Grettings', `Grettings ${userId}`);
// Handle disconnection.
socket.on('disconnect', () => {
if (process.env.NODE_ENV !== 'production') {
console.info(`⚡︎ Disconnection: ${userId}`);
}
});
}
Extra material (client):
Just a very basic version of what the JavaScript socket.io client could be:
import io from 'socket.io-client';
const socketPath = '/socket.io'; // <- Default path.
// But you could configure your server
// to something like /api/socket.io
const socket = io.connect('localhost:3000', { path: socketPath });
socket.on('connect', () => {
console.info('Connected');
socket.on('Grettings', (data) => {
console.info(`Server gretting: ${data}`);
});
});
socket.on('connect_error', (error) => {
console.error(`Connection error: ${error}`);
});
References:
I just couldn't reference inside the code, so I moved it here.
1: How to set up your Passport strategies: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
This article (http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/) shows how to
store sessions of the HTTP server in Redis (using Predis)
get these sessions from Redis in node.js by the session id sent in a cookie
Using this code you are able to get them in socket.io, too.
var io = require('socket.io').listen(8081);
var cookie = require('cookie');
var redis = require('redis'), client = redis.createClient();
io.sockets.on('connection', function (socket) {
var cookies = cookie.parse(socket.handshake.headers['cookie']);
console.log(cookies.PHPSESSID);
client.get('sessions/' + cookies.PHPSESSID, function(err, reply) {
console.log(JSON.parse(reply));
});
});
use session and Redis between c/s
Server side
io.use(function(socket, next) {
// get here session id
console.log(socket.handshake.headers.cookie); and match from redis session data
next();
});
this should do it
//server side
io.sockets.on('connection', function (con) {
console.log(con.id)
})
//client side
var io = io.connect('http://...')
console.log(io.sessionid)

How to verify a Paypal webhook notification DIY style (without using Paypal SDK)

Upon integrating the smart button of Paypal I have issues to verify webhook notifications sent by Paypal. The examples I have found are either outdated or do not work.
Is there a way to verify the webhook notifications, ideally in a DIY way (ie. without having to use the bulky and complex Paypal API)?
To the best of my knowledge, this code is only one that actually works. All other examples I have found on stack overflow will not work because instead of passing the ID of the webhook itself when composing the signature string, they use the ID of the webhook event, thus the verify will fail.
The webhook ID will be generated once you add the webhook in the developer backend of Paypal. After creation of the webhook you will see its id in the list of installed webhooks.
The rest is pretty straight forward: We get the headers and the HTTP body and compose the signature using Paypal's recipe:
To generate the signature, PayPal concatenates and separates these
items with the pipe (|) character.
"These items" are: The transmission id, the transmission date, the webhook id and a CRC over the HTTP body. The first two can be found in the header of the request, the webhook id in the developer backend (of course, that id will never change), the CRC is calculated like shown below.
The certificate's location is in the header, too, so we load it and extract the private key.
Last thing to watch out for: The name of the algorithm provided by Paypal (again in a header field) is not exactly the same as understood by PHP. Paypal calls it "sha256WithRSA" but openssl_verify will expect "sha256WithRSAEncryption".
// get request headers
$headers=apache_request_headers();
// get http payload
$body=file_get_contents('php://input');
// compose signature string: The third part is the ID of the webhook ITSELF(!),
// NOT the ID of the webhook event sent. You find the ID of the webhook
// in Paypal's developer backend where you have created the webhook
$data=
$headers['Paypal-Transmission-Id'].'|'.
$headers['Paypal-Transmission-Time'].'|'.
'[THE_ID_OF_THE_WEBHOOK_ACCORDING_TO_DEVELOPER_BACKEND]'.'|'.
crc32($body);
// load certificate and extract public key
$pubKey=openssl_pkey_get_public(file_get_contents($headers['Paypal-Cert-Url']));
$key=openssl_pkey_get_details($pubKey)['key'];
// verify data against provided signature
$result=openssl_verify(
$data,
base64_decode($headers['Paypal-Transmission-Sig']),
$key,
'sha256WithRSAEncryption'
);
if ($result==1) {
// webhook notification is verified
...
}
elseif ($result==0) {
// webhook notification is NOT verified
...
}
else {
// there was an error verifying this
...
}
Answering this for nodejs, as there are subtle security issues and some missing logic in original (but very helpful) answer. This answer addresses the following issues:
Someone putting in their own URL and thereby getting authentication of their own requests
CRC needs to be an unsigned integer, not a signed integer.
NodeJs < 17.0 is missing some built in X509 functionality.
Ideally one should validate the signing cert with the built in cert chain
but NodeJS < 17.0 can't do this easily AFAICT. The trust model relies on TLS and the built in nodejs trust chain for the cert fetch URL and not the returned cert from cert URL , which is probably good enough.
const forge = require('node-forge');
const crypto = require('crypto')
const CRC32 = require('crc-32');
const axios = require('axios');
const transmissionId = paypalSubsEvent.headers['PAYPAL-TRANSMISSION-ID'];
const transmissionTime = paypalSubsEvent.headers['PAYPAL-TRANSMISSION-TIME'];
const signature = paypalSubsEvent.headers['PAYPAL-TRANSMISSION-SIG'];
const webhookId = '<your webhook ID from your paypal dev. account>';
const url = paypalSubsEvent.headers['PAYPAL-CERT-URL'];
const bodyCrc32 = CRC32.str(paypalSubsEvent.body);
const unsigned_crc = bodyCrc32 >>> 0; // found by trial and error
// verify domain is actually paypal.com, or else someone
// could spoof in their own cert
const urlObj = new URL(url);
if (!urlObj.hostname.endsWith('.paypal.com')) {
throw new Error(
`URL ${certUrl} is not in the domain paypal.com, refusing to fetch cert for security reasons`);
}
const validationString =
transmissionId + '|'
+ transmissionTime + '|'
+ webhookId + '|'
+ unsigned_crc;
const certResult = await axios.get(url); // Trust TLS to check the URL is really from *.paypal.com
const cert = forge.pki.certificateFromPem(certResult.data);
const publicKey = forge.pki.publicKeyToPem(cert.publicKey)
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(validationString);
verifier.end();
const result = verifier.verify(publicKey, signature, 'base64');
console.log(result);
You can use the following steps with Paypal API's
Create App and get the Client ID and Secret from the Developer dashboard
Create Webhook inside App and get a webhook ID
Implementation PayPal API's
https://www.postman.com/paypal/workspace/paypal-public-api-workspace/collection/19024122-92a85d0e-51e7-47da-9f83-c45dcb1cdf24?action=share&creator=22959279
Get the new Access token with help of Client ID and Secret, every time connect with PayPal.
4.Use the webhook Id, Access Token, and request Headers to verify the Webhook
try{
$json = file_get_contents('php://input');
$data = json_decode($json);
$paypalmode = ($this->dev_mode == 0) ? '' : '.sandbox';
$API_Endpoint = 'https://api-m' . $paypalmode . '.paypal.com/v1/';
//step-01 get token
$res_token = getToken($API_Endpoint);//get Token mention in above postman link
//step-02 validate webhook
$webhook_id = 'XXXXXX';
$post_data = array(
"webhook_id" => $webhook_id ,
"transmission_id" => $_SERVER['HTTP_PAYPAL_TRANSMISSION_ID'],
"transmission_time" => $_SERVER['HTTP_PAYPAL_TRANSMISSION_TIME'],
"cert_url" => $_SERVER['HTTP_PAYPAL_CERT_URL'],
"auth_algo" => $_SERVER['HTTP_PAYPAL_AUTH_ALGO'],
"transmission_sig" => $_SERVER['HTTP_PAYPAL_TRANSMISSION_SIG'],
"webhook_event" => $data
);
$res = verifyWebhook($API_Endpoint . 'notifications/verify-webhook-signature',
$res_token['access_token'], $post_data);//use postman 'verify-webhook-signature' api mention in webhook section
if (isset($res->verification_status) && $res->verification_status == 'SUCCESS') {
//success
}else{
//failure
}
} catch (Exception $ex) {
//error
}
Responding to this to save potential headaches but the above example does not work because an authentication token is needed to be sent along with your get request for the cert file "file_get_contents($header['Paypal-Cert-Url'])" will not work on its own.
Simply include your authentication token in the header and it'll work.

Laravel/Lumen Auth JWT token not valid in subsequent requests, is it possibly expired?

I have an app that uses Laravel/Lumen and its Auth guard JWT tokens for login.
I send a request to
http://myserver.com/authenticate
and I get a token in response.
Then when I use this token in subsequent requests
http://myserver.com/users
with the token in the header
Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJjbG96ZXJ0b29sc1YyIiwianRpIjoiNTBiMjE1MjllZGIxMmI4OGJlYTJmOTQxMTViNjc2NmYiLCJpYXQiOjE1MzY1NTU3NzEsIm5iZiI6MTUzNjU1NTc3NiwiZXhwIjoxNTM2NTcwOTc2LCJkYXRhIjp7ImVtYWlsIjoia3lsZWtvb3BtYW5AZ21haWwuY29tIiwiYXZhdGFyIjoiIiwiZmlyc3RfbmFtZSI6Ikt5bGUiLCJsYXN0X25hbWUiOiJLb29wbWFuIiwiaWQiOjMzNH0sInN1YiI6MzM0fQ.p20K56BW0c_J-xlk9gV6wDFafxgNuKUOmgk-4ExKhh9qPw79R0bpm-QbnVQFtYlatB_MjLYK1NdUt5GlGaOE9w
The request obviously usually comes back with a 200, (on my local server anyways)
However, on my production server all subsequent requests with the provided token come back with a 401 / Unauthorized
All the settings are the same on both servers.
I have this in my .env on both my production server, and local server.
JWT_KEY=yUyg2oo3M2N0Lf0CnsbG1ztsL1ovA70K
JWT_EXPIRE_AFTER=15200
JWT_ISSUER=mysite
JWT_ID_FIELD=id
JWT_NBF_DELAY=25
DB_TIMEZONE=+00:00
APP_TIMEZONE=UTC
My assumption is that it has something to do with expiry and/or server time.
Like I think that the token is coming back already expired, therefore on the subsequent request it is invalid.
Am I correct in thinking this is where the issue lies? And how do I go about fixing it/testing it?
You can visit https://jwt.io and paste your token into the encoded field to get back the expire date and check then in the developer console
const currentTime = Date.now() / 1000
if( exp < currentTime) {
// is expired
}
I have something like this in my code:
const checkExpiredJwtDate = token => {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jwtObject = JSON.parse(window.atob(base64))
const currentTime = Date.now() / 1000;
if (jwtObject.exp < currentTime) {
// is expired...
}
};
How to decode jwt token in javascript

Can I use APNs Auth Key .p8 file with PHP to send iOS push notifications?

My push notifications stopped working with one of the recent updates. When I looked into it more, I discovered that Apple now lets you generate a non-expiring APNs Auth Key that works for both production and test. I have it working with the following node.js script:
var apn = require('apn');
// Set up apn with the APNs Auth Key
var apnProvider = new apn.Provider({
token: {
key: 'apns.p8', // Path to the key p8 file
keyId: '<my key id>', // The Key ID of the p8 file (available at https://developer.apple.com/account/ios/certificate/key)
teamId: '<my team id' // The Team ID of your Apple Developer Account (available at https://developer.apple.com/account/#/membership/)
},
production: false // Set to true if sending a notification to a production iOS app
});
// Enter the device token from the Xcode console
var deviceToken = '<my device token>';
// Prepare a new notification
var notification = new apn.Notification();
// Specify your iOS app's Bundle ID (accessible within the project editor)
notification.topic = '<my bundle id';
// Set expiration to 1 hour from now (in case device is offline)
notification.expiry = Math.floor(Date.now() / 1000) + 3600;
// Set app badge indicator
notification.badge = 3;
// Play ping.aiff sound when the notification is received
notification.sound = 'ping.aiff';
// Display the following message (the actual notification text, supports emoji)
notification.alert = 'This is a test notification \u270C';
// Send any extra payload data with the notification which will be accessible to your app in didReceiveRemoteNotification
notification.payload = {id: 123};
// Actually send the notification
apnProvider.send(notification, deviceToken).then(function(result) {
// Check the result for any failed devices
console.log(result);
process.exit(0)
});
Is there any way to use the new APNs Auth Key with PHP? I can call the node.js script from PHP, using exec("node app.js &", $output);, and it works, but it starts to get ugly. Should PHP still work using the old .pem file approach?

Random 400 "token_invalid" errors with Laravel / jwt-auth and Angular / Satellizer app

I have an Angular app that consumes an API I built in Laravel, and I use jwt-auth for token management and satellizer on the front end to send the token with each request.
My live environment (for both the front end and the API - which will be moved to a different server once the app is finished) at the moment consists of 2 AWS EC2 instances running nginx with a load balancer. Both servers have the same jwt secret key.
However, and at the moment I can't work out any pattern to it, I randomly get 400 "token_invalid" errors returned from my api. It is not one particular api route, nor is it on every load of the app. When I get a 400 error, from my /clients endpoint for example, other requests will have returned 200's. Next time, all will return 200's. The time after that I may get 200 returned for /clients but a 400 error for /users.
Could this be an issue with me using a load balancer? The jwt secret key, as I said, is the same on both servers - as all the code is in GIT.
I am not using the jwt.refresh middleware.
One other thing to mention is that I don't ever get 400 errors returned when running the app locally via Homestead, ony in production.
EDIT - it seems as though logging out (which clears both my user object (basic details only) and the token from local storage, clearing my cache, then logging back in most often causes the error - is this helpful?
Below is an example of one of my api calls.
App.js
.service('ClientsService', function($http, $q, __env) {
this.index = function () {
var deferred = $q.defer();
$http.get(__env.apiUrl + '/clients')
.then(function successCallback(response) {
console.log(response.data);
deferred.resolve(response.data);
},
function errorCallback(response) {
console.log(response);
});
return deferred.promise;
}
})
ClientsController.js
.controller('ClientsController', function(ClientsService, $stateParams, $mdDialog, $mdToast) {
var vm = this;
ClientsService.index().then(function(clients) {
console.log('ClientsCtrl init');
vm.clients = clients.data;
});
// other controller code
})
I'm really struggling to debug this, so any help would be much appreciated. If any more info is needed, please let me know.
https://github.com/tymondesigns/jwt-auth/issues/1583
solution: use the same jwt secret in .env file

Categories