forked from GNUsocial/gnu-social
Merge branch 'nightly' of git.gnu.io:gnu/gnu-social into nightly
This commit is contained in:
commit
28eb441812
@ -65,6 +65,15 @@ class TagprofileAction extends FormAction
|
|||||||
return sprintf(_m('ADDTOLIST','List %s'), $this->target->getNickname());
|
return sprintf(_m('ADDTOLIST','List %s'), $this->target->getNickname());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
// Only serve page content if we aren't POSTing via ajax
|
||||||
|
// otherwise, we serve XML content from doPost()
|
||||||
|
if (!$this->isPost() || !$this->boolean('ajax')) {
|
||||||
|
parent::showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->elementStart('div', 'entity_profile h-card');
|
$this->elementStart('div', 'entity_profile h-card');
|
||||||
|
65
plugins/Diaspora/DiasporaPlugin.php
Normal file
65
plugins/Diaspora/DiasporaPlugin.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* GNU Social - a federating social network
|
||||||
|
* Copyright (C) 2015, Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diaspora federation protocol plugin for GNU Social
|
||||||
|
*
|
||||||
|
* Depends on:
|
||||||
|
* - OStatus plugin
|
||||||
|
* - WebFinger plugin
|
||||||
|
*
|
||||||
|
* @package ProtocolDiasporaPlugin
|
||||||
|
* @maintainer Mikael Nordfeldth <mmn@hethane.se>
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DiasporaPlugin extends Plugin
|
||||||
|
{
|
||||||
|
const REL_SEED_LOCATION = 'http://joindiaspora.com/seed_location';
|
||||||
|
const REL_GUID = 'http://joindiaspora.com/guid';
|
||||||
|
const REL_PUBLIC_KEY = 'diaspora-public-key';
|
||||||
|
|
||||||
|
public function onEndAttachPubkeyToUserXRD(Magicsig $magicsig, XML_XRD $xrd, Profile $target)
|
||||||
|
{
|
||||||
|
// So far we've only handled RSA keys, but it can change in the future,
|
||||||
|
// so be prepared. And remember to change the statically assigned type attribute below!
|
||||||
|
assert($magicsig->publicKey instanceof Crypt_RSA);
|
||||||
|
$xrd->links[] = new XML_XRD_Element_Link(self::REL_PUBLIC_KEY,
|
||||||
|
base64_encode($magicsig->exportPublicKey()), 'RSA');
|
||||||
|
|
||||||
|
// Instead of choosing a random string, we calculate our GUID from the public key
|
||||||
|
// by fingerprint through a sha256 hash.
|
||||||
|
$xrd->links[] = new XML_XRD_Element_Link(self::REL_GUID,
|
||||||
|
strtolower($magicsig->toFingerprint()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onPluginVersion(array &$versions)
|
||||||
|
{
|
||||||
|
$versions[] = array('name' => 'Diaspora',
|
||||||
|
'version' => '0.1',
|
||||||
|
'author' => 'Mikael Nordfeldth',
|
||||||
|
'homepage' => 'https://gnu.io/social',
|
||||||
|
// TRANS: Plugin description.
|
||||||
|
'rawdescription' => _m('Follow people across social networks that implement '.
|
||||||
|
'the <a href="https://diasporafoundation.org/">Diaspora</a> federation protocol.'));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
7
plugins/OStatus/EVENTS.txt
Normal file
7
plugins/OStatus/EVENTS.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
StartAttachPubkeyToUserXRD: Runs only for XRD generation where a Magicsig exists for a Profile which is a "person".
|
||||||
|
@param Magicsig $magicsig crypto stuff related to the profile we're representing
|
||||||
|
@param XRD $xrd the XRD object which holds all data for the profile we're representing
|
||||||
|
|
||||||
|
EndAttachPubkeyToUserXRD: Runs only for XRD generation where a Magicsig exists for a Profile which is a "person". And only if StartAttachPubkeyToUserXRD didn't abort.
|
||||||
|
@param Magicsig $magicsig crypto stuff related to the profile we're representing
|
||||||
|
@param XRD $xrd the XRD object which holds all data for the profile we're representing
|
@ -30,19 +30,6 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
|
|
||||||
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/phpseclib');
|
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/phpseclib');
|
||||||
|
|
||||||
class FeedSubException extends Exception
|
|
||||||
{
|
|
||||||
function __construct($msg=null)
|
|
||||||
{
|
|
||||||
$type = get_class($this);
|
|
||||||
if ($msg) {
|
|
||||||
parent::__construct("$type: $msg");
|
|
||||||
} else {
|
|
||||||
parent::__construct($type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OStatusPlugin extends Plugin
|
class OStatusPlugin extends Plugin
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -1315,11 +1302,14 @@ class OStatusPlugin extends Plugin
|
|||||||
$magicsig = Magicsig::generate($target->getUser());
|
$magicsig = Magicsig::generate($target->getUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($magicsig instanceof Magicsig) {
|
if (!$magicsig instanceof Magicsig) {
|
||||||
|
return false; // value doesn't mean anything, just figured I'd indicate this function didn't do anything
|
||||||
|
}
|
||||||
|
if (Event::handle('StartAttachPubkeyToUserXRD', array($magicsig, $xrd, $target))) {
|
||||||
$xrd->links[] = new XML_XRD_Element_Link(Magicsig::PUBLICKEYREL,
|
$xrd->links[] = new XML_XRD_Element_Link(Magicsig::PUBLICKEYREL,
|
||||||
'data:application/magic-public-key,'. $magicsig->toString());
|
'data:application/magic-public-key,'. $magicsig->toString());
|
||||||
$xrd->links[] = new XML_XRD_Element_Link(Magicsig::DIASPORA_PUBLICKEYREL,
|
// The following event handles plugins like Diaspora which add their own version of the Magicsig pubkey
|
||||||
base64_encode($magicsig->exportPublicKey()));
|
Event::handle('EndAttachPubkeyToUserXRD', array($magicsig, $xrd, $target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ require_once 'Crypt/RSA.php';
|
|||||||
class Magicsig extends Managed_DataObject
|
class Magicsig extends Managed_DataObject
|
||||||
{
|
{
|
||||||
const PUBLICKEYREL = 'magic-public-key';
|
const PUBLICKEYREL = 'magic-public-key';
|
||||||
const DIASPORA_PUBLICKEYREL = 'diaspora-public-key';
|
|
||||||
|
|
||||||
const DEFAULT_KEYLEN = 1024;
|
const DEFAULT_KEYLEN = 1024;
|
||||||
const DEFAULT_SIGALG = 'RSA-SHA256';
|
const DEFAULT_SIGALG = 'RSA-SHA256';
|
||||||
@ -179,18 +178,31 @@ class Magicsig extends Managed_DataObject
|
|||||||
* @param boolean $full_pair set to true to include the private key.
|
* @param boolean $full_pair set to true to include the private key.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function toString($full_pair=false)
|
public function toString($full_pair=false, $base64url=true)
|
||||||
{
|
{
|
||||||
$mod = Magicsig::base64_url_encode($this->publicKey->modulus->toBytes());
|
$base64_func = $base64url ? 'Magicsig::base64_url_encode' : 'base64_encode';
|
||||||
$exp = Magicsig::base64_url_encode($this->publicKey->exponent->toBytes());
|
$mod = call_user_func($base64_func, $this->publicKey->modulus->toBytes());
|
||||||
|
$exp = call_user_func($base64_func, $this->publicKey->exponent->toBytes());
|
||||||
|
|
||||||
$private_exp = '';
|
$private_exp = '';
|
||||||
if ($full_pair && $this->privateKey instanceof Crypt_RSA && $this->privateKey->exponent->toBytes()) {
|
if ($full_pair && $this->privateKey instanceof Crypt_RSA && $this->privateKey->exponent->toBytes()) {
|
||||||
$private_exp = '.' . Magicsig::base64_url_encode($this->privateKey->exponent->toBytes());
|
$private_exp = '.' . call_user_func($base64_func, $this->privateKey->exponent->toBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'RSA.' . $mod . '.' . $exp . $private_exp;
|
return 'RSA.' . $mod . '.' . $exp . $private_exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toFingerprint()
|
||||||
|
{
|
||||||
|
// This assumes a specific behaviour from toString, to format as such:
|
||||||
|
// "RSA." + base64(pubkey.modulus_as_bytes) + "." + base64(pubkey.exponent_as_bytes)
|
||||||
|
// We don't want the base64 string to be the "url encoding" version because it is not
|
||||||
|
// as common in programming libraries. And we want it to be base64 encoded since ASCII
|
||||||
|
// representation avoids any problems with NULL etc. in less forgiving languages and also
|
||||||
|
// just easier to debug...
|
||||||
|
return strtolower(hash('sha256', $this->toString(false, false)));
|
||||||
|
}
|
||||||
|
|
||||||
public function exportPublicKey($format=CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
public function exportPublicKey($format=CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
||||||
{
|
{
|
||||||
$this->publicKey->setPublicKey();
|
$this->publicKey->setPublicKey();
|
||||||
|
@ -17,13 +17,12 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package OStatusPlugin
|
* @package OStatusPlugin
|
||||||
* @maintainer Brion Vibber <brion@status.net>
|
* @author Brion Vibber <brion@status.net>
|
||||||
|
* @maintainer Mikael Nordfeldth <mmn@hethane.se>
|
||||||
*/
|
*/
|
||||||
class Ostatus_profile extends Managed_DataObject
|
class Ostatus_profile extends Managed_DataObject
|
||||||
{
|
{
|
||||||
@ -1746,11 +1745,8 @@ class Ostatus_profile extends Managed_DataObject
|
|||||||
throw new Exception(_m('Not a valid webfinger address.'));
|
throw new Exception(_m('Not a valid webfinger address.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$hints = array('webfinger' => $addr);
|
$hints = array_merge(array('webfinger' => $addr),
|
||||||
|
DiscoveryHints::fromXRD($xrd));
|
||||||
$dhints = DiscoveryHints::fromXRD($xrd);
|
|
||||||
|
|
||||||
$hints = array_merge($hints, $dhints);
|
|
||||||
|
|
||||||
// If there's an Hcard, let's grab its info
|
// If there's an Hcard, let's grab its info
|
||||||
if (array_key_exists('hcard', $hints)) {
|
if (array_key_exists('hcard', $hints)) {
|
||||||
|
13
plugins/OStatus/lib/feedsubexception.php
Normal file
13
plugins/OStatus/lib/feedsubexception.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
class FeedSubException extends Exception
|
||||||
|
{
|
||||||
|
function __construct($msg=null)
|
||||||
|
{
|
||||||
|
$type = get_class($this);
|
||||||
|
if ($msg) {
|
||||||
|
parent::__construct("$type: $msg");
|
||||||
|
} else {
|
||||||
|
parent::__construct($type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -71,7 +71,19 @@ class Salmon
|
|||||||
common_log(LOG_ERR, "Salmon post to $endpoint_uri failed: " . $e->getMessage());
|
common_log(LOG_ERR, "Salmon post to $endpoint_uri failed: " . $e->getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($response->getStatus() != 200) {
|
|
||||||
|
// Diaspora wants a slightly different formatting on the POST (other Content-type, so body needs "xml=")
|
||||||
|
if ($response->getStatus() === 422) {
|
||||||
|
common_debug(sprintf('Salmon (from profile %d) endpoint %s returned status %s. Diaspora? Will try again! Body: %s',
|
||||||
|
$user->id, $endpoint_uri, $response->getStatus(), $response->getBody()));
|
||||||
|
$headers = array('Content-Type: application/x-www-form-urlencoded');
|
||||||
|
$client->setBody('xml=' . Magicsig::base64_url_encode($envxml));
|
||||||
|
$response = $client->post($endpoint_uri, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 200 OK is the best response
|
||||||
|
// 202 Accepted is what we get from Diaspora for example
|
||||||
|
if (!in_array($response->getStatus(), array(200, 202))) {
|
||||||
common_log(LOG_ERR, sprintf('Salmon (from profile %d) endpoint %s returned status %s: %s',
|
common_log(LOG_ERR, sprintf('Salmon (from profile %d) endpoint %s returned status %s: %s',
|
||||||
$user->id, $endpoint_uri, $response->getStatus(), $response->getBody()));
|
$user->id, $endpoint_uri, $response->getStatus(), $response->getBody()));
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,13 +41,27 @@ class SalmonAction extends Action
|
|||||||
|
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
if (!isset($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
|
if (!isset($_SERVER['CONTENT_TYPE'])) {
|
||||||
// TRANS: Client error. Do not translate "application/magic-envelope+xml".
|
// TRANS: Client error. Do not translate "Content-type"
|
||||||
$this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
|
$this->clientError(_m('Salmon requires a Content-type header.'));
|
||||||
|
}
|
||||||
|
$envxml = null;
|
||||||
|
switch ($_SERVER['CONTENT_TYPE']) {
|
||||||
|
case 'application/magic-envelope+xml':
|
||||||
|
$envxml = file_get_contents('php://input');
|
||||||
|
break;
|
||||||
|
case 'application/x-www-form-urlencoded':
|
||||||
|
$envxml = Magicsig::base64_url_decode($this->trimmed('xml'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TRANS: Client error. Do not translate the quoted "application/[type]" strings.
|
||||||
|
$this->clientError(_m('Salmon requires "application/magic-envelope+xml". For Diaspora we also accept "application/x-www-form-urlencoded" with an "xml" parameter.', 415));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$envxml = file_get_contents('php://input');
|
if (empty($envxml)) {
|
||||||
|
throw new ClientException('No magic envelope supplied in POST.');
|
||||||
|
}
|
||||||
$magic_env = new MagicEnvelope($envxml); // parse incoming XML as a MagicEnvelope
|
$magic_env = new MagicEnvelope($envxml); // parse incoming XML as a MagicEnvelope
|
||||||
|
|
||||||
$entry = $magic_env->getPayload(); // Not cryptographically verified yet!
|
$entry = $magic_env->getPayload(); // Not cryptographically verified yet!
|
||||||
|
@ -54,10 +54,28 @@ print "\n";
|
|||||||
print "Re-running feed discovery for profile URL $oprofile->uri\n";
|
print "Re-running feed discovery for profile URL $oprofile->uri\n";
|
||||||
// @fixme will bork where the URI isn't the profile URL for now
|
// @fixme will bork where the URI isn't the profile URL for now
|
||||||
$discover = new FeedDiscovery();
|
$discover = new FeedDiscovery();
|
||||||
$feedurl = $discover->discoverFromURL($oprofile->uri);
|
try {
|
||||||
|
$feedurl = $discover->discoverFromURL($oprofile->uri);
|
||||||
|
$salmonuri = $discover->getAtomLink(Salmon::REL_SALMON)
|
||||||
|
?: $discover->getAtomLink(Salmon::NS_REPLIES); // NS_REPLIES is deprecated
|
||||||
|
} catch (FeedSubException $e) {
|
||||||
|
$acct = $oprofile->localProfile()->getAcctUri();
|
||||||
|
print "Could not discover feeds HTML response, trying reconstructed acct URI: " . $acct;
|
||||||
|
$disco = new Discovery();
|
||||||
|
$xrd = $disco->lookup($acct);
|
||||||
|
$hints = DiscoveryHints::fromXRD($xrd);
|
||||||
|
|
||||||
|
if (!array_key_exists('feedurl', $hints)) {
|
||||||
|
throw new FeedSubNoFeedException($acct);
|
||||||
|
}
|
||||||
|
$feedurl = $hints['feedurl'];
|
||||||
|
$salmonuri = array_key_exists('salmon', $hints) ? $hints['salmon'] : null;
|
||||||
|
|
||||||
|
// get the hub data too and put it in the FeedDiscovery object
|
||||||
|
$discover->discoverFromFeedUrl($feedurl);
|
||||||
|
}
|
||||||
|
|
||||||
$huburi = $discover->getHubLink();
|
$huburi = $discover->getHubLink();
|
||||||
$salmonuri = $discover->getAtomLink(Salmon::REL_SALMON)
|
|
||||||
?: $discover->getAtomLink(Salmon::NS_REPLIES);
|
|
||||||
|
|
||||||
print " Feed URL: $feedurl\n";
|
print " Feed URL: $feedurl\n";
|
||||||
print " Hub URL: $huburi\n";
|
print " Hub URL: $huburi\n";
|
||||||
|
Loading…
Reference in New Issue
Block a user