I'm trying to parse the json signed_request you receive from Facebook in perl but need a little help!
($encoded_sig, $payload) = split('\.', $formdata{'signed_request'});
$sig = decode_base64url($encoded_sig);
$data = decode_json(decode_base64url($payload));
%decoded = %{ decode_json(decode_base64url($payload)) };
$expected_sig = hmac_sha256($payload, $app_secret);
if ($expected_sig eq $sig) {
while (my ($key, $value) = each %decoded) {
print "$key = $value\n<br>";
}
}
Each $value can either contain a string or a reference to another HASH (and some of those HASHs may contain another HASH), is there a better way to process this?
The script above returns:
algorithm = HMAC-SHA256
page = HASH(0x632b100)
issued_at = 1323081670
user = HASH(0x632b150)
and the json received after decoding is:
{"algorithm":"HMAC-SHA256","issued_at":1323081670,"page":{"id":"192130540873448","liked":true,"admin":true},"user":{"country":"gb","locale":"en_GB","age":{"min":21}}}
Ideally would like to see a result of:
algorithm = HMAC-SHA256
page-id = 192130540873448
page-liked = true
page-admin = true
issued_at = 1323081670
user-country = gb
user-locale = en_GB
user-age-min = 21
Data structure will increase as upon an authorised user response from Facebook more data is provided.
Many thanks
Initially I posted an URL with a working example. Thanks to Brad for pointing out that it's better to provide a code here, so I removed an URL and included the code below:
#!/usr/bin/perl
use strict;
use CGI;
use MIME::Base64;
use JSON;
use Digest::SHA qw(hmac_sha256);
my $secret = '<secret>';
my $q = new CGI;
my $sreq = $q->param('signed_request');
eval {
die 'not a signed_request' unless (defined $sreq);
my ($esig, $pload) = split('\.', $sreq);
$esig = decode_base64url($esig);
my $vsig = hmac_sha256($pload, $secret);
die 'invalid signature' unless ($esig eq $vsig);
my $data = decode_json(decode_base64url($pload));
print "Content-Type: text/html\n\n";
if ($data->{'page'}->{'liked'} eq 'true') {
print "Oh yeah, you liked me :-)";
} else {
print "No? why not? Please press the Like button";
}
};
if ($#) {
print "Content-Type: text/html\n\ndied: $#";
}
sub decode_base64url {
my $s = shift;
$s =~ tr[-_][+/];
$s .= '=' while length($s) % 4;
return decode_base64($s);
}
sub parse_hash {
my $hash = shift;
my $array = [];
foreach my $key (keys %$hash) {
if (ref($hash->{$key}) eq 'HASH') {
push #$array, $key . ' => {' . join(', ', #{ parse_hash($hash->{$key}) }) . '}';
} else {
push #$array, $key . ' => ' . $hash->{$key};
}
}
return $array;
}
To answer my own question :)
if ($expected_sig eq $sig) {
while (my ($key, $value) = each %decoded) {
if (ref($value) eq "HASH") {
while ( my ($key2, $value2) = each(%{$value}) ) {
$mydata{"$key-$key2"}=$value2;
if (ref($value2) eq "HASH") {
while ( my ($key3, $value3) = each(%{$value2}) ) {
$mydata{"$key-$key2-$key3"}=$value3;
print "$key-$key2-$key3 = $value3\n<br>";
}}
else
{
print "$key-$key2 = $value2\n<br>";
}}}
else
{
$mydata{"$key"}=$value;
print "$key = $value\n<br>";
}}}
outputs:
algorithm = HMAC-SHA256
page-admin = 1
page-liked = 1
page-id = 192130540873448
issued_at = 1323081670
user-country = gb
user-locale = en_GB
user-age-min = 21
Only way is:
$my_algorithm = $algorithm
$page-id = $page->{'id'};
$page-liked = $page->{'linked'};
$page-admin = $page->{'admin'};
$my_issued_at = $issued_at
$user-country = $user->{'country'};
$user-locale = $user->{'locale'};
$user-age-min = $user->{'age'}->{'min'};
Related
I would like to log SOAP::Lite transport request/response contents using a custom identifier (e.g. a transaction-id or txn_id in my example below):
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use SOAP::Lite +trace => [ transport => \&log_transport, ];
sub log_transport {
my ($in) = #_;
if (ref($in) eq "HTTP::Request") {
# INSERT INTO logs ( txn_id, request ) VALUES ( $tnx_id, $in->content )
say STDERR Dumper(ref($in), $in->content);
}
elsif (ref($in) eq "HTTP::Response") {
# UPDATE logs SET response = '$in->content' WHERE txn_id = $tnx_id
say STDERR Dumper(ref($in), $in->content);
}
}
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
my $soap = SOAP::Lite->proxy('https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords');
$soap->serializer()->register_ns('http://www.dataaccess.com/webservicesserver/' ,"ns");
sub getWords
{
my ($number, $txn_id) = #_ ;
my $method = SOAP::Data->name("ns:NumberToWords");
my #params = ( SOAP::Data->name("ubiNum" => $number) );
my $response = $soap->call($method => #params);
if (!$response->fault) {
say STDOUT "NumberToWords = " . $response->result;
}
else {
say STDERR "error: " . (defined $response->faultstring? $response->faultstring : $soap->transport->status);
}
}
getWords(444, '123abc');
In my example above, how can I pass the transaction-id 123abc to my logger?
P.S. I do not wish to use:
$soap->outputxml(1)->call($method => #params)
It does not seem like the SOAP::Trace transport callback supports extra argument passing. As a workaround you could use a lexical variable declared in the outer scope like this:
use strict;
use warnings;
use Data::Dumper;
my $TXN_ID;
use SOAP::Lite +trace => [ transport => \&log_transport, ];
sub log_transport {
my ($in) = #_;
say STDERR "Logging transaction id: $TXN_ID:";
if (ref($in) eq "HTTP::Request") {
# INSERT INTO logs ( txn_id, request ) VALUES ( $tnx_id, $in->content )
say STDERR Dumper(ref($in), $in->content);
}
elsif (ref($in) eq "HTTP::Response") {
# UPDATE logs SET response = '$in->content' WHERE txn_id = $tnx_id
say STDERR Dumper(ref($in), $in->content);
}
}
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
my $soap = SOAP::Lite->proxy('https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords');
$soap->serializer()->register_ns('http://www.dataaccess.com/webservicesserver/' ,"ns");
sub getWords
{
my ($number, $txn_id) = #_ ;
$TXN_ID = $txn_id;
my $method = SOAP::Data->name("ns:NumberToWords");
my #params = ( SOAP::Data->name("ubiNum" => $number) );
my $response = $soap->call($method => #params);
if (!$response->fault) {
say STDOUT "NumberToWords = " . $response->result;
}
else {
say STDERR "error: " . (defined $response->faultstring? $response->faultstring : $soap->transport->status);
}
}
getWords(444, '123abc');
I make the scanner using perl, but when i try to test the script i got blank results on the some engine, didn't give me results, may someone help me to check the script where line is wrong writing in perl?
Thanks
sub google() {
my #list;
my $key = $_[0];
for (my $i=0; $i<=1000; $i+=100){
my $search = ("http://www.google.com/search?q=".key($key)."&num=100&filter=0&start=".$i);
my $res = search_engine_query($search);
while ($res =~ m/<a href=\"?http:\/\/([^>\"]*)\//g) {
my $link = $1;
if ($link !~ /google/){
my #grep = links($link);
push(#list,#grep);
}
}
}
return #list;
}
sub search_engine() {
my (#total,#clean);
my $chan = $_[0];
my $bug = $_[1];
my $dork = $_[2];
my $engine = $_[3];
my $logo = $_[4];
if ($engine eq "GooGLe") { my #google = google($dork); push(#total,#google); }
if ($engine eq "AllTheWeb") { my #alltheweb = alltheweb($dork); push(#total,#alltheweb); }
if ($engine eq "Bing") { my #bing = bing($dork); push(#total,#bing); }
if ($engine eq "ALtaViSTa") { my #altavista = altavista($dork); push(#total,#altavista); }
if ($engine eq "AsK") { my #ask = ask($dork); push(#total,#ask); }
if ($engine eq "UoL") { my #uol = uol($dork); push(#total,#uol); }
if ($engine eq "YahOo") { my #yahoo = yahoo($dork); push(#total,#yahoo); }
#clean = clean(#total);
&msg("$chan","$logo(7#2$engine15)12 Total:4 (".scalar(#total).")12 Clean:4 (".scalar(#clean).")");
return #clean;
}
if ($engine =~ /google/i) {
if (my $pid = fork) { waitpid($pid, 0); }
else { if (fork) { exit; } else {
&lfc($chan,$bug,$dork,"GooGLe");
} exit; }
}
You can download n0body Scanner at here.
For one thing, you are using a zero-argument prototype for a function that you pass an argument to. Don't do that.
For another, are you inspecting the response whenever you are unhappy with the results? Is the response something other than 200? Does the response include an error message from the search engine?
Based on this line alone:
&msg("$chan",
"$logo(7#2$engine15)12 Total:4 (".scalar(#total).")12 Clean:4 (".scalar(#clean).")");
I also conclude that you're not using use strict and use warnings. Do that.
I am try to get the list items from share point server site using perl
script.i am write the script but give the error "401 Unauthorized". please help to solve
this problem.In this i am geven domain ,username ,password also.once see the credentials.
i am write script below
use LWP::UserAgent;
use LWP::Debug;
use Data::Dumper;
use SOAP::Lite on_action => sub { "$_[0]$_[1]"; };
import SOAP::Data 'name', 'value';
our $sp_endpoint = 'http://sezdsk22787/_vti_bin/lists.asmx';
our $sp_domain = 'dev:80';
our $sp_username = 'spadmin';
our $sp_password = 'Cmc#1234';
$debug = 0;
if ($debug) {
LWP::Debug::level('+');
SOAP::Lite->import(+trace => 'all');
}
my #ua_args = (keep_alive => 1);
my #credentials = ($sp_domain, "", $sp_username, $sp_password);
my $schema_ua = LWP::UserAgent->new(#ua_args);
$schema_ua->credentials(#credentials);
$soap = SOAP::Lite->proxy($sp_endpoint, #ua_args, credentials => \#credentials);
$soap->schema->useragent($schema_ua);
$soap->uri("http://schemas.microsoft.com/sharepoint/soap/GetVersions");
$lists = $soap->GetListCollection();
quit(1, $lists->faultstring()) if defined $lists->fault();
sub lists_getid
{
my $title = shift;
my #result = $lists->dataof('//GetListCollectionResult/Lists/DL_Accounts');
foreach my $data (#result) {
my $attr = $data->attr;
return $attr->{ID} if ($attr->{Title} eq $title);
}
return undef;
}
print "#credentials \n";
sub lists_getitems
{
my $listid = shift;
my $in_listName = name('listName' => $listid);
my $in_viewName = name('viewName' => '');
my $in_rowLimit = name('rowLimit' => 99999);
my $call = $soap->GetListItems($in_listName, $in_viewName, $in_rowLimit);
quit(1, $call->faultstring()) if defined $call->fault();
return $call->dataof('//GetListItemsResult/listitems/data/row');
}
my $list_id = lists_getid('Disk Space');
print "List ID is: $list_id\n";
my #items = lists_getitems($list_id);
foreach my $data (#items) {
my $attr = $data->attr;
print Dumper($attr);
}
I'm working on an adhoc GUI so that I can easily view a bunch of data from the VMWare Perl SDK without having to setup a bunch of scripts under IIS. The basic idea is to start up the script, and have it fork two processes. One is the HTTP::Daemon web server, and then two seconds later its the Win32::IEAutomation run browser. It's not pretty, I admit, but I'm slightly comfortable with the VMPerlSDK than the VMCOMSDK. Plus I'm kind of curious to see if I can get this to work.
As far as I can tell, the program starts okay. The fork works. The little URI parser works. The only problem is whenever I try to call /quit to shutdown the server, the script explodes.
Any suggestions (aside from how this should be done with IIS and AutoIT, I know, I know) would be appreciated. Thanks!
#!/usr/bin/perl -w
use Data::Dumper;
use HTTP::Daemon;
use HTTP::Status;
use HTTP::Response;
use strict;
use warnings;
use Win32::IEAutomation;
sub MainPage {
return<<eol
<html>
<head><title>Test</title></head>
<body>
<h3>Home</h3>
<p>Quit</p>
</body>
</html>
eol
}
# Parses out web variables
sub WebParse {
my ($wstring) = #_;
my %webs = ();
# gets key/value data
my #pairs = split(/&/, $wstring);
# puts the key name into an array
foreach my $pair (#pairs) {
my ($kname, $kval) = split (/=/, $pair);
$kval =~ tr/+/ /;
$kval =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$webs{$kname} = $kval;
}
return(%webs);
}
sub StartServer {
my $PORT = shift;
my $ALLOWED = shift;
my $d = HTTP::Daemon->new(ReuseAddr => 1, LocalAddr => $ALLOWED, LocalPort => $PORT) || die;
# Prints a startup message
print "Please contact me at: <URL:", $d->url, ">\n";
my $xt = 0;
BLOOP: while (my $c = $d->accept) {
while (my $r = $c->get_request) {
# Handles requests with the GET or POST methods
if ($r->method =~ m/GET/i || $r->method =~ m/POST/i) {
my $uri = $r->uri; my %ENV = ();
$ENV{REQUEST_METHOD} = $r->method;
$ENV{CONTENT_TYPE} = join('; ', $r->content_type);
$ENV{CONTENT_LENGTH} = $r->content_length || '';
$ENV{SCRIPT_NAME} = $uri->path || 1;
$ENV{REMOTE_ADDR} = $c->peerhost();
if ($r->method =~ m/GET/i) {
$ENV{QUERY_STRING} = $uri->query || '';
}
elsif ($r->method =~ m/POST/i) {
$ENV{QUERY_STRING} = $r->{"_content"} || '';
}
my %q = &WebParse($ENV{QUERY_STRING});
my $res = HTTP::Response->new("200");
if ($uri =~ m/quit/i) {
$res->content("Goodbye");
$xt=1;
}
else {
$res->content(MainPage());
}
$c->send_response($res);
}
# Otherwise
else {
$c->send_error("This server only accepts GET or POST methods");
}
if ($xt == 1) {
sleep(2);
$c->force_last_request();
last BLOOP;
}
$c->close;
}
undef($c);
}
$d->close;
undef($d);
exit;
}
sub StartInterface {
my $PORT = shift;
my $ALLOWED = shift;
my $ie = Win32::IEAutomation->new(visible => 1, maximize => 1);
$ie->gotoURL("http://".$ALLOWED.":".$PORT."/");
exit;
}
# Return Status
my $STATUS = 1;
# Server port number
my $PORT = 9005;
# The server that's allowed to talk to this one
my $ALLOWED = "127.0.0.1";
my $pid = fork();
if ($pid == 0) {
StartServer($PORT, $ALLOWED);
} else {
sleep(2);
StartInterface($PORT, $ALLOWED);
}
exit;
before you close your daemon $d, shutdown the socket and tell the parent pid to quit:
$d->shutdown(2);
$d->close;
undef $d;
kill(2,getppid());
exit;
How to get the value of a parameter code using URI::URL Perl module?
From this link:
http://www.someaddress.com/index.html?test=value&code=INT_12345
It can be done using URI::URL or URI (I know the first one is kind of obsolete). Thanks in advance.
Create a URI object and use the query_form method to get the key/value pairs for the query. If you know that the code parameter is only specified once, you can do it like this:
my $uri = URI->new("http://www.someaddress.com/index.html?test=value&code=INT_12345");
my %query = $uri->query_form;
print $query{code};
Alternatively you can use URI::QueryParam whichs adds soem aditional methods to the URI object:
my $uri = URI->new("http://www.someaddress.com/index.html?test=value&code=INT_12345");
print $uri->query_param("code");
use URI;
my $uri = URI->new("http://someaddr.com/index.html?test=FIRST&test=SECOND&code=INT_12345");
my %query = $uri->query_form;
use Data::Dumper;
print Dumper \%query;
We can see:
$VAR1 = {
'test' => 'SECOND',
'code' => 'INT_12345'
};
Unfortunately, this result is wrong.
There is possible solution:
use URI::Escape;
sub parse_query {
my ( $query, $params ) = #_;
$params ||= {};
foreach $var ( split( /&/, $query ) ){
my ( $k, $v ) = split( /=/, $var );
$k = uri_unescape $k;
$v = uri_unescape $v;
if( exists $params->{$k} ) {
if( 'ARRAY' eq ref $params->{$k} ) {
push #{ $params->{$k} }, $v;
} else {
$params->{$k} = [ $params->{$k}, $v ];
}
} else {
$params->{$k} = $v;
}
}
return $params;
}