Salmon class, update function name and function calls. Some standards as well.
return $key;
}
-function pubrsatome($key,&$m,&$e) {
- require_once('library/asn1.php');
- require_once('include/salmon.php');
+function pubrsatome($key, &$m, &$e)
+{
+ require_once 'library/asn1.php';
$lines = explode("\n", $key);
unset($lines[0]);
return metorsa($m, $e);
}
-function pemtome($key, &$m, &$e) {
- require_once('include/salmon.php');
+function pemtome($key, &$m, &$e)
+{
$lines = explode("\n", $key);
unset($lines[0]);
unset($lines[count($lines)]);
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
use Friendica\Protocol\PortableContact;
+use Friendica\Protocol\Salmon;
require_once 'include/group.php';
-require_once 'include/salmon.php';
function update_contact($id) {
/*
$item['verb'] = ACTIVITY_FOLLOW;
$item['follow'] = $contact["url"];
$slap = OStatus::salmon($item, $r[0]);
- slapper($r[0], $contact['notify'], $slap);
+ Salmon::slapper($r[0], $contact['notify'], $slap);
}
if ($contact['network'] == NETWORK_DIASPORA) {
require_once 'include/bbcode.php';
require_once 'include/oembed.php';
-require_once 'include/salmon.php';
require_once 'include/crypto.php';
require_once 'include/tags.php';
require_once 'include/files.php';
+++ /dev/null
-<?php
-/**
- * @file include/salmon.php
- */
-use Friendica\Network\Probe;
-use Friendica\Util\XML;
-
-require_once 'include/crypto.php';
-
-function get_salmon_key($uri, $keyhash)
-{
- $ret = array();
-
- logger('Fetching salmon key for '.$uri);
-
- $arr = Probe::lrdd($uri);
-
- if (is_array($arr)) {
- foreach ($arr as $a) {
- if ($a['@attributes']['rel'] === 'magic-public-key') {
- $ret[] = $a['@attributes']['href'];
- }
- }
- } else {
- return '';
- }
-
- // We have found at least one key URL
- // If it's inline, parse it - otherwise get the key
-
- if (count($ret) > 0) {
- 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);
- }
- } elseif (normalise_link($ret[$x]) == 'http://') {
- $ret[$x] = fetch_url($ret[$x]);
- }
- }
- }
-
-
- logger('Key located: ' . print_r($ret, true));
-
- if (count($ret) == 1) {
- // We only found one one key so we don't care if the hash matches.
- // If it's the wrong key we'll find out soon enough because
- // message verification will fail. This also covers some older
- // software which don't supply a keyhash. As long as they only
- // have one key we'll be right.
-
- return $ret[0];
- } else {
- foreach ($ret as $a) {
- $hash = base64url_encode(hash('sha256', $a));
- if ($hash == $keyhash) {
- return $a;
- }
- }
- }
-
- return '';
-}
-
-
-
-function slapper($owner, $url, $slap)
-{
- // does contact have a salmon endpoint?
-
- if (! strlen($url)) {
- return;
- }
-
- if (! $owner['sprvkey']) {
- logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
- $owner['username'], $owner['uid']));
- return;
- }
-
- logger('slapper called for '.$url.'. Data: ' . $slap);
-
- // create a magic envelope
-
- $data = base64url_encode($slap);
- $data_type = 'application/atom+xml';
- $encoding = 'base64url';
- $algorithm = 'RSA-SHA256';
- $keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
-
- $precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
-
- // GNU Social format
- $signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
-
- // Compliant format
- $signature2 = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
-
- // Old Status.net format
- $signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey']));
-
- // At first try the non compliant method that works for GNU Social
- $xmldata = array("me:env" => array("me:data" => $data,
- "@attributes" => array("type" => $data_type),
- "me:encoding" => $encoding,
- "me:alg" => $algorithm,
- "me:sig" => $signature,
- "@attributes2" => array("key_id" => $keyhash)));
-
- $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
-
- $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
-
- // slap them
- post_url($url, $salmon, array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon)
- ));
-
- $a = get_app();
- $return_code = $a->get_curl_code();
-
- // check for success, e.g. 2xx
-
- if ($return_code > 299) {
- logger('GNU Social salmon failed. Falling back to compliant mode');
-
- // Now try the compliant mode that normally isn't used for GNU Social
- $xmldata = array("me:env" => array("me:data" => $data,
- "@attributes" => array("type" => $data_type),
- "me:encoding" => $encoding,
- "me:alg" => $algorithm,
- "me:sig" => $signature2,
- "@attributes2" => array("key_id" => $keyhash)));
-
- $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
-
- $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
-
- // slap them
- post_url($url, $salmon, array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon)
- ));
- $return_code = $a->get_curl_code();
- }
-
- if ($return_code > 299) {
- logger('compliant salmon failed. Falling back to old status.net');
-
- // Last try. This will most likely fail as well.
- $xmldata = array("me:env" => array("me:data" => $data,
- "@attributes" => array("type" => $data_type),
- "me:encoding" => $encoding,
- "me:alg" => $algorithm,
- "me:sig" => $signature3,
- "@attributes2" => array("key_id" => $keyhash)));
-
- $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
-
- $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
-
- // slap them
- post_url($url, $salmon, array(
- 'Content-type: application/magic-envelope+xml',
- 'Content-length: ' . strlen($salmon))
- );
- $return_code = $a->get_curl_code();
- }
-
- logger('slapper for '.$url.' returned ' . $return_code);
-
- if (! $return_code) {
- return -1;
- }
-
- if (($return_code == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
- return -1;
- }
-
- return ((($return_code >= 200) && ($return_code < 300)) ? 0 : 1);
-}
<?php
-
/**
- * Zot endpoint
+ * @file mod/post.php
+ * @brief Zot endpoint
*/
use Friendica\App;
use Friendica\Database\DBM;
+use dba;
-require_once('include/salmon.php');
-require_once('include/crypto.php');
+require_once 'include/crypto.php';
// not yet ready for prime time
//require_once('include/zot.php');
-function post_post(App $a) {
-
+/**
+ * @param object $a App
+ * @return void
+ */
+function post_post(App $a)
+{
$bulk_delivery = false;
if ($a->argc == 1) {
$bulk_delivery = true;
- }
- else {
+ } else {
$nickname = $a->argv[2];
- $r = q("SELECT * FROM `user` WHERE `nickname` = '%s'
- AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1",
- dbesc($nickname)
- );
+ $r = dba::select('user', array(), array('nickname' => $nickname, 'account_expired' => 0, 'account_removed' => 0), array('limit' => 1));
if (! DBM::is_result($r)) {
http_status_exit(500);
}
- $importer = $r[0];
+ $importer = $r;
}
$xml = file_get_contents('php://input');
logger('mod-post: new zot: ' . $xml, LOGGER_DATA);
- if(! $xml)
+ if (! $xml) {
http_status_exit(500);
+ }
- $msg = zot_decode($importer,$xml);
+ $msg = zot_decode($importer, $xml);
- logger('mod-post: decoded msg: ' . print_r($msg,true), LOGGER_DATA);
+ logger('mod-post: decoded msg: ' . print_r($msg, true), LOGGER_DATA);
- if(! is_array($msg))
+ if (! is_array($msg)) {
http_status_exit(500);
+ }
$ret = 0;
- $ret = zot_incoming($bulk_delivery, $importer,$msg);
+ $ret = zot_incoming($bulk_delivery, $importer, $msg);
http_status_exit(($ret) ? $ret : 200);
// NOTREACHED
}
-
<?php
-
/**
- * Diaspora endpoint
+ * @file mod/receive.php
+ * @brief Diaspora endpoint
*/
use Friendica\App;
use Friendica\Database\DBM;
use Friendica\Protocol\Diaspora;
-require_once('include/salmon.php');
-require_once('include/crypto.php');
+require_once 'include/crypto.php';
-function receive_post(App $a) {
+/**
+ * @param object $a App
+ * @return void
+ */
+function receive_post(App $a)
+{
$enabled = intval(Config::get('system', 'diaspora_enabled'));
if (!$enabled) {
logger('mod-diaspora: disabled');
if (!$xml) {
$postdata = file_get_contents("php://input");
- if ($postdata == '') {
+ if ($postdata == '') {
http_status_exit(500);
}
http_status_exit(($ret) ? 200 : 500);
// NOTREACHED
}
-
use Friendica\Core\PConfig;
use Friendica\Database\DBM;
use Friendica\Protocol\OStatus;
+use Friendica\Protocol\Salmon;
-require_once 'include/salmon.php';
require_once 'include/crypto.php';
require_once 'include/items.php';
require_once 'include/follow.php';
logger('mod-salmon: Fetching key for ' . $author_link);
- $key = get_salmon_key($author_link,$keyhash);
+ $key = Salmon::getKey($author_link, $keyhash);
if(! $key) {
logger('mod-salmon: Could not retrieve author key.');
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\OStatus;
+use Friendica\Protocol\Salmon;
use dba;
require_once 'boot.php';
$slap = OStatus::salmon($item, $user);
if ((x($contact, 'notify')) && (strlen($contact['notify']))) {
- require_once 'include/salmon.php';
- slapper($user, $contact['notify'], $slap);
+ Salmon::slapper($user, $contact['notify'], $slap);
}
} elseif ($contact['network'] === NETWORK_DIASPORA) {
Diaspora::sendUnshare($user, $contact);
--- /dev/null
+<?php
+/**
+ * @file src/Protocol/Salmon.php
+ */
+namespace Friendica\Protocol;
+
+use Friendica\Network\Probe;
+use Friendica\Util\XML;
+
+require_once 'include/crypto.php';
+
+/**
+ * @brief Salmon Protocol class
+ * The Salmon Protocol is a message exchange protocol running over HTTP designed to decentralize commentary
+ * and annotations made against newsfeed articles such as blog posts.
+ */
+class Salmon
+{
+ /**
+ * @param string $uri Uniform Resource Identifier
+ * @param string $keyhash encoded key
+ * @return mixed
+ */
+ public static function getKey($uri, $keyhash)
+ {
+ $ret = array();
+
+ logger('Fetching salmon key for '.$uri);
+
+ $arr = Probe::lrdd($uri);
+
+ if (is_array($arr)) {
+ foreach ($arr as $a) {
+ if ($a['@attributes']['rel'] === 'magic-public-key') {
+ $ret[] = $a['@attributes']['href'];
+ }
+ }
+ } else {
+ return '';
+ }
+
+ // We have found at least one key URL
+ // If it's inline, parse it - otherwise get the key
+
+ if (count($ret) > 0) {
+ 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);
+ }
+ } elseif (normalise_link($ret[$x]) == 'http://') {
+ $ret[$x] = fetch_url($ret[$x]);
+ }
+ }
+ }
+
+
+ logger('Key located: ' . print_r($ret, true));
+
+ if (count($ret) == 1) {
+ // We only found one one key so we don't care if the hash matches.
+ // If it's the wrong key we'll find out soon enough because
+ // message verification will fail. This also covers some older
+ // software which don't supply a keyhash. As long as they only
+ // have one key we'll be right.
+
+ return $ret[0];
+ } else {
+ foreach ($ret as $a) {
+ $hash = base64url_encode(hash('sha256', $a));
+ if ($hash == $keyhash) {
+ return $a;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param array $owner owner
+ * @param string $url url
+ * @param string $slap slap
+ * @return integer
+ */
+ public static function slapper($owner, $url, $slap)
+ {
+ // does contact have a salmon endpoint?
+
+ if (! strlen($url)) {
+ return;
+ }
+
+ if (! $owner['sprvkey']) {
+ logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
+ $owner['username'], $owner['uid']));
+ return;
+ }
+
+ logger('slapper called for '.$url.'. Data: ' . $slap);
+
+ // create a magic envelope
+
+ $data = base64url_encode($slap);
+ $data_type = 'application/atom+xml';
+ $encoding = 'base64url';
+ $algorithm = 'RSA-SHA256';
+ $keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
+
+ $precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
+
+ // GNU Social format
+ $signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
+
+ // Compliant format
+ $signature2 = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
+
+ // Old Status.net format
+ $signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey']));
+
+ // At first try the non compliant method that works for GNU Social
+ $xmldata = array("me:env" => array("me:data" => $data,
+ "@attributes" => array("type" => $data_type),
+ "me:encoding" => $encoding,
+ "me:alg" => $algorithm,
+ "me:sig" => $signature,
+ "@attributes2" => array("key_id" => $keyhash)));
+
+ $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
+
+ $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
+
+ // slap them
+ post_url($url, $salmon, array(
+ 'Content-type: application/magic-envelope+xml',
+ 'Content-length: ' . strlen($salmon)
+ ));
+
+ $a = get_app();
+ $return_code = $a->get_curl_code();
+
+ // check for success, e.g. 2xx
+
+ if ($return_code > 299) {
+ logger('GNU Social salmon failed. Falling back to compliant mode');
+
+ // Now try the compliant mode that normally isn't used for GNU Social
+ $xmldata = array("me:env" => array("me:data" => $data,
+ "@attributes" => array("type" => $data_type),
+ "me:encoding" => $encoding,
+ "me:alg" => $algorithm,
+ "me:sig" => $signature2,
+ "@attributes2" => array("key_id" => $keyhash)));
+
+ $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
+
+ $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
+
+ // slap them
+ post_url($url, $salmon, array(
+ 'Content-type: application/magic-envelope+xml',
+ 'Content-length: ' . strlen($salmon)
+ ));
+ $return_code = $a->get_curl_code();
+ }
+
+ if ($return_code > 299) {
+ logger('compliant salmon failed. Falling back to old status.net');
+
+ // Last try. This will most likely fail as well.
+ $xmldata = array("me:env" => array("me:data" => $data,
+ "@attributes" => array("type" => $data_type),
+ "me:encoding" => $encoding,
+ "me:alg" => $algorithm,
+ "me:sig" => $signature3,
+ "@attributes2" => array("key_id" => $keyhash)));
+
+ $namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
+
+ $salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
+
+ // slap them
+ post_url($url, $salmon, array(
+ 'Content-type: application/magic-envelope+xml',
+ 'Content-length: ' . strlen($salmon))
+ );
+ $return_code = $a->get_curl_code();
+ }
+
+ logger('slapper for '.$url.' returned ' . $return_code);
+
+ if (! $return_code) {
+ return -1;
+ }
+
+ if (($return_code == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
+ return -1;
+ }
+
+ return (($return_code >= 200) && ($return_code < 300)) ? 0 : 1;
+ }
+}
use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
+use Friendica\Protocol\Salmon;
use dba;
require_once 'include/queue_fn.php';
require_once 'include/html2plain.php';
-require_once 'include/salmon.php';
require_once 'include/datetime.php';
require_once 'include/items.php';
require_once 'include/bbcode.php';
// They are especially used for notifications to OStatus users that don't follow us.
if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) {
- if (!Config::get('system','dfrn_only')) {
+ if (!Config::get('system', 'dfrn_only')) {
foreach ($url_recipients as $url) {
if ($url) {
logger('notifier: urldelivery: ' . $url);
- $deliver_status = slapper($owner,$url,$slap);
+ $deliver_status = Salmon::slapper($owner, $url, $slap);
/// @TODO Redeliver/queue these items on failure, though there is no contact record
}
}
<?php
-
/**
* @file src/Worker/Queue.php
*/
-
namespace Friendica\Worker;
use Friendica\Core\Cache;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\PortableContact;
+use Friendica\Protocol\Salmon;
use dba;
require_once 'include/queue_fn.php';
require_once 'include/datetime.php';
require_once 'include/items.php';
require_once 'include/bbcode.php';
-require_once 'include/salmon.php';
class Queue
{
case NETWORK_OSTATUS:
if ($contact['notify']) {
logger('queue: slapdelivery: item ' . $q_item['id'] . ' for ' . $contact['name'] . ' <' . $contact['url'] . '>');
- $deliver_status = slapper($owner, $contact['notify'], $data);
+ $deliver_status = Salmon::slapper($owner, $contact['notify'], $data);
if ($deliver_status == (-1)) {
update_queue_time($q_item['id']);