From 3cd438c4e3450ce00deeae5be3821c20b1377aee Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 30 Apr 2019 22:22:36 +0200 Subject: [PATCH 01/12] Move mod/hostxrd to src/Module/Hostxrd --- mod/_well_known.php | 3 ++- mod/hostxrd.php | 34 --------------------------- src/Module/Hostxrd.php | 52 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 35 deletions(-) delete mode 100644 mod/hostxrd.php create mode 100644 src/Module/Hostxrd.php diff --git a/mod/_well_known.php b/mod/_well_known.php index 8e82dabef..d861b2780 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -3,6 +3,7 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\System; +use Friendica\Module\Hostxrd; use Friendica\Module\Nodeinfo; require_once 'mod/hostxrd.php'; @@ -13,7 +14,7 @@ function _well_known_init(App $a) if ($a->argc > 1) { switch ($a->argv[1]) { case "host-meta": - hostxrd_init($a); + Hostxrd::printHostMeta(); break; case "x-social-relay": wk_social_relay(); diff --git a/mod/hostxrd.php b/mod/hostxrd.php deleted file mode 100644 index 93a9d833c..000000000 --- a/mod/hostxrd.php +++ /dev/null @@ -1,34 +0,0 @@ - $a->getHostName(), - '$zroot' => System::baseUrl(), - '$domain' => System::baseUrl(), - '$bigkey' => Salmon::salmonKey(Config::get('system', 'site_pubkey'))] - ); - - exit(); -} diff --git a/src/Module/Hostxrd.php b/src/Module/Hostxrd.php new file mode 100644 index 000000000..75997c86b --- /dev/null +++ b/src/Module/Hostxrd.php @@ -0,0 +1,52 @@ +getConfig(); + + header("Content-type: text/xml"); + $pubkey = $config->get('system', 'site_pubkey'); + + if (!$pubkey) { + $res = Crypto::newKeypair(1024); + + $config->set('system','site_prvkey', $res['prvkey']); + $config->set('system','site_pubkey', $res['pubkey']); + } + + $tpl = Renderer::getMarkupTemplate('xrd_host.tpl'); + echo Renderer::replaceMacros($tpl, [ + '$zhost' => $app->getHostName(), + '$zroot' => $app->getBaseURL(), + '$domain' => $app->getBaseURL(), + '$bigkey' => Salmon::salmonKey($config->get('system', 'site_pubkey'))] + ); + + exit(); + } +} From 6afeacf02bd1db21b683c0a01d6472cac23cb3a9 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 30 Apr 2019 22:25:06 +0200 Subject: [PATCH 02/12] remove require_once --- mod/_well_known.php | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/_well_known.php b/mod/_well_known.php index d861b2780..3dbac799f 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -6,7 +6,6 @@ use Friendica\Core\System; use Friendica\Module\Hostxrd; use Friendica\Module\Nodeinfo; -require_once 'mod/hostxrd.php'; require_once 'mod/xrd.php'; function _well_known_init(App $a) From 007d0459beb5a1a071e9d400fd43e1aa8552fd2f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 30 Apr 2019 22:25:38 +0200 Subject: [PATCH 03/12] optimize check --- src/Module/Hostxrd.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Module/Hostxrd.php b/src/Module/Hostxrd.php index 75997c86b..4f95ebb45 100644 --- a/src/Module/Hostxrd.php +++ b/src/Module/Hostxrd.php @@ -30,9 +30,8 @@ class Hostxrd extends BaseModule $config = $app->getConfig(); header("Content-type: text/xml"); - $pubkey = $config->get('system', 'site_pubkey'); - if (!$pubkey) { + if (!$config->get('system', 'site_pubkey', false)) { $res = Crypto::newKeypair(1024); $config->set('system','site_prvkey', $res['prvkey']); From e7f8d8c3b640c7729adec105ed6ce97829539389 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 30 Apr 2019 22:36:28 +0200 Subject: [PATCH 04/12] Adding to router --- mod/_well_known.php | 4 ++-- src/App/Router.php | 2 ++ src/Module/{Hostxrd.php => HostMeta.php} | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) rename src/Module/{Hostxrd.php => HostMeta.php} (96%) diff --git a/mod/_well_known.php b/mod/_well_known.php index 3dbac799f..3bd86ecc9 100644 --- a/mod/_well_known.php +++ b/mod/_well_known.php @@ -3,7 +3,7 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\System; -use Friendica\Module\Hostxrd; +use Friendica\Module\HostMeta; use Friendica\Module\Nodeinfo; require_once 'mod/xrd.php'; @@ -13,7 +13,7 @@ function _well_known_init(App $a) if ($a->argc > 1) { switch ($a->argv[1]) { case "host-meta": - Hostxrd::printHostMeta(); + HostMeta::printHostMeta(); break; case "x-social-relay": wk_social_relay(); diff --git a/src/App/Router.php b/src/App/Router.php index 039d3e2cf..53fe0689a 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -42,6 +42,8 @@ class Router { $this->routeCollector->addRoute(['GET', 'POST'], '/itemsource[/{guid}]', Module\Itemsource::class); $this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class); + $this->routeCollector->addRoute(['GET'], '/host-meta', Module\HostMeta::class); + $this->routeCollector->addRoute(['GET'], '/hostxrd', Module\HostMeta::class); } public function __construct(RouteCollector $routeCollector = null) diff --git a/src/Module/Hostxrd.php b/src/Module/HostMeta.php similarity index 96% rename from src/Module/Hostxrd.php rename to src/Module/HostMeta.php index 4f95ebb45..21953b541 100644 --- a/src/Module/Hostxrd.php +++ b/src/Module/HostMeta.php @@ -10,7 +10,7 @@ use Friendica\Util\Crypto; /** * Prints the host-meta text */ -class Hostxrd extends BaseModule +class HostMeta extends BaseModule { public static function rawContent() { From 90248f6bb7227d0de15085a53bb6108f1e5a91ec Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 00:14:06 +0200 Subject: [PATCH 05/12] Move .well-known, webfinger, xrd to src/Module/ --- mod/_well_known.php | 82 -------- mod/webfinger.php | 42 ---- mod/xrd.php | 134 ------------ src/App/Router.php | 8 + src/Model/Search.php | 32 +++ src/Model/User.php | 16 +- src/Module/{Nodeinfo.php => NodeInfo.php} | 7 +- src/Module/WebFinger.php | 235 ++++++++++++++++++++++ src/Module/{ => WellKnown}/HostMeta.php | 15 +- src/Module/WellKnown/XSocialRelay.php | 62 ++++++ 10 files changed, 358 insertions(+), 275 deletions(-) delete mode 100644 mod/_well_known.php delete mode 100644 mod/webfinger.php delete mode 100644 mod/xrd.php create mode 100644 src/Model/Search.php rename src/Module/{Nodeinfo.php => NodeInfo.php} (95%) create mode 100644 src/Module/WebFinger.php rename src/Module/{ => WellKnown}/HostMeta.php (76%) create mode 100644 src/Module/WellKnown/XSocialRelay.php diff --git a/mod/_well_known.php b/mod/_well_known.php deleted file mode 100644 index 3bd86ecc9..000000000 --- a/mod/_well_known.php +++ /dev/null @@ -1,82 +0,0 @@ -argc > 1) { - switch ($a->argv[1]) { - case "host-meta": - HostMeta::printHostMeta(); - break; - case "x-social-relay": - wk_social_relay(); - break; - case "nodeinfo": - Nodeinfo::printWellKnown($a); - break; - case "webfinger": - xrd_init($a); - break; - } - } - System::httpExit(404); -} - -function wk_social_relay() -{ - $subscribe = (bool) Config::get('system', 'relay_subscribe', false); - - if ($subscribe) { - $scope = Config::get('system', 'relay_scope', SR_SCOPE_ALL); - } else { - $scope = SR_SCOPE_NONE; - } - - $tags = []; - - if ($scope == SR_SCOPE_TAGS) { - $server_tags = Config::get('system', 'relay_server_tags'); - $tagitems = explode(",", $server_tags); - - /// @todo Check if it was better to use "strtolower" on the tags - foreach ($tagitems AS $tag) { - $tag = trim($tag, "# "); - $tags[$tag] = $tag; - } - - if (Config::get('system', 'relay_user_tags')) { - $terms = q("SELECT DISTINCT(`term`) FROM `search`"); - - foreach ($terms AS $term) { - $tag = trim($term["term"], "#"); - $tags[$tag] = $tag; - } - } - } - - $taglist = []; - foreach ($tags AS $tag) { - if (!empty($tag)) { - $taglist[] = $tag; - } - } - - $relay = [ - 'subscribe' => $subscribe, - 'scope' => $scope, - 'tags' => $taglist, - 'protocols' => ['diaspora' => ['receive' => System::baseUrl() . '/receive/public'], - 'dfrn' => ['receive' => System::baseUrl() . '/dfrn_notify']] - ]; - - header('Content-type: application/json; charset=utf-8'); - echo json_encode($relay, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - exit; -} diff --git a/mod/webfinger.php b/mod/webfinger.php deleted file mode 100644 index b22b1ee64..000000000 --- a/mod/webfinger.php +++ /dev/null @@ -1,42 +0,0 @@ - L10n::t("Public access denied."), - "description" => L10n::t("Only logged in users are permitted to perform a probing.") - ] - ); - exit(); - } - - $o = '
'; - $o .= '

Webfinger Diagnostic

'; - - $o .= '
'; - $o .= 'Lookup address: '; - $o .= '
'; - - $o .= '

'; - - if (!empty($_GET['addr'])) { - $addr = trim($_GET['addr']); - $res = Probe::lrdd($addr); - $o .= '
';
-		$o .= str_replace("\n", '
', print_r($res, true)); - $o .= '
'; - } - $o .= '
'; - - return $o; -} diff --git a/mod/xrd.php b/mod/xrd.php deleted file mode 100644 index b4cb60afe..000000000 --- a/mod/xrd.php +++ /dev/null @@ -1,134 +0,0 @@ -argv[0] == 'xrd') { - if (empty($_GET['uri'])) { - System::httpExit(404); - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { - $mode = 'json'; - } else { - $mode = 'xml'; - } - } else { - if (empty($_GET['resource'])) { - System::httpExit(404); - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { - $mode = 'xml'; - } else { - $mode = 'json'; - } - } - - if (substr($uri, 0, 4) === 'http') { - $name = ltrim(basename($uri), '~'); - } else { - $local = str_replace('acct:', '', $uri); - if (substr($local, 0, 2) == '//') { - $local = substr($local, 2); - } - - $name = substr($local, 0, strpos($local, '@')); - } - - $user = DBA::selectFirst('user', [], ['nickname' => $name]); - if (!DBA::isResult($user)) { - System::httpExit(404); - } - - $profile_url = System::baseUrl().'/profile/'.$user['nickname']; - - $alias = str_replace('/profile/', '/~', $profile_url); - - $addr = 'acct:'.$user['nickname'].'@'.$a->getHostName(); - if ($a->getURLPath()) { - $addr .= '/'.$a->getURLPath(); - } - - if ($mode == 'xml') { - xrd_xml($addr, $alias, $profile_url, $user); - } else { - xrd_json($addr, $alias, $profile_url, $user); - } -} - -function xrd_json($uri, $alias, $profile_url, $r) -{ - $salmon_key = Salmon::salmonKey($r['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: application/json; charset=utf-8"); - - $json = ['subject' => $uri, - 'aliases' => [$alias, $profile_url], - 'links' => [ - ['rel' => NAMESPACE_DFRN, 'href' => $profile_url], - ['rel' => NAMESPACE_FEED, 'type' => 'application/atom+xml', 'href' => System::baseUrl().'/dfrn_poll/'.$r['nickname']], - ['rel' => 'http://webfinger.net/rel/profile-page', 'type' => 'text/html', 'href' => $profile_url], - ['rel' => 'self', 'type' => 'application/activity+json', 'href' => $profile_url], - ['rel' => 'http://microformats.org/profile/hcard', 'type' => 'text/html', 'href' => System::baseUrl().'/hcard/'.$r['nickname']], - ['rel' => NAMESPACE_POCO, 'href' => System::baseUrl().'/poco/'.$r['nickname']], - ['rel' => 'http://webfinger.net/rel/avatar', 'type' => 'image/jpeg', 'href' => System::baseUrl().'/photo/profile/'.$r['uid'].'.jpg'], - ['rel' => 'http://joindiaspora.com/seed_location', 'type' => 'text/html', 'href' => System::baseUrl()], - ['rel' => 'salmon', 'href' => System::baseUrl().'/salmon/'.$r['nickname']], - ['rel' => 'http://salmon-protocol.org/ns/salmon-replies', 'href' => System::baseUrl().'/salmon/'.$r['nickname']], - ['rel' => 'http://salmon-protocol.org/ns/salmon-mention', 'href' => System::baseUrl().'/salmon/'.$r['nickname'].'/mention'], - ['rel' => 'http://ostatus.org/schema/1.0/subscribe', 'template' => System::baseUrl().'/follow?url={uri}'], - ['rel' => 'magic-public-key', 'href' => 'data:application/magic-public-key,'.$salmon_key], - ['rel' => 'http://purl.org/openwebauth/v1', 'type' => 'application/x-zot+json', 'href' => System::baseUrl().'/owa'] - ] - ]; - - echo json_encode($json); - exit(); -} - -function xrd_xml($uri, $alias, $profile_url, $r) -{ - $salmon_key = Salmon::salmonKey($r['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: text/xml"); - - $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); - - $o = Renderer::replaceMacros($tpl, [ - '$nick' => $r['nickname'], - '$accturi' => $uri, - '$alias' => $alias, - '$profile_url' => $profile_url, - '$hcard_url' => System::baseUrl() . '/hcard/' . $r['nickname'], - '$atom' => System::baseUrl() . '/dfrn_poll/' . $r['nickname'], - '$poco_url' => System::baseUrl() . '/poco/' . $r['nickname'], - '$photo' => System::baseUrl() . '/photo/profile/' . $r['uid'] . '.jpg', - '$baseurl' => System::baseUrl(), - '$salmon' => System::baseUrl() . '/salmon/' . $r['nickname'], - '$salmen' => System::baseUrl() . '/salmon/' . $r['nickname'] . '/mention', - '$subscribe' => System::baseUrl() . '/follow?url={uri}', - '$openwebauth' => System::baseUrl() . '/owa', - '$modexp' => 'data:application/magic-public-key,' . $salmon_key] - ); - - $arr = ['user' => $r, 'xml' => $o]; - Hook::callAll('personal_xrd', $arr); - - echo $arr['xml']; - exit(); -} diff --git a/src/App/Router.php b/src/App/Router.php index 53fe0689a..c17398977 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -44,6 +44,14 @@ class Router $this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class); $this->routeCollector->addRoute(['GET'], '/host-meta', Module\HostMeta::class); $this->routeCollector->addRoute(['GET'], '/hostxrd', Module\HostMeta::class); + $this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class); + $this->routeCollector->addRoute(['GET'], '/xrd', Module\WebFinger::class); + $this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { + $collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class); + $collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class); + $collector->addRoute(['GET'], '/webfinger[/xrd]' , Module\WebFinger::class); + $collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class); + }); } public function __construct(RouteCollector $routeCollector = null) diff --git a/src/Model/Search.php b/src/Model/Search.php new file mode 100644 index 000000000..5829ff91d --- /dev/null +++ b/src/Model/Search.php @@ -0,0 +1,32 @@ + $uid]); + return DBA::selectFirst('user', $fields, ['uid' => $uid]); + } + + /** + * @param string $nickname + * @param array $fields + * @return array|boolean User record if it exists, false otherwise + * @throws Exception + */ + public static function getByNickname($nickname, array $fields = []) + { + return DBA::selectFirst('user', $fields, ['nickname' => $nickname]); } /** diff --git a/src/Module/Nodeinfo.php b/src/Module/NodeInfo.php similarity index 95% rename from src/Module/Nodeinfo.php rename to src/Module/NodeInfo.php index 18f2c7280..7fad79fd3 100644 --- a/src/Module/Nodeinfo.php +++ b/src/Module/NodeInfo.php @@ -8,9 +8,10 @@ use Friendica\Core\Addon; use Friendica\Core\System; /** - * Prints infos about the current node + * Standardized way of exposing metadata about a server running one of the distributed social networks. + * @see https://github.com/jhass/nodeinfo/blob/master/PROTOCOL.md */ -class Nodeinfo extends BaseModule +class NodeInfo extends BaseModule { /** * Prints the Nodeinfo for a well-known request @@ -48,7 +49,7 @@ class Nodeinfo extends BaseModule } if (($app->argc != 2) || ($app->argv[1] != '1.0')) { - System::httpExit(404); + self::printWellKnown($app); } } diff --git a/src/Module/WebFinger.php b/src/Module/WebFinger.php new file mode 100644 index 000000000..d456c6aac --- /dev/null +++ b/src/Module/WebFinger.php @@ -0,0 +1,235 @@ + L10n::t("Public access denied."), + "description" => L10n::t("Only logged in users are permitted to perform a probing.") + ] + ); + exit(); + } + + $output = '
'; + $output .= '

Webfinger Diagnostic

'; + + $output .= '
'; + $output .= 'Lookup address: '; + $output .= '
'; + + $output .= '

'; + + if (!empty($_GET['addr'])) { + $addr = trim($_GET['addr']); + $res = Probe::lrdd($addr); + $output .= '
';
+			$output .= str_replace("\n", '
', print_r($res, true)); + $output .= '
'; + } + $output .= '
'; + + return $output; + } + + public static function rawContent() + { + parent::rawContent(); + + $app = self::getApp(); + + // @TODO: Replace with parameter from router + if ($app->argv[0] == 'xrd') { + if (empty($_GET['uri'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { + $mode = 'json'; + } else { + $mode = 'xml'; + } + } else { + if (empty($_GET['resource'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { + $mode = 'xml'; + } else { + $mode = 'json'; + } + } + + if (substr($uri, 0, 4) === 'http') { + $name = ltrim(basename($uri), '~'); + } else { + $local = str_replace('acct:', '', $uri); + if (substr($local, 0, 2) == '//') { + $local = substr($local, 2); + } + + $name = substr($local, 0, strpos($local, '@')); + } + + $user = User::getByNickname($name); + + if (empty($user)) { + System::httpExit(404); + } + + $profileURL = $app->getBaseURL() . '/profile/' . $user['nickname']; + $alias = str_replace('/profile/', '/~', $profileURL); + + $addr = 'acct:' . $user['nickname'] . '@' . $app->getHostName(); + if ($app->getURLPath()) { + $addr .= '/' . $app->getURLPath(); + } + + if ($mode == 'xml') { + self::printXML($addr, $alias, $profileURL, $app->getBaseURL(), $user); + } else { + self::printJSON($addr, $alias, $profileURL, $app->getBaseURL(), $user); + } + } + + private static function printJSON($uri, $alias, $orofileURL, $baseURL, $user) + { + $salmon_key = Salmon::salmonKey($user['spubkey']); + + header('Access-Control-Allow-Origin: *'); + header("Content-type: application/json; charset=utf-8"); + + $json = ['subject' => $uri, + 'aliases' => [ + $alias, + $orofileURL, + ], + 'links' => [ + [ + 'rel' => NAMESPACE_DFRN, + 'href' => $orofileURL, + ], + [ + 'rel' => NAMESPACE_FEED, + 'type' => 'application/atom+xml', + 'href' => $baseURL . '/dfrn_poll/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/profile-page', + 'type' => 'text/html', + 'href' => $orofileURL, + ], + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => $orofileURL, + ], + [ + 'rel' => 'http://microformats.org/profile/hcard', + 'type' => 'text/html', + 'href' => $baseURL . '/hcard/' . $user['nickname'], + ], + [ + 'rel' => NAMESPACE_POCO, + 'href' => $baseURL . '/poco/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/avatar', + 'type' => 'image/jpeg', + 'href' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + ], + [ + 'rel' => 'http://joindiaspora.com/seed_location', + 'type' => 'text/html', + 'href' => $baseURL, + ], + [ + 'rel' => 'salmon', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-replies', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-mention', + 'href' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => $baseURL . '/follow?url={uri}', + ], + [ + 'rel' => 'magic-public-key', + 'href' => 'data:application/magic-public-key,' . $salmon_key, + ], + [ + 'rel' => 'http://purl.org/openwebauth/v1', + 'type' => 'application/x-zot+json', + 'href' => $baseURL . '/owa', + ], + ], + ]; + + echo json_encode($json); + exit(); + } + + private static function printXML($uri, $alias, $profileURL, $baseURL, $user) + { + $salmon_key = Salmon::salmonKey($user['spubkey']); + + header('Access-Control-Allow-Origin: *'); + header("Content-type: text/xml"); + + $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); + + $o = Renderer::replaceMacros($tpl, [ + '$nick' => $user['nickname'], + '$accturi' => $uri, + '$alias' => $alias, + '$profile_url' => $profileURL, + '$hcard_url' => $baseURL . '/hcard/' . $user['nickname'], + '$atom' => $baseURL . '/dfrn_poll/' . $user['nickname'], + '$poco_url' => $baseURL . '/poco/' . $user['nickname'], + '$photo' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + '$baseurl' => $baseURL, + '$salmon' => $baseURL . '/salmon/' . $user['nickname'], + '$salmen' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + '$subscribe' => $baseURL . '/follow?url={uri}', + '$openwebauth' => $baseURL . '/owa', + '$modexp' => 'data:application/magic-public-key,' . $salmon_key] + ); + + $arr = ['user' => $user, 'xml' => $o]; + Hook::callAll('personal_xrd', $arr); + + echo $arr['xml']; + exit(); + } +} diff --git a/src/Module/HostMeta.php b/src/Module/WellKnown/HostMeta.php similarity index 76% rename from src/Module/HostMeta.php rename to src/Module/WellKnown/HostMeta.php index 21953b541..282781adf 100644 --- a/src/Module/HostMeta.php +++ b/src/Module/WellKnown/HostMeta.php @@ -1,6 +1,6 @@ getConfig(); diff --git a/src/Module/WellKnown/XSocialRelay.php b/src/Module/WellKnown/XSocialRelay.php new file mode 100644 index 000000000..5766a8ce5 --- /dev/null +++ b/src/Module/WellKnown/XSocialRelay.php @@ -0,0 +1,62 @@ +getConfig(); + + $subscribe = $config->get('system', 'relay_subscribe', false); + + if ($subscribe) { + $scope = $config->get('system', 'relay_scope', SR_SCOPE_ALL); + } else { + $scope = SR_SCOPE_NONE; + } + + $systemTags = []; + $userTags = []; + + if ($scope == SR_SCOPE_TAGS) { + $server_tags = $config->get('system', 'relay_server_tags'); + $tagitems = explode(",", $server_tags); + + /// @todo Check if it was better to use "strtolower" on the tags + foreach ($tagitems AS $tag) { + $systemTags[] = trim($tag, "# "); + } + + if ($config->get('system', 'relay_user_tags')) { + $userTags = Search::getUserTags(); + } + } + + $tagList = array_unique(array_merge($systemTags, $userTags)); + + $relay = [ + 'subscribe' => $subscribe, + 'scope' => $scope, + 'tags' => $tagList, + 'protocols' => ['diaspora' => + ['receive' => $app->getBaseURL() . '/receive/public'], + 'dfrn' => + ['receive' => $app->getBaseURL() . '/dfrn_notify']] + ]; + + header('Content-type: application/json; charset=utf-8'); + echo json_encode($relay, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + exit; + } +} From 48d388d82c316bfd490490d6a9a12e28cc455272 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 00:15:22 +0200 Subject: [PATCH 06/12] fix route --- src/App/Router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/Router.php b/src/App/Router.php index c17398977..d16cc5b44 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -49,7 +49,7 @@ class Router $this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class); $collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class); - $collector->addRoute(['GET'], '/webfinger[/xrd]' , Module\WebFinger::class); + $collector->addRoute(['GET'], '/webfinger' , Module\WebFinger::class); $collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class); }); } From 8581fbb40ff8c2aef0122aa9e60ec8c5425442b5 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 18:24:09 +0200 Subject: [PATCH 07/12] refactor caused by feedback --- src/App/Router.php | 4 +- src/Module/WebFinger.php | 235 -------------------------- src/Module/WellKnown/HostMeta.php | 2 - src/Module/WellKnown/WebFinger.php | 196 +++++++++++++++++++++ src/Module/WellKnown/XSocialRelay.php | 2 - src/Module/Xrd.php | 43 +++++ view/templates/xrd.tpl | 16 ++ 7 files changed, 257 insertions(+), 241 deletions(-) delete mode 100644 src/Module/WebFinger.php create mode 100644 src/Module/WellKnown/WebFinger.php create mode 100644 src/Module/Xrd.php create mode 100644 view/templates/xrd.tpl diff --git a/src/App/Router.php b/src/App/Router.php index d16cc5b44..b904de64b 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -45,11 +45,11 @@ class Router $this->routeCollector->addRoute(['GET'], '/host-meta', Module\HostMeta::class); $this->routeCollector->addRoute(['GET'], '/hostxrd', Module\HostMeta::class); $this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class); - $this->routeCollector->addRoute(['GET'], '/xrd', Module\WebFinger::class); + $this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class); $this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class); $collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class); - $collector->addRoute(['GET'], '/webfinger' , Module\WebFinger::class); + $collector->addRoute(['GET'], '/webfinger' , Module\WellKnown\WebFinger::class); $collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class); }); } diff --git a/src/Module/WebFinger.php b/src/Module/WebFinger.php deleted file mode 100644 index d456c6aac..000000000 --- a/src/Module/WebFinger.php +++ /dev/null @@ -1,235 +0,0 @@ - L10n::t("Public access denied."), - "description" => L10n::t("Only logged in users are permitted to perform a probing.") - ] - ); - exit(); - } - - $output = '
'; - $output .= '

Webfinger Diagnostic

'; - - $output .= '
'; - $output .= 'Lookup address: '; - $output .= '
'; - - $output .= '

'; - - if (!empty($_GET['addr'])) { - $addr = trim($_GET['addr']); - $res = Probe::lrdd($addr); - $output .= '
';
-			$output .= str_replace("\n", '
', print_r($res, true)); - $output .= '
'; - } - $output .= '
'; - - return $output; - } - - public static function rawContent() - { - parent::rawContent(); - - $app = self::getApp(); - - // @TODO: Replace with parameter from router - if ($app->argv[0] == 'xrd') { - if (empty($_GET['uri'])) { - return; - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { - $mode = 'json'; - } else { - $mode = 'xml'; - } - } else { - if (empty($_GET['resource'])) { - return; - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { - $mode = 'xml'; - } else { - $mode = 'json'; - } - } - - if (substr($uri, 0, 4) === 'http') { - $name = ltrim(basename($uri), '~'); - } else { - $local = str_replace('acct:', '', $uri); - if (substr($local, 0, 2) == '//') { - $local = substr($local, 2); - } - - $name = substr($local, 0, strpos($local, '@')); - } - - $user = User::getByNickname($name); - - if (empty($user)) { - System::httpExit(404); - } - - $profileURL = $app->getBaseURL() . '/profile/' . $user['nickname']; - $alias = str_replace('/profile/', '/~', $profileURL); - - $addr = 'acct:' . $user['nickname'] . '@' . $app->getHostName(); - if ($app->getURLPath()) { - $addr .= '/' . $app->getURLPath(); - } - - if ($mode == 'xml') { - self::printXML($addr, $alias, $profileURL, $app->getBaseURL(), $user); - } else { - self::printJSON($addr, $alias, $profileURL, $app->getBaseURL(), $user); - } - } - - private static function printJSON($uri, $alias, $orofileURL, $baseURL, $user) - { - $salmon_key = Salmon::salmonKey($user['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: application/json; charset=utf-8"); - - $json = ['subject' => $uri, - 'aliases' => [ - $alias, - $orofileURL, - ], - 'links' => [ - [ - 'rel' => NAMESPACE_DFRN, - 'href' => $orofileURL, - ], - [ - 'rel' => NAMESPACE_FEED, - 'type' => 'application/atom+xml', - 'href' => $baseURL . '/dfrn_poll/' . $user['nickname'], - ], - [ - 'rel' => 'http://webfinger.net/rel/profile-page', - 'type' => 'text/html', - 'href' => $orofileURL, - ], - [ - 'rel' => 'self', - 'type' => 'application/activity+json', - 'href' => $orofileURL, - ], - [ - 'rel' => 'http://microformats.org/profile/hcard', - 'type' => 'text/html', - 'href' => $baseURL . '/hcard/' . $user['nickname'], - ], - [ - 'rel' => NAMESPACE_POCO, - 'href' => $baseURL . '/poco/' . $user['nickname'], - ], - [ - 'rel' => 'http://webfinger.net/rel/avatar', - 'type' => 'image/jpeg', - 'href' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', - ], - [ - 'rel' => 'http://joindiaspora.com/seed_location', - 'type' => 'text/html', - 'href' => $baseURL, - ], - [ - 'rel' => 'salmon', - 'href' => $baseURL . '/salmon/' . $user['nickname'], - ], - [ - 'rel' => 'http://salmon-protocol.org/ns/salmon-replies', - 'href' => $baseURL . '/salmon/' . $user['nickname'], - ], - [ - 'rel' => 'http://salmon-protocol.org/ns/salmon-mention', - 'href' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', - ], - [ - 'rel' => 'http://ostatus.org/schema/1.0/subscribe', - 'template' => $baseURL . '/follow?url={uri}', - ], - [ - 'rel' => 'magic-public-key', - 'href' => 'data:application/magic-public-key,' . $salmon_key, - ], - [ - 'rel' => 'http://purl.org/openwebauth/v1', - 'type' => 'application/x-zot+json', - 'href' => $baseURL . '/owa', - ], - ], - ]; - - echo json_encode($json); - exit(); - } - - private static function printXML($uri, $alias, $profileURL, $baseURL, $user) - { - $salmon_key = Salmon::salmonKey($user['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: text/xml"); - - $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); - - $o = Renderer::replaceMacros($tpl, [ - '$nick' => $user['nickname'], - '$accturi' => $uri, - '$alias' => $alias, - '$profile_url' => $profileURL, - '$hcard_url' => $baseURL . '/hcard/' . $user['nickname'], - '$atom' => $baseURL . '/dfrn_poll/' . $user['nickname'], - '$poco_url' => $baseURL . '/poco/' . $user['nickname'], - '$photo' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', - '$baseurl' => $baseURL, - '$salmon' => $baseURL . '/salmon/' . $user['nickname'], - '$salmen' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', - '$subscribe' => $baseURL . '/follow?url={uri}', - '$openwebauth' => $baseURL . '/owa', - '$modexp' => 'data:application/magic-public-key,' . $salmon_key] - ); - - $arr = ['user' => $user, 'xml' => $o]; - Hook::callAll('personal_xrd', $arr); - - echo $arr['xml']; - exit(); - } -} diff --git a/src/Module/WellKnown/HostMeta.php b/src/Module/WellKnown/HostMeta.php index 282781adf..aad56293d 100644 --- a/src/Module/WellKnown/HostMeta.php +++ b/src/Module/WellKnown/HostMeta.php @@ -15,8 +15,6 @@ class HostMeta extends BaseModule { public static function rawContent() { - parent::rawContent(); - $app = self::getApp(); $config = $app->getConfig(); diff --git a/src/Module/WellKnown/WebFinger.php b/src/Module/WellKnown/WebFinger.php new file mode 100644 index 000000000..d9a143a7a --- /dev/null +++ b/src/Module/WellKnown/WebFinger.php @@ -0,0 +1,196 @@ +argv[0] == 'xrd') { + if (empty($_GET['uri'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { + $mode = 'json'; + } else { + $mode = 'xml'; + } + } else { + if (empty($_GET['resource'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { + $mode = 'xml'; + } else { + $mode = 'json'; + } + } + + if (substr($uri, 0, 4) === 'http') { + $name = ltrim(basename($uri), '~'); + } else { + $local = str_replace('acct:', '', $uri); + if (substr($local, 0, 2) == '//') { + $local = substr($local, 2); + } + + $name = substr($local, 0, strpos($local, '@')); + } + + $user = User::getByNickname($name); + + if (empty($user)) { + System::httpExit(404); + } + + $profileURL = $app->getBaseURL() . '/profile/' . $user['nickname']; + $alias = str_replace('/profile/', '/~', $profileURL); + + $addr = 'acct:' . $user['nickname'] . '@' . $app->getHostName(); + if ($app->getURLPath()) { + $addr .= '/' . $app->getURLPath(); + } + + if ($mode == 'xml') { + self::printXML($addr, $alias, $profileURL, $app->getBaseURL(), $user); + } else { + self::printJSON($addr, $alias, $profileURL, $app->getBaseURL(), $user); + } + } + + private static function printJSON($uri, $alias, $orofileURL, $baseURL, $user) + { + $salmon_key = Salmon::salmonKey($user['spubkey']); + + header('Access-Control-Allow-Origin: *'); + header("Content-type: application/json; charset=utf-8"); + + $json = [ + 'subject' => $uri, + 'aliases' => [ + $alias, + $orofileURL, + ], + 'links' => [ + [ + 'rel' => NAMESPACE_DFRN, + 'href' => $orofileURL, + ], + [ + 'rel' => NAMESPACE_FEED, + 'type' => 'application/atom+xml', + 'href' => $baseURL . '/dfrn_poll/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/profile-page', + 'type' => 'text/html', + 'href' => $orofileURL, + ], + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => $orofileURL, + ], + [ + 'rel' => 'http://microformats.org/profile/hcard', + 'type' => 'text/html', + 'href' => $baseURL . '/hcard/' . $user['nickname'], + ], + [ + 'rel' => NAMESPACE_POCO, + 'href' => $baseURL . '/poco/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/avatar', + 'type' => 'image/jpeg', + 'href' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + ], + [ + 'rel' => 'http://joindiaspora.com/seed_location', + 'type' => 'text/html', + 'href' => $baseURL, + ], + [ + 'rel' => 'salmon', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-replies', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-mention', + 'href' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => $baseURL . '/follow?url={uri}', + ], + [ + 'rel' => 'magic-public-key', + 'href' => 'data:application/magic-public-key,' . $salmon_key, + ], + [ + 'rel' => 'http://purl.org/openwebauth/v1', + 'type' => 'application/x-zot+json', + 'href' => $baseURL . '/owa', + ], + ], + ]; + + echo json_encode($json); + exit(); + } + + private static function printXML($uri, $alias, $profileURL, $baseURL, $user) + { + $salmon_key = Salmon::salmonKey($user['spubkey']); + + header('Access-Control-Allow-Origin: *'); + header("Content-type: text/xml"); + + $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); + + $o = Renderer::replaceMacros($tpl, [ + '$nick' => $user['nickname'], + '$accturi' => $uri, + '$alias' => $alias, + '$profile_url' => $profileURL, + '$hcard_url' => $baseURL . '/hcard/' . $user['nickname'], + '$atom' => $baseURL . '/dfrn_poll/' . $user['nickname'], + '$poco_url' => $baseURL . '/poco/' . $user['nickname'], + '$photo' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + '$baseurl' => $baseURL, + '$salmon' => $baseURL . '/salmon/' . $user['nickname'], + '$salmen' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + '$subscribe' => $baseURL . '/follow?url={uri}', + '$openwebauth' => $baseURL . '/owa', + '$modexp' => 'data:application/magic-public-key,' . $salmon_key + ]); + + $arr = ['user' => $user, 'xml' => $o]; + Hook::callAll('personal_xrd', $arr); + + echo $arr['xml']; + exit(); + } +} diff --git a/src/Module/WellKnown/XSocialRelay.php b/src/Module/WellKnown/XSocialRelay.php index 5766a8ce5..da3533fee 100644 --- a/src/Module/WellKnown/XSocialRelay.php +++ b/src/Module/WellKnown/XSocialRelay.php @@ -13,8 +13,6 @@ class XSocialRelay extends BaseModule { public static function rawContent() { - parent::rawContent(); - $app = self::getApp(); $config = $app->getConfig(); diff --git a/src/Module/Xrd.php b/src/Module/Xrd.php new file mode 100644 index 000000000..1251e6e28 --- /dev/null +++ b/src/Module/Xrd.php @@ -0,0 +1,43 @@ + L10n::t("Public access denied."), + "description" => L10n::t("Only logged in users are permitted to perform a probing.") + ] + ); + exit(); + } + } + + public static function content() + { + $addr = defaults($_GET, 'addr', ''); + $res = ''; + + if (!empty($addr)) { + $res = Probe::lrdd($addr); + $res = str_replace("\n", '
', print_r($res, true)); + } + + $tpl = Renderer::getMarkupTemplate("xrd.tpl"); + return Renderer::replaceMacros($tpl, [ + '$addr' => $addr, + '$res' => $res, + ]); + } +} diff --git a/view/templates/xrd.tpl b/view/templates/xrd.tpl new file mode 100644 index 000000000..c9c2e48a1 --- /dev/null +++ b/view/templates/xrd.tpl @@ -0,0 +1,16 @@ +
+

Webfinger Diagnostic

+ +
+ Lookup address: + +
+ +

+ + {{if $res}} +
+		{{$res}}
+	
+ {{/if}} +
From 6a52d79a84cb438f4b473a792f884fd6a320b8c6 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 18:25:28 +0200 Subject: [PATCH 08/12] refactor caused by feedback --- src/App/Router.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/App/Router.php b/src/App/Router.php index b904de64b..67b1e828a 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -42,8 +42,6 @@ class Router { $this->routeCollector->addRoute(['GET', 'POST'], '/itemsource[/{guid}]', Module\Itemsource::class); $this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class); - $this->routeCollector->addRoute(['GET'], '/host-meta', Module\HostMeta::class); - $this->routeCollector->addRoute(['GET'], '/hostxrd', Module\HostMeta::class); $this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class); $this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class); $this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { From 0345c50e2db5509f3913d1d15d6726bb051049da Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 18:42:44 +0200 Subject: [PATCH 09/12] refactor Nodeinfo for more strait implementation --- src/Module/NodeInfo.php | 48 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/Module/NodeInfo.php b/src/Module/NodeInfo.php index 7fad79fd3..c8d75b8e1 100644 --- a/src/Module/NodeInfo.php +++ b/src/Module/NodeInfo.php @@ -13,14 +13,37 @@ use Friendica\Core\System; */ class NodeInfo extends BaseModule { + public static function init() + { + $config = self::getApp()->getConfig(); + + if (!$config->get('system', 'nodeinfo')) { + System::httpExit(404); + } + } + + public static function rawContent() + { + $app = self::getApp(); + + // @TODO: Replace with parameter from router + // if the first argument is ".well-known", print the well-known text + if (($app->argc > 1) && ($app->argv[0] == '.well-known')) { + self::printWellKnown($app); + // otherwise print the nodeinfo + } else { + self::printNodeInfo($app); + } + } + /** - * Prints the Nodeinfo for a well-known request + * Prints the well-known nodeinfo redirect * * @param App $app * * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function printWellKnown(App $app) + private static function printWellKnown(App $app) { $config = $app->getConfig(); @@ -39,24 +62,15 @@ class NodeInfo extends BaseModule exit; } - public static function init() + /** + * Print the nodeinfo + * + * @param App $app + */ + private static function printNodeInfo(App $app) { - $app = self::getApp(); $config = $app->getConfig(); - if (!$config->get('system', 'nodeinfo')) { - System::httpExit(404); - } - - if (($app->argc != 2) || ($app->argv[1] != '1.0')) { - self::printWellKnown($app); - } - } - - public static function rawContent() - { - $config = self::getApp()->getConfig(); - $smtp = (function_exists('imap_open') && !$config->get('system', 'imap_disabled') && !$config->get('system', 'dfrn_only')); $nodeinfo = [ From 2ae4b9f7e9f29e54c03557205677a1576917fc26 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 19:17:52 +0200 Subject: [PATCH 10/12] Last refactoring :-) / refactor due feedback --- src/App/Router.php | 3 +- src/Module/WebFinger.php | 48 ++++++ src/Module/WellKnown/HostMeta.php | 16 +- src/Module/WellKnown/WebFinger.php | 196 --------------------- src/Module/WellKnown/XSocialRelay.php | 14 +- src/Module/Xrd.php | 198 +++++++++++++++++++--- view/templates/{xrd.tpl => webfinger.tpl} | 2 +- 7 files changed, 243 insertions(+), 234 deletions(-) create mode 100644 src/Module/WebFinger.php delete mode 100644 src/Module/WellKnown/WebFinger.php rename view/templates/{xrd.tpl => webfinger.tpl} (88%) diff --git a/src/App/Router.php b/src/App/Router.php index 67b1e828a..96923289c 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -43,11 +43,12 @@ class Router $this->routeCollector->addRoute(['GET', 'POST'], '/itemsource[/{guid}]', Module\Itemsource::class); $this->routeCollector->addRoute(['GET'], '/amcd', Module\AccountManagementControlDocument::class); $this->routeCollector->addRoute(['GET'], '/nodeinfo/1.0', Module\NodeInfo::class); + $this->routeCollector->addRoute(['GET'], '/webfinger', Module\WebFinger::class); $this->routeCollector->addRoute(['GET'], '/xrd', Module\Xrd::class); $this->routeCollector->addGroup('/.well-known', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/host-meta' , Module\WellKnown\HostMeta::class); $collector->addRoute(['GET'], '/nodeinfo[/1.0]' , Module\NodeInfo::class); - $collector->addRoute(['GET'], '/webfinger' , Module\WellKnown\WebFinger::class); + $collector->addRoute(['GET'], '/webfinger' , Module\Xrd::class); $collector->addRoute(['GET'], '/x-social-relay' , Module\WellKnown\XSocialRelay::class); }); } diff --git a/src/Module/WebFinger.php b/src/Module/WebFinger.php new file mode 100644 index 000000000..66280dce1 --- /dev/null +++ b/src/Module/WebFinger.php @@ -0,0 +1,48 @@ + L10n::t("Public access denied."), + "description" => L10n::t("Only logged in users are permitted to perform a probing.") + ] + ); + exit(); + } + } + + public static function content() + { + $app = self::getApp(); + + $addr = defaults($_GET, 'addr', ''); + $res = ''; + + if (!empty($addr)) { + $res = Probe::lrdd($addr); + $res = print_r($res, true); + } + + $tpl = Renderer::getMarkupTemplate('webfinger.tpl'); + return Renderer::replaceMacros($tpl, [ + '$addr' => $addr, + '$res' => $res, + ]); + } +} diff --git a/src/Module/WellKnown/HostMeta.php b/src/Module/WellKnown/HostMeta.php index aad56293d..fd04467f7 100644 --- a/src/Module/WellKnown/HostMeta.php +++ b/src/Module/WellKnown/HostMeta.php @@ -18,22 +18,22 @@ class HostMeta extends BaseModule $app = self::getApp(); $config = $app->getConfig(); - header("Content-type: text/xml"); + header('Content-type: text/xml'); if (!$config->get('system', 'site_pubkey', false)) { $res = Crypto::newKeypair(1024); - $config->set('system','site_prvkey', $res['prvkey']); - $config->set('system','site_pubkey', $res['pubkey']); + $config->set('system', 'site_prvkey', $res['prvkey']); + $config->set('system', 'site_pubkey', $res['pubkey']); } $tpl = Renderer::getMarkupTemplate('xrd_host.tpl'); echo Renderer::replaceMacros($tpl, [ - '$zhost' => $app->getHostName(), - '$zroot' => $app->getBaseURL(), - '$domain' => $app->getBaseURL(), - '$bigkey' => Salmon::salmonKey($config->get('system', 'site_pubkey'))] - ); + '$zhost' => $app->getHostName(), + '$zroot' => $app->getBaseURL(), + '$domain' => $app->getBaseURL(), + '$bigkey' => Salmon::salmonKey($config->get('system', 'site_pubkey')) + ]); exit(); } diff --git a/src/Module/WellKnown/WebFinger.php b/src/Module/WellKnown/WebFinger.php deleted file mode 100644 index d9a143a7a..000000000 --- a/src/Module/WellKnown/WebFinger.php +++ /dev/null @@ -1,196 +0,0 @@ -argv[0] == 'xrd') { - if (empty($_GET['uri'])) { - return; - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { - $mode = 'json'; - } else { - $mode = 'xml'; - } - } else { - if (empty($_GET['resource'])) { - return; - } - - $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); - if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { - $mode = 'xml'; - } else { - $mode = 'json'; - } - } - - if (substr($uri, 0, 4) === 'http') { - $name = ltrim(basename($uri), '~'); - } else { - $local = str_replace('acct:', '', $uri); - if (substr($local, 0, 2) == '//') { - $local = substr($local, 2); - } - - $name = substr($local, 0, strpos($local, '@')); - } - - $user = User::getByNickname($name); - - if (empty($user)) { - System::httpExit(404); - } - - $profileURL = $app->getBaseURL() . '/profile/' . $user['nickname']; - $alias = str_replace('/profile/', '/~', $profileURL); - - $addr = 'acct:' . $user['nickname'] . '@' . $app->getHostName(); - if ($app->getURLPath()) { - $addr .= '/' . $app->getURLPath(); - } - - if ($mode == 'xml') { - self::printXML($addr, $alias, $profileURL, $app->getBaseURL(), $user); - } else { - self::printJSON($addr, $alias, $profileURL, $app->getBaseURL(), $user); - } - } - - private static function printJSON($uri, $alias, $orofileURL, $baseURL, $user) - { - $salmon_key = Salmon::salmonKey($user['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: application/json; charset=utf-8"); - - $json = [ - 'subject' => $uri, - 'aliases' => [ - $alias, - $orofileURL, - ], - 'links' => [ - [ - 'rel' => NAMESPACE_DFRN, - 'href' => $orofileURL, - ], - [ - 'rel' => NAMESPACE_FEED, - 'type' => 'application/atom+xml', - 'href' => $baseURL . '/dfrn_poll/' . $user['nickname'], - ], - [ - 'rel' => 'http://webfinger.net/rel/profile-page', - 'type' => 'text/html', - 'href' => $orofileURL, - ], - [ - 'rel' => 'self', - 'type' => 'application/activity+json', - 'href' => $orofileURL, - ], - [ - 'rel' => 'http://microformats.org/profile/hcard', - 'type' => 'text/html', - 'href' => $baseURL . '/hcard/' . $user['nickname'], - ], - [ - 'rel' => NAMESPACE_POCO, - 'href' => $baseURL . '/poco/' . $user['nickname'], - ], - [ - 'rel' => 'http://webfinger.net/rel/avatar', - 'type' => 'image/jpeg', - 'href' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', - ], - [ - 'rel' => 'http://joindiaspora.com/seed_location', - 'type' => 'text/html', - 'href' => $baseURL, - ], - [ - 'rel' => 'salmon', - 'href' => $baseURL . '/salmon/' . $user['nickname'], - ], - [ - 'rel' => 'http://salmon-protocol.org/ns/salmon-replies', - 'href' => $baseURL . '/salmon/' . $user['nickname'], - ], - [ - 'rel' => 'http://salmon-protocol.org/ns/salmon-mention', - 'href' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', - ], - [ - 'rel' => 'http://ostatus.org/schema/1.0/subscribe', - 'template' => $baseURL . '/follow?url={uri}', - ], - [ - 'rel' => 'magic-public-key', - 'href' => 'data:application/magic-public-key,' . $salmon_key, - ], - [ - 'rel' => 'http://purl.org/openwebauth/v1', - 'type' => 'application/x-zot+json', - 'href' => $baseURL . '/owa', - ], - ], - ]; - - echo json_encode($json); - exit(); - } - - private static function printXML($uri, $alias, $profileURL, $baseURL, $user) - { - $salmon_key = Salmon::salmonKey($user['spubkey']); - - header('Access-Control-Allow-Origin: *'); - header("Content-type: text/xml"); - - $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); - - $o = Renderer::replaceMacros($tpl, [ - '$nick' => $user['nickname'], - '$accturi' => $uri, - '$alias' => $alias, - '$profile_url' => $profileURL, - '$hcard_url' => $baseURL . '/hcard/' . $user['nickname'], - '$atom' => $baseURL . '/dfrn_poll/' . $user['nickname'], - '$poco_url' => $baseURL . '/poco/' . $user['nickname'], - '$photo' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', - '$baseurl' => $baseURL, - '$salmon' => $baseURL . '/salmon/' . $user['nickname'], - '$salmen' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', - '$subscribe' => $baseURL . '/follow?url={uri}', - '$openwebauth' => $baseURL . '/owa', - '$modexp' => 'data:application/magic-public-key,' . $salmon_key - ]); - - $arr = ['user' => $user, 'xml' => $o]; - Hook::callAll('personal_xrd', $arr); - - echo $arr['xml']; - exit(); - } -} diff --git a/src/Module/WellKnown/XSocialRelay.php b/src/Module/WellKnown/XSocialRelay.php index da3533fee..33e58d0c5 100644 --- a/src/Module/WellKnown/XSocialRelay.php +++ b/src/Module/WellKnown/XSocialRelay.php @@ -29,7 +29,7 @@ class XSocialRelay extends BaseModule if ($scope == SR_SCOPE_TAGS) { $server_tags = $config->get('system', 'relay_server_tags'); - $tagitems = explode(",", $server_tags); + $tagitems = explode(',', $server_tags); /// @todo Check if it was better to use "strtolower" on the tags foreach ($tagitems AS $tag) { @@ -47,10 +47,14 @@ class XSocialRelay extends BaseModule 'subscribe' => $subscribe, 'scope' => $scope, 'tags' => $tagList, - 'protocols' => ['diaspora' => - ['receive' => $app->getBaseURL() . '/receive/public'], - 'dfrn' => - ['receive' => $app->getBaseURL() . '/dfrn_notify']] + 'protocols' => [ + 'diaspora' => [ + 'receive' => $app->getBaseURL() . '/receive/public' + ], + 'dfrn' => [ + 'receive' => $app->getBaseURL() . '/dfrn_notify' + ] + ] ]; header('Content-type: application/json; charset=utf-8'); diff --git a/src/Module/Xrd.php b/src/Module/Xrd.php index 1251e6e28..38ce151ff 100644 --- a/src/Module/Xrd.php +++ b/src/Module/Xrd.php @@ -3,41 +3,193 @@ namespace Friendica\Module; use Friendica\BaseModule; -use Friendica\Core\L10n; +use Friendica\Core\Hook; use Friendica\Core\Renderer; use Friendica\Core\System; -use Friendica\Network\Probe; +use Friendica\Model\User; +use Friendica\Protocol\Salmon; +use Friendica\Util\Strings; +/** + * Prints responses to /.well-known/webfinger or /xrd requests + */ class Xrd extends BaseModule { - public static function init() + public static function rawContent() { - if (local_user()) { - System::httpExit( - 403, - [ - "title" => L10n::t("Public access denied."), - "description" => L10n::t("Only logged in users are permitted to perform a probing.") - ] - ); - exit(); + $app = self::getApp(); + + // @TODO: Replace with parameter from router + if ($app->argv[0] == 'xrd') { + if (empty($_GET['uri'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { + $mode = 'json'; + } else { + $mode = 'xml'; + } + } else { + if (empty($_GET['resource'])) { + return; + } + + $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); + if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { + $mode = 'xml'; + } else { + $mode = 'json'; + } + } + + if (substr($uri, 0, 4) === 'http') { + $name = ltrim(basename($uri), '~'); + } else { + $local = str_replace('acct:', '', $uri); + if (substr($local, 0, 2) == '//') { + $local = substr($local, 2); + } + + $name = substr($local, 0, strpos($local, '@')); + } + + $user = User::getByNickname($name); + + if (empty($user)) { + System::httpExit(404); + } + + $profileURL = $app->getBaseURL() . '/profile/' . $user['nickname']; + $alias = str_replace('/profile/', '/~', $profileURL); + + $addr = 'acct:' . $user['nickname'] . '@' . $app->getHostName(); + if ($app->getURLPath()) { + $addr .= '/' . $app->getURLPath(); + } + + if ($mode == 'xml') { + self::printXML($addr, $alias, $profileURL, $app->getBaseURL(), $user); + } else { + self::printJSON($addr, $alias, $profileURL, $app->getBaseURL(), $user); } } - public static function content() + private static function printJSON($uri, $alias, $orofileURL, $baseURL, $user) { - $addr = defaults($_GET, 'addr', ''); - $res = ''; + $salmon_key = Salmon::salmonKey($user['spubkey']); - if (!empty($addr)) { - $res = Probe::lrdd($addr); - $res = str_replace("\n", '
', print_r($res, true)); - } + header('Access-Control-Allow-Origin: *'); + header('Content-type: application/json; charset=utf-8'); - $tpl = Renderer::getMarkupTemplate("xrd.tpl"); - return Renderer::replaceMacros($tpl, [ - '$addr' => $addr, - '$res' => $res, + $json = [ + 'subject' => $uri, + 'aliases' => [ + $alias, + $orofileURL, + ], + 'links' => [ + [ + 'rel' => NAMESPACE_DFRN, + 'href' => $orofileURL, + ], + [ + 'rel' => NAMESPACE_FEED, + 'type' => 'application/atom+xml', + 'href' => $baseURL . '/dfrn_poll/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/profile-page', + 'type' => 'text/html', + 'href' => $orofileURL, + ], + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => $orofileURL, + ], + [ + 'rel' => 'http://microformats.org/profile/hcard', + 'type' => 'text/html', + 'href' => $baseURL . '/hcard/' . $user['nickname'], + ], + [ + 'rel' => NAMESPACE_POCO, + 'href' => $baseURL . '/poco/' . $user['nickname'], + ], + [ + 'rel' => 'http://webfinger.net/rel/avatar', + 'type' => 'image/jpeg', + 'href' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + ], + [ + 'rel' => 'http://joindiaspora.com/seed_location', + 'type' => 'text/html', + 'href' => $baseURL, + ], + [ + 'rel' => 'salmon', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-replies', + 'href' => $baseURL . '/salmon/' . $user['nickname'], + ], + [ + 'rel' => 'http://salmon-protocol.org/ns/salmon-mention', + 'href' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => $baseURL . '/follow?url={uri}', + ], + [ + 'rel' => 'magic-public-key', + 'href' => 'data:application/magic-public-key,' . $salmon_key, + ], + [ + 'rel' => 'http://purl.org/openwebauth/v1', + 'type' => 'application/x-zot+json', + 'href' => $baseURL . '/owa', + ], + ], + ]; + + echo json_encode($json); + exit(); + } + + private static function printXML($uri, $alias, $profileURL, $baseURL, $user) + { + $salmon_key = Salmon::salmonKey($user['spubkey']); + + header('Access-Control-Allow-Origin: *'); + header('Content-type: text/xml'); + + $tpl = Renderer::getMarkupTemplate('xrd_person.tpl'); + + $o = Renderer::replaceMacros($tpl, [ + '$nick' => $user['nickname'], + '$accturi' => $uri, + '$alias' => $alias, + '$profile_url' => $profileURL, + '$hcard_url' => $baseURL . '/hcard/' . $user['nickname'], + '$atom' => $baseURL . '/dfrn_poll/' . $user['nickname'], + '$poco_url' => $baseURL . '/poco/' . $user['nickname'], + '$photo' => $baseURL . '/photo/profile/' . $user['uid'] . '.jpg', + '$baseurl' => $baseURL, + '$salmon' => $baseURL . '/salmon/' . $user['nickname'], + '$salmen' => $baseURL . '/salmon/' . $user['nickname'] . '/mention', + '$subscribe' => $baseURL . '/follow?url={uri}', + '$openwebauth' => $baseURL . '/owa', + '$modexp' => 'data:application/magic-public-key,' . $salmon_key ]); + + $arr = ['user' => $user, 'xml' => $o]; + Hook::callAll('personal_xrd', $arr); + + echo $arr['xml']; + exit(); } } diff --git a/view/templates/xrd.tpl b/view/templates/webfinger.tpl similarity index 88% rename from view/templates/xrd.tpl rename to view/templates/webfinger.tpl index c9c2e48a1..109a7fce2 100644 --- a/view/templates/xrd.tpl +++ b/view/templates/webfinger.tpl @@ -1,7 +1,7 @@

Webfinger Diagnostic

-
+ Lookup address:
From faae48959ec24f4e46120fd711e6b412856d9db5 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 19:29:24 +0200 Subject: [PATCH 11/12] code standards :-) --- src/Module/WebFinger.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module/WebFinger.php b/src/Module/WebFinger.php index 66280dce1..2f8a017cc 100644 --- a/src/Module/WebFinger.php +++ b/src/Module/WebFinger.php @@ -19,8 +19,8 @@ class WebFinger extends BaseModule System::httpExit( 403, [ - "title" => L10n::t("Public access denied."), - "description" => L10n::t("Only logged in users are permitted to perform a probing.") + 'title' => L10n::t("Public access denied."), + 'description' => L10n::t("Only logged in users are permitted to perform a probing.") ] ); exit(); @@ -41,8 +41,8 @@ class WebFinger extends BaseModule $tpl = Renderer::getMarkupTemplate('webfinger.tpl'); return Renderer::replaceMacros($tpl, [ - '$addr' => $addr, - '$res' => $res, + '$addr' => $addr, + '$res' => $res, ]); } } From a47a6a0cd95465b151e38e0c106e7653aa890d7e Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 1 May 2019 19:48:49 +0200 Subject: [PATCH 12/12] code standards :-) --- src/Module/WebFinger.php | 6 +++--- src/Module/WellKnown/XSocialRelay.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module/WebFinger.php b/src/Module/WebFinger.php index 2f8a017cc..3afcecb05 100644 --- a/src/Module/WebFinger.php +++ b/src/Module/WebFinger.php @@ -19,9 +19,9 @@ class WebFinger extends BaseModule System::httpExit( 403, [ - 'title' => L10n::t("Public access denied."), - 'description' => L10n::t("Only logged in users are permitted to perform a probing.") - ] + 'title' => L10n::t('Public access denied.'), + 'description' => L10n::t('Only logged in users are permitted to perform a probing.'), + ], ); exit(); } diff --git a/src/Module/WellKnown/XSocialRelay.php b/src/Module/WellKnown/XSocialRelay.php index 33e58d0c5..a1bbeb78a 100644 --- a/src/Module/WellKnown/XSocialRelay.php +++ b/src/Module/WellKnown/XSocialRelay.php @@ -33,7 +33,7 @@ class XSocialRelay extends BaseModule /// @todo Check if it was better to use "strtolower" on the tags foreach ($tagitems AS $tag) { - $systemTags[] = trim($tag, "# "); + $systemTags[] = trim($tag, '# '); } if ($config->get('system', 'relay_user_tags')) {