magic-envelope verification, status.net appears to do it wrong.
Ultimately we need to do it right (or why bother having a spec?), and fallback to doing it wrong if we're talking to a broken system - which ironically seems to include most of the federated social web projects.
This commit is contained in:
parent
39b19cd089
commit
5edee3c4d1
73
boot.php
73
boot.php
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
define ( 'BUILD_ID', 1010 );
|
define ( 'BUILD_ID', 1011 );
|
||||||
define ( 'DFRN_PROTOCOL_VERSION', '2.0' );
|
define ( 'DFRN_PROTOCOL_VERSION', '2.0' );
|
||||||
|
|
||||||
define ( 'EOL', "<br />\r\n" );
|
define ( 'EOL', "<br />\r\n" );
|
||||||
|
@ -116,6 +116,7 @@ class App {
|
||||||
private $db;
|
private $db;
|
||||||
|
|
||||||
private $curl_code;
|
private $curl_code;
|
||||||
|
private $curl_headers;
|
||||||
|
|
||||||
function __construct() {
|
function __construct() {
|
||||||
|
|
||||||
|
@ -204,6 +205,15 @@ class App {
|
||||||
return $this->curl_code;
|
return $this->curl_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_curl_headers($headers) {
|
||||||
|
$this->curl_headers = $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_curl_headers() {
|
||||||
|
return $this->curl_headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// retrieve the App structure
|
// retrieve the App structure
|
||||||
|
@ -339,13 +349,12 @@ function t($s) {
|
||||||
// results.
|
// results.
|
||||||
|
|
||||||
if(! function_exists('fetch_url')) {
|
if(! function_exists('fetch_url')) {
|
||||||
function fetch_url($url,$binary = false) {
|
function fetch_url($url,$binary = false, &$redirects = 0) {
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
if(! $ch) return false;
|
if(($redirects > 8) || (! $ch))
|
||||||
|
return false;
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
|
|
||||||
curl_setopt($ch, CURLOPT_MAXREDIRS,8);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
||||||
|
|
||||||
// by default we will allow self-signed certs
|
// by default we will allow self-signed certs
|
||||||
|
@ -366,26 +375,41 @@ function fetch_url($url,$binary = false) {
|
||||||
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
|
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
|
||||||
|
|
||||||
$s = curl_exec($ch);
|
$s = curl_exec($ch);
|
||||||
$info = curl_getinfo($ch);
|
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$header = substr($s,0,strpos($s,"\r\n\r\n"));
|
||||||
|
if($http_code == 301 || $http_code == 302 || $http_code == 303) {
|
||||||
|
$matches = array();
|
||||||
|
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
|
||||||
|
$url = trim(array_pop($matches));
|
||||||
|
$url_parsed = parse_url($url);
|
||||||
|
if (isset($url_parsed)) {
|
||||||
|
$redirects++;
|
||||||
|
return fetch_url($url,$binary,$redirects);
|
||||||
|
}
|
||||||
|
}
|
||||||
$a = get_app();
|
$a = get_app();
|
||||||
$a->set_curl_code($info['http_code']);
|
$a->set_curl_code($http_code);
|
||||||
|
$body = substr($s,strlen($header)+4);
|
||||||
|
$a->set_curl_headers($header);
|
||||||
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return($s);
|
return($body);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// post request to $url. $params is an array of post variables.
|
// post request to $url. $params is an array of post variables.
|
||||||
|
|
||||||
if(! function_exists('post_url')) {
|
if(! function_exists('post_url')) {
|
||||||
function post_url($url,$params) {
|
function post_url($url,$params, &$redirects = 0) {
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
if(! $ch) return false;
|
if(($redirects > 8) || (! $ch))
|
||||||
|
return false;
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
|
|
||||||
curl_setopt($ch, CURLOPT_MAXREDIRS,8);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
||||||
curl_setopt($ch, CURLOPT_POST,1);
|
curl_setopt($ch, CURLOPT_POST,1);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
|
curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
|
||||||
|
|
||||||
$check_cert = get_config('system','verifyssl');
|
$check_cert = get_config('system','verifyssl');
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
|
||||||
$prx = get_config('system','proxy');
|
$prx = get_config('system','proxy');
|
||||||
|
@ -398,11 +422,26 @@ function post_url($url,$params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$s = curl_exec($ch);
|
$s = curl_exec($ch);
|
||||||
$info = curl_getinfo($ch);
|
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$header = substr($s,0,strpos($s,"\r\n\r\n"));
|
||||||
|
if($http_code == 301 || $http_code == 302 || $http_code == 303) {
|
||||||
|
$matches = array();
|
||||||
|
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
|
||||||
|
$url = trim(array_pop($matches));
|
||||||
|
$url_parsed = parse_url($url);
|
||||||
|
if (isset($url_parsed)) {
|
||||||
|
$redirects++;
|
||||||
|
return post_url($url,$binary,$redirects);
|
||||||
|
}
|
||||||
|
}
|
||||||
$a = get_app();
|
$a = get_app();
|
||||||
$a->set_curl_code($info['http_code']);
|
$a->set_curl_code($http_code);
|
||||||
|
$body = substr($s,strlen($header)+4);
|
||||||
|
$a->set_curl_headers($header);
|
||||||
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return($s);
|
return($body);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// random hash, 64 chars
|
// random hash, 64 chars
|
||||||
|
|
|
@ -62,6 +62,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
|
||||||
`issued-id` char(255) NOT NULL,
|
`issued-id` char(255) NOT NULL,
|
||||||
`dfrn-id` char(255) NOT NULL,
|
`dfrn-id` char(255) NOT NULL,
|
||||||
`url` char(255) NOT NULL,
|
`url` char(255) NOT NULL,
|
||||||
|
`lrdd` char(255) NOT NULL,
|
||||||
`pubkey` text NOT NULL,
|
`pubkey` text NOT NULL,
|
||||||
`prvkey` text NOT NULL,
|
`prvkey` text NOT NULL,
|
||||||
`request` text NOT NULL,
|
`request` text NOT NULL,
|
||||||
|
|
|
@ -139,7 +139,7 @@ function get_feed_for(&$a, $dfrn_id, $owner_id, $last_update, $direction = 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$salmon = '<link rel="salmon" href="' . xmlify($a->get_baseurl() . '/salmon/' . $owner_nick) . '" />' . "\n" ;
|
$salmon = '<link rel="salmon" href="' . xmlify($a->get_baseurl() . '/salmon/' . $owner_nick) . '" />' . "\n" ;
|
||||||
$salmon = ''; // remove this line when salmon handler is finished
|
// $salmon = ''; // remove this line when salmon handler is finished
|
||||||
|
|
||||||
$atom .= replace_macros($feed_template, array(
|
$atom .= replace_macros($feed_template, array(
|
||||||
'$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick),
|
'$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick),
|
||||||
|
|
|
@ -16,3 +16,112 @@ function salmon_key($pubkey) {
|
||||||
|
|
||||||
return 'RSA' . '.' . $m . '.' . $e ;
|
return 'RSA' . '.' . $m . '.' . $e ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function base64url_encode($s) {
|
||||||
|
return strtr(base64_encode($s),'+/','-_');
|
||||||
|
}
|
||||||
|
|
||||||
|
function base64url_decode($s) {
|
||||||
|
return base64_decode(strtr($s,'-_','+/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_salmon_key($uri,$keyhash) {
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
$debugging = get_config('system','debugging');
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetch key' . "\n", FILE_APPEND);
|
||||||
|
|
||||||
|
if(strstr($uri,'@')) {
|
||||||
|
$arr = webfinger($uri);
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetch key from webfinger' . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$html = fetch_url($uri);
|
||||||
|
$a = get_app();
|
||||||
|
$h = $a->get_curl_headers();
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetch key via HTML header: ' . $h . "\n", FILE_APPEND);
|
||||||
|
|
||||||
|
$l = explode("\n",$h);
|
||||||
|
if(count($l)) {
|
||||||
|
foreach($l as $line) {
|
||||||
|
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . $line . "\n", FILE_APPEND);
|
||||||
|
if((stristr($line,'link:')) && preg_match('/<([^>].*)>.*rel\=[\'\"]lrdd[\'\"]/',$line,$matches)) {
|
||||||
|
$link = $matches[1];
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetch key via Link from header: ' . $link . "\n", FILE_APPEND);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! isset($link)) {
|
||||||
|
require_once('library/HTML5/Parser.php');
|
||||||
|
$dom = HTML5_Parser::parse($html);
|
||||||
|
|
||||||
|
if(! $dom)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$items = $dom->getElementsByTagName('link');
|
||||||
|
|
||||||
|
foreach($items as $item) {
|
||||||
|
$x = $item->getAttribute('rel');
|
||||||
|
if($x == "lrdd") {
|
||||||
|
$link = $item->getAttribute('href');
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetch key via HTML body' . $link . "\n", FILE_APPEND);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! isset($link))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$arr = fetch_xrd_links($link);
|
||||||
|
|
||||||
|
if($arr) {
|
||||||
|
foreach($arr as $a) {
|
||||||
|
if($a['@attributes']['rel'] === 'magic-public-key') {
|
||||||
|
$ret[] = $a['@attributes']['href'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(count($ret)) {
|
||||||
|
for($x = 0; $x < count($ret); $x ++) {
|
||||||
|
if(substr($ret[$x],0,5) === 'data:') {
|
||||||
|
if(strstr($ret[$x],','))
|
||||||
|
$ret[$x] = substr($ret[$x],strpos($ret[$x],',')+1);
|
||||||
|
else
|
||||||
|
$ret[$x] = substr($ret[$x],5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$ret[$x] = fetch_url($ret[$x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Key located: ' . print_r($ret,true) . "\n", FILE_APPEND);
|
||||||
|
|
||||||
|
if(count($ret) == 1) {
|
||||||
|
return $ret[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach($ret as $a) {
|
||||||
|
$hash = base64url_encode(hash('sha256',$a));
|
||||||
|
if($hash == $keyhash)
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ class ASN_BASE {
|
||||||
case ASN_BOOLEAN:
|
case ASN_BOOLEAN:
|
||||||
return new ASN_BOOLEAN((bool)$data);
|
return new ASN_BOOLEAN((bool)$data);
|
||||||
case ASN_INTEGER:
|
case ASN_INTEGER:
|
||||||
return new ASN_INTEGER(strtr(base64_encode($data),'+/=','-_,'));
|
return new ASN_INTEGER(strtr(base64_encode($data),'+/','-_'));
|
||||||
// return new ASN_INTEGER(ord($data));
|
// return new ASN_INTEGER(ord($data));
|
||||||
case ASN_BIT_STR:
|
case ASN_BIT_STR:
|
||||||
return new ASN_BIT_STR(self::parseASNString($data, $level+1, $maxLevels));
|
return new ASN_BIT_STR(self::parseASNString($data, $level+1, $maxLevels));
|
||||||
|
|
170
mod/salmon.php
170
mod/salmon.php
|
@ -1,5 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: pass keyhash to key discovery
|
||||||
|
// add relevant contacts so they can use this
|
||||||
|
|
||||||
|
// There is a lot of debug stuff in here because this is quite a
|
||||||
|
// complicated process to try and sort out.
|
||||||
|
|
||||||
|
require_once('include/salmon.php');
|
||||||
|
require_once('simplepie/simplepie.inc');
|
||||||
|
|
||||||
function salmon_return($val) {
|
function salmon_return($val) {
|
||||||
|
|
||||||
if($val >= 500)
|
if($val >= 500)
|
||||||
|
@ -18,7 +28,7 @@ function salmon_post(&$a) {
|
||||||
|
|
||||||
$debugging = get_config('system','debugging');
|
$debugging = get_config('system','debugging');
|
||||||
if($debugging)
|
if($debugging)
|
||||||
file_put_contents('salmon.out',$xml,FILE_APPEND);
|
file_put_contents('salmon.out','New Salmon: ' . $xml . "\n",FILE_APPEND);
|
||||||
|
|
||||||
$nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : '');
|
$nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : '');
|
||||||
$mentions = (($a->argc > 2 && $a->argv[2] === 'mention') ? true : false);
|
$mentions = (($a->argc > 2 && $a->argv[2] === 'mention') ? true : false);
|
||||||
|
@ -31,22 +41,168 @@ function salmon_post(&$a) {
|
||||||
|
|
||||||
$importer = $r[0];
|
$importer = $r[0];
|
||||||
|
|
||||||
require_once('include/items.php');
|
// parse the xml
|
||||||
|
|
||||||
|
$dom = simplexml_load_string($xml,'SimpleXMLElement',0,NAMESPACE_SALMON_ME);
|
||||||
|
|
||||||
|
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . print_r($dom,true) . "\n" , FILE_APPEND);
|
||||||
|
|
||||||
|
// figure out where in the DOM tree our data is hiding
|
||||||
|
|
||||||
|
if($dom->provenance->data)
|
||||||
|
$base = $dom->provenance;
|
||||||
|
elseif($dom->env->data)
|
||||||
|
$base = $dom->env;
|
||||||
|
elseif($dom->data)
|
||||||
|
$base = $dom;
|
||||||
|
|
||||||
|
if(! $base) {
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Unable to find salmon data in XML' . "\n" , FILE_APPEND);
|
||||||
|
salmon_return(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stash the signature away for now. We have to find their key or it won't be good for anything.
|
||||||
|
|
||||||
|
|
||||||
|
$signature = base64url_decode($base->sig);
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Encoded Signature: ' . $base->sig . "\n" , FILE_APPEND);
|
||||||
|
|
||||||
|
// unpack our data element.
|
||||||
|
|
||||||
|
// strip whitespace
|
||||||
|
$data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
|
||||||
|
$type = $base->data[0]->attributes()->type[0];
|
||||||
|
$encoding = $base->encoding;
|
||||||
|
$alg = $base->alg;
|
||||||
|
|
||||||
|
$signed_data = $data;
|
||||||
|
// . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
|
||||||
|
// decode it
|
||||||
|
$data = base64url_decode($data);
|
||||||
|
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Signed data:>>>' . $signed_data . "<<<\n" , FILE_APPEND);
|
||||||
|
|
||||||
|
// Remove the xml declaration
|
||||||
|
$data = preg_replace('/\<\?xml[^\?].*\?\>/','',$data);
|
||||||
|
|
||||||
// Create a fake feed wrapper so simplepie doesn't choke
|
// Create a fake feed wrapper so simplepie doesn't choke
|
||||||
|
|
||||||
$tpl = load_view_file('view/atom_feed.tpl');
|
$tpl = load_view_file('view/fake_feed.tpl');
|
||||||
|
|
||||||
$base = substr($xml,strpos($xml,'<entry'));
|
$base = substr($data,strpos($data,'<entry'));
|
||||||
|
|
||||||
$xml = $tpl . $base . '</feed>';
|
$feedxml = $tpl . $base . '</feed>';
|
||||||
|
|
||||||
salmon_return(500); // until the handler is finished
|
if($debugging) {
|
||||||
|
file_put_contents('salmon.out', 'Processed feed: ' . $feedxml . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
// consume_salmon($xml,$importer);
|
// Now parse it like a normal atom feed to scrape out the author URI
|
||||||
|
|
||||||
|
$feed = new SimplePie();
|
||||||
|
$feed->set_raw_data($feedxml);
|
||||||
|
$feed->enable_order_by_date(false);
|
||||||
|
$feed->init();
|
||||||
|
|
||||||
|
if($debugging) {
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Feed parsed.' . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($feed->get_item_quantity()) {
|
||||||
|
foreach($feed->get_items() as $item) {
|
||||||
|
$author = $item->get_author();
|
||||||
|
$author_link = unxmlify($author->get_link());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! $author_link) {
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . 'Could not retrieve author URI.' . "\n", FILE_APPEND);
|
||||||
|
salmon_return(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we have the author URI, go to the web and find their public key
|
||||||
|
|
||||||
|
if($debugging) {
|
||||||
|
file_put_contents('salmon.out', "\n" . 'Fetching key for ' . $author_link . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = get_salmon_key($author_link,$keyhash);
|
||||||
|
|
||||||
|
if(! $key) {
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . 'Could not retrieve author key.' . "\n", FILE_APPEND);
|
||||||
|
salmon_return(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup RSA stuff to verify the signature
|
||||||
|
|
||||||
|
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpsec');
|
||||||
|
|
||||||
|
require_once('phpsec/Crypt/RSA.php');
|
||||||
|
|
||||||
|
$key_info = explode('.',$key);
|
||||||
|
|
||||||
|
$m = base64url_decode($key_info[1]);
|
||||||
|
$e = base64url_decode($key_info[2]);
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . print_r($key_info,true) . "\n", FILE_APPEND);
|
||||||
|
|
||||||
|
$rsa = new CRYPT_RSA();
|
||||||
|
$rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
|
||||||
|
$rsa->setHash('sha256');
|
||||||
|
|
||||||
|
$rsa->modulus = new Math_BigInteger($m, 256);
|
||||||
|
$rsa->k = strlen($rsa->modulus->toBytes());
|
||||||
|
$rsa->exponent = new Math_BigInteger($e, 256);
|
||||||
|
|
||||||
|
// We should have everything we need now. Let's see if it verifies.
|
||||||
|
|
||||||
|
$verify = $rsa->verify($signed_data,$signature);
|
||||||
|
|
||||||
|
if(! $verify) {
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . 'Message did not verify. Discarding.' . "\n", FILE_APPEND);
|
||||||
|
salmon_return(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . 'Message verified.' . "\n", FILE_APPEND);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
$r = q("SELECT * FROM `contact` WHERE `network` = 'stat' AND `lrdd` = '%s' AND `uid` = %d LIMIT 1",
|
||||||
|
dbesc($author_link),
|
||||||
|
intval($importer['uid'])
|
||||||
|
);
|
||||||
|
if(! count($r)) {
|
||||||
|
if($debugging)
|
||||||
|
file_put_contents('salmon.out',"\n" . 'Author unknown to us.' . "\n", FILE_APPEND);
|
||||||
|
salmon_return(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
require_once('include/items.php');
|
||||||
|
|
||||||
|
$hub = '';
|
||||||
|
|
||||||
|
consume_feed($feedxml,$importer,$r[0],$hub);
|
||||||
|
|
||||||
salmon_return(200);
|
salmon_return(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,3 +76,7 @@ function update_1008() {
|
||||||
function update_1009() {
|
function update_1009() {
|
||||||
q("ALTER TABLE `user` ADD `allow_location` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `default-location` ");
|
q("ALTER TABLE `user` ADD `allow_location` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `default-location` ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function update_1010() {
|
||||||
|
q("ALTER TABLE `contact` ADD `lrdd` CHAR( 255 ) NOT NULL AFTER `url` ");
|
||||||
|
}
|
||||||
|
|
18
view/fake_feed.tpl
Normal file
18
view/fake_feed.tpl
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom"
|
||||||
|
xmlns:thr="http://purl.org/syndication/thread/1.0"
|
||||||
|
xmlns:at="http://purl.org/atompub/tombstones/1.0"
|
||||||
|
xmlns:media="http://purl.org/syndication/atommedia"
|
||||||
|
xmlns:dfrn="http://purl.org/macgirvin/dfrn/1.0"
|
||||||
|
xmlns:as="http://activitystrea.ms/spec/1.0/"
|
||||||
|
xmlns:georss="http://www.georss.org/georss" >
|
||||||
|
|
||||||
|
<id>fake feed</id>
|
||||||
|
<title>fake title</title>
|
||||||
|
|
||||||
|
<updated>1970-01-01T00:00:00Z</updated>
|
||||||
|
|
||||||
|
<author>
|
||||||
|
<name>Fake Name</name>
|
||||||
|
<uri>http://example.com</uri>
|
||||||
|
</author>
|
Loading…
Reference in a new issue