How can I listen to webhooks from PayStack? - webhooks

I created a website and I integrated payment using PayStack and it is fully functional, but something unusual came up sometime when a customer wanted to make a payment. After the successful payment processing, maybe something went wrong with the customer's Network provider but the customer was not redirected to a success page where to give values to database.
So I implemented webhooks to get values from paystack and PUT THE CONTENTS in a .txt (webhookApi.txt) file but it seems something is wrong with the code and I can't figure it out.
`
<?php
// only a post with paystack signature header gets our attention
if ((strtoupper($_SERVER['REQUEST_METHOD']) != 'POST' ) || !array_key_exists('x-paystack-signature', $_SERVER) )
exit();
// Retrieve the request's body
$input = #file_get_contents("php://input");
define('PAYSTACK_SECRET_KEY','sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxx');
// validate event do all at once to avoid timing attack
if($_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] !== hash_hmac('HMAC SHA512', $input, PAYSTACK_SECRET_KEY))
exit();
http_response_code(200);
// parse event (which is json string) as object
// Do something - that will not take long - with $event
$event = json_decode($input);
$reference = $event->data->reference;
$email = $event->data->customer->email;
$eventMessage = $event->event;
file_put_contents("webhookApi.txt", PHP_EOL.$input, FILE_APPEND);
exit();
?>
`

Related

How to receive Shopify Webhook?

Below is my code.
define('SHOPIFY_APP_SECRET', 'xxxxxxxxxx');
function verify_webhook($data, $hmac_header)
{
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPIFY_APP_SECRET, true));
return hash_equals($hmac_header, $calculated_hmac);
}
$hmac_header = $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
echo "<pre>";
print_r($data);
exit;
?>
I've registered the app/uninstalled webhook.
So this is my code but not receiving any response
I know it is a late answer. But might helpful for the future user who will land here. You forgot to save the response you are getting from uninstall webhook to somewhere. Considered saving response to file. here is php code to save. After saving the response you can read or do processing after that.
file_put_contents($newFileName, $data);
Also, save the response only when HMAC hash matched you got from api. You can get domain name and for which topic api is fired. below is code. Do the necessary work.
$domain = $_SERVER['X-Shopify-Shop-Domain'];
$topic = $_SERVER['X-Shopify-Topic'];
Let me know if you are looking for more detail. thanks

Twilio How to do pagination with messages?

I am able to get the messages from the new php client. How do I do pagination with messages? How to get next_uri, first_uri, page_size parameters ?
<?php
require_once '/Twilio/autoload.php'; // Loads the library
use Twilio\Rest\Client;
// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "xxx";
$token = "xxx";
$client = new Client($sid, $token);
// Loop over the list of messages and echo a property for each one
foreach ($client->messages->read() as $message) {
echo $message->body;
}
?>
Twilio developer evangelist here.
Instead of using read() you can use stream() which will return an iterator for your messages. You can give stream() a limit, but by default it has no limit and will iterate over all of your messages.
<?php
require_once '/Twilio/autoload.php'; // Loads the library
use Twilio\Rest\Client;
// Your Account Sid and Auth Token from twilio.com/user/account
$sid = "xxx";
$token = "xxx";
$client = new Client($sid, $token);
// Loop over the list of messages and echo a property for each one
foreach ($client->messages->stream() as $message) {
echo $message->body;
}
?>
The pagination information itself is returned in each request. You can see an example of a call to the Calls resource in the documentation and the pagination information will be the same for Messages.
I wasted hours on this. In case it saves some future person some time, here's what I did. I'm using Laravel but you get the idea:
In your controller:
// If no pagination info has been specified, get the first page of data
// using page(). If there is pagination info in the request, use it with
// getPage()
if (! $request->page) {
$messages = $client->messages->page([], 30);
} else {
$messages = $client->messages->getPage($request->page);
}
Then, in your view (Laravel/blade pseudo-code):
#foreach ($messages as $message)
$message->body
// ... etc
#endforeach
// Next page link
?page={{ urlencode($messages->getNextPageUrl()) }}
// Prev page link
?page={{ urlencode($messages->getPreviousPageUrl()) }}
Docs for page() and getPage().
Here is the Node.js code for fetching message history using paging. You can specify how many items should be in a single page by using the parameter pageSize and use limit parameter to limit the number of pages to display
client.messages.each({
dateSent: new Date(date.toDateString()),
from: event.To,
to: event.From,
pageSize: 1,
limit:1,
done: function(done) {//this is the call back for the for each loop. this will get fired even if no messages found.
console.log('completed for each');
}
}, (messages) => {//each message can handle here.
console.log("message body:", messages.body);
}, (Error) => {
console.log('err');
});

Instagram API: the server doesn't receive data

I use this code to get data from Instagram API. The code runs correctly on some servers, but on other servers it doesn't receive data from Instagram API. The "Curl" is enabled in all servers, who knows what happened?
<?php
require 'instagram.class.php';
require 'config.php';
// Receive OAuth code parameter
$code = $_GET['code'];
// Check whether the user has granted access
if (true === isset($code)) {
// Receive OAuth token object
// Take a look at the API response
$data = $instagram->getOAuthToken($code);
if(empty($data->user->username)){
header('Location: index.php');
} else {
session_start();
$_SESSION['xxx']=$data;
$user=$data->user->username;
$ig_id=$data->user->id;
header('Location: profile.php');
}
} else {
// Check whether an error occurred
if (true === isset($_GET['error'])){
echo $_GET['error_description'];
}
}
?>

Mandrill Webhooks - Security

For security purposes, I try to allow only Mandrill's IP(s) to access these urls.
Does anyone know them?
Mandrill's signature is located in the HTTP response header: Authenticating-webhook-requests
In the request header find: X-Mandrill-Signature. This is a base64 of the hashcode, signed using web-hook key. This key is secret to your webhook only.
We have a range of IPs used for webhooks, but they can (and likely will) change or have new ones added as we scale. An alternative would be to add a query string to the webhook URL you add in Mandrill, and then check for that query string when a POST comes in so you can verify it's coming from Mandrill.
Just replace the constants and use this function:
<?php
function generateSignature($post)
{
$signed_data = WEB_HOOK_URL;
ksort($post);
foreach ($post as $key => $value) {
$signed_data .= $key;
$signed_data .= $value;
}
return base64_encode(hash_hmac('sha1', $signed_data, WEB_HOOK_AUTH_KEY, true));
}
//---
if (generateSignature($_POST) != $_SERVER['HTTP_X_MANDRILL_SIGNATURE']) {
//Invalid
}
?>
As described in mandrill's docs, they provide a signature to check if the request really came from them. to build the request there's a few steps:
start with the exact url of your webhook (mind slashes and params)
sort the post variables by key (in case of mandrill, you'll only have one post parameter: mandrill_events)
add key and value to the url, without any delimiter
hmac the url with your secret key (you can get the key from the web-interface) and base64 it.
compare the result with the X-Mandrill-Signature header
here's a sample implementation in python:
import hmac, hashlib
def check_mailchimp_signature(params, url, key):
signature = hmac.new(key, url, hashlib.sha1)
for key in sorted(params):
signature.update(key)
signature.update(params[key])
return signature.digest().encode("base64").rstrip("\n")
205.201.136.0/16
I have just whitelisted them in my server's firewall.
We don't need to white list the Ip they are using. Instead of that they have provided their own way to authenticate the webhook request.
When you are creating the mandrill webhook it will generate the key. It will come under the response we are getting to our post URL which is provided in the webhook.
public async Task<IHttpActionResult> MandrillEmailWebhookResponse()
{
string mandrillEvents = HttpContext.Current.Request.Form["mandrill_events"].Replace("mandrill_events=", "");
// validate the request is coming from mandrill API
string url = ConfigurationManager.AppSettings["mandrillWebhookUrl"];
string MandrillKey = ConfigurationManager.AppSettings["mandrillWebHookKey"];
url += "mandrill_events";
url += mandrillEvents;
byte[] byteKey = System.Text.Encoding.ASCII.GetBytes(MandrillKey);
byte[] byteValue = System.Text.Encoding.ASCII.GetBytes(url);
HMACSHA1 myhmacsha1 = new HMACSHA1(byteKey);
byte[] hashValue = myhmacsha1.ComputeHash(byteValue);
string generatedSignature = Convert.ToBase64String(hashValue);
string mandrillSignature = HttpContext.Current.Request.Headers["X-Mandrill-Signature"].ToString();
if (generatedSignature == mandrillSignature)
{
// validation = "Validation successful";
// do the updating using the response data
}
}

Page secure script with Codeigniter. Am I along the right track?

I am creating a function to protect my admin pages if a user is not logged in. Am I doing it in a correct way. The following function is included on all my admin pages.
What else should I check for before give acccess to my admin pages for a secure page??
function is_logged_in_admin()
{
$CI =& get_instance();
$is_logged_in = $CI->session->userdata('is_logged_in');
$username = $CI->session->userdata('username');
$status = $CI->session->userdata('status');
if(!isset($is_logged_in) || $is_logged_in != true)
{
redirect('auth/login',location);
}
if(!$username == 'myeswr')
{
redirect('auth/login',location);
}
if(!$status == '1')
{
redirect('auth/resend_activation',location);
}
}
With the code you have here, there is a possibility for granting permission w/o intent. Its not likely, but if for some reason there is a logic error (not syntax error) somewhere in your code for if #1, you are not redirected, and the other 2 fail.
I suggest using if.. elseif.. elseif.. else. Final else being a redirect to login, as a failsafe.
You may also want to check length of login (or just use CI's built in session length).

Resources