mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-19 16:55:18 +00:00
Remove LD-signatures with extreme bias.
This commit is contained in:
parent
fe03d1c51a
commit
1ed3fcf68e
22 changed files with 241 additions and 345 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -69,6 +69,9 @@ nbproject/
|
|||
*.kdev4
|
||||
# PHPStorm
|
||||
.idea/
|
||||
.phpunit.result.cache
|
||||
tests/.phpunit.result.cache
|
||||
tests/.phpunit.cache
|
||||
|
||||
|
||||
## composer
|
||||
|
|
|
@ -4,13 +4,13 @@ namespace Code\Daemon;
|
|||
|
||||
use Code\Lib\Config;
|
||||
use Code\Lib\IConfig;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Libzot;
|
||||
use Code\Lib\ObjCache;
|
||||
use Code\Lib\Queue;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\ActivityPub;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\Channel;
|
||||
use Code\Extend\Hook;
|
||||
|
||||
|
@ -377,7 +377,7 @@ class Notifier implements DaemonInterface
|
|||
|
||||
} else {
|
||||
self::$encoded_item = array_merge(Activity::ap_context(), Activity::encode_activity($target_item, true));
|
||||
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
|
||||
self::$encoded_item['proof'] = (new JcsEddsa2022)->sign(self::$encoded_item, self::$channel);
|
||||
}
|
||||
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
|
||||
logger('encoded: ' . print_r(self::$encoded_item, true), LOGGER_DEBUG);
|
||||
|
|
|
@ -71,7 +71,7 @@ class ActivityPub
|
|||
|
||||
$msg = array_merge(Activity::ap_context(), $ti);
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $arr['channel']);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $arr['channel']);
|
||||
|
||||
logger('ActivityPub_encoded (purge_all): ' . json_encode($msg, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
|
@ -106,7 +106,7 @@ class ActivityPub
|
|||
|
||||
$msg = array_merge(Activity::ap_context(), $ti);
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $arr['channel']);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $arr['channel']);
|
||||
|
||||
logger('ActivityPub_encoded: ' . json_encode($msg, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
|
@ -278,11 +278,11 @@ class ActivityPub
|
|||
if (intval($x['recipient']['xchan_type']) === XCHAN_TYPE_GROUP) {
|
||||
$join_msg = $msg;
|
||||
$join_msg['type'] = 'Join';
|
||||
$join_msg['signature'] = LDSignatures::sign($join_msg, $x['sender']);
|
||||
$join_msg['proof'] = (new JcsEddsa2022)->sign($join_msg, $x['sender']);
|
||||
$jmsg2 = json_encode($join_msg, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $x['sender']);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $x['sender']);
|
||||
$jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$h = q(
|
||||
|
@ -346,7 +346,7 @@ class ActivityPub
|
|||
]
|
||||
);
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $x['sender']);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $x['sender']);
|
||||
|
||||
$jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
|
@ -386,7 +386,7 @@ class ActivityPub
|
|||
]
|
||||
);
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $x['sender']);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $x['sender']);
|
||||
$jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$r = q("select * from abook left join hubloc on abook_xchan = hubloc_hash
|
||||
|
@ -473,7 +473,7 @@ class ActivityPub
|
|||
);
|
||||
}
|
||||
|
||||
$msg['signature'] = LDSignatures::sign($msg, $channel);
|
||||
$msg['proof'] = (new JcsEddsa2022)->sign($msg, $channel);
|
||||
|
||||
$jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class ActivityStreams
|
|||
public $origin = null;
|
||||
public $owner = null;
|
||||
public $signer = null;
|
||||
public $ldsig = null;
|
||||
public $edsig = null;
|
||||
public $sigok = false;
|
||||
public $recips = null;
|
||||
public $raw_recips = null;
|
||||
|
@ -114,15 +114,9 @@ class ActivityStreams
|
|||
$this->replyto = $this->get_property_obj('replyTo');
|
||||
}
|
||||
|
||||
$this->ldsig = $this->get_compound_property('signature');
|
||||
if ($this->ldsig) {
|
||||
$this->signer = $this->get_compound_property('creator', $this->ldsig);
|
||||
if (
|
||||
$this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer)
|
||||
&& is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']
|
||||
) {
|
||||
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
||||
}
|
||||
$this->edsig = $this->get_compound_property('proof');
|
||||
if ($this->edsig) {
|
||||
$this->checkEddsaSignature();
|
||||
}
|
||||
|
||||
// Implied create activity required by C2S specification if no object is present
|
||||
|
@ -509,6 +503,41 @@ class ActivityStreams
|
|||
return $x;
|
||||
}
|
||||
|
||||
public function checkEddsaSignature()
|
||||
{
|
||||
$signer = $this->get_property_obj('verificationMethod', $this->edsig);
|
||||
|
||||
$parseUrl = parse_url($signer);
|
||||
if (!empty($parseUrl['fragment']) && str_starts_with($parseUrl['fragment'],'z6Mk')) {
|
||||
$publicKey = $parseUrl['fragment'];
|
||||
unset($parseUrl['fragment']);
|
||||
unset($parseUrl['query']);
|
||||
}
|
||||
$url = unparse_url($parseUrl);
|
||||
$this->signer = [ 'id' => $url ];
|
||||
$hublocs = Activity::get_actor_hublocs($url);
|
||||
$hasStoredKey = false;
|
||||
if ($hublocs) {
|
||||
foreach ($hublocs as $hubloc) {
|
||||
if ($publicKey && $hubloc['xchan_epubkey'] === $publicKey) {
|
||||
$hasStoredKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! $hasStoredKey) {
|
||||
$this->signer = Activity::fetch($url);
|
||||
if ($this->signer
|
||||
&& !empty($this->signer['assertionMethod'])
|
||||
&& !empty($this->signer['assertionMethod']['publicKeyMultibase'])) {
|
||||
$publicKey = $this->signer['assertionMethod']['publicKeyMultibase'];
|
||||
}
|
||||
}
|
||||
if ($publicKey) {
|
||||
$this->sigok = (new JcsEddsa2022)->verify($this->data, $publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
public function debug() : null | string
|
||||
{
|
||||
return var_export($this, true);
|
||||
|
|
|
@ -53,6 +53,8 @@ class JcsEddsa2022
|
|||
logger('verify exception:' . $e->getMessage());
|
||||
}
|
||||
|
||||
logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Code\Lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
require_once('library/jsonld/jsonld.php');
|
||||
|
||||
class LDSignatures
|
||||
{
|
||||
|
||||
|
||||
public static function verify($data, $pubkey): bool
|
||||
{
|
||||
$ohash = self::hash(self::signable_options($data['signature']));
|
||||
$dhash = self::hash(self::signable_data($data));
|
||||
|
||||
$result = false;
|
||||
if (!empty($data['signature']['signatureValue'])) {
|
||||
$result = Crypto::verify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey);
|
||||
logger('LD-verify: ' . ((intval($result)) ? 'true' : 'false'));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function sign($data, $channel): array
|
||||
{
|
||||
|
||||
$options = [
|
||||
'type' => 'RsaSignature2017',
|
||||
'nonce' => random_string(),
|
||||
'creator' => Channel::url($channel),
|
||||
'created' => datetime_convert('UTC', 'UTC', 'now', 'Y-m-d\TH:i:s\Z')
|
||||
];
|
||||
|
||||
$ohash = self::hash(self::signable_options($options));
|
||||
$dhash = self::hash(self::signable_data($data));
|
||||
$options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash, $channel['channel_prvkey']));
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
|
||||
public static function signable_data($data): bool|string
|
||||
{
|
||||
|
||||
$newdata = [];
|
||||
if ($data) {
|
||||
foreach ($data as $k => $v) {
|
||||
if ($k != 'signature') {
|
||||
$newdata[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_encode($newdata, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
|
||||
public static function signable_options($options): bool|string
|
||||
{
|
||||
|
||||
$newopts = ['@context' => 'https://w3id.org/identity/v1'];
|
||||
if ($options) {
|
||||
foreach ($options as $k => $v) {
|
||||
if (!in_array($k, ['type', 'id', 'signatureValue'])) {
|
||||
$newopts[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_encode($newopts, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
public static function hash($obj): string
|
||||
{
|
||||
|
||||
return hash('sha256', self::normalise($obj));
|
||||
}
|
||||
|
||||
public static function normalise($data)
|
||||
{
|
||||
if (is_string($data)) {
|
||||
$data = json_decode($data);
|
||||
}
|
||||
|
||||
if (!is_object($data)) {
|
||||
return '';
|
||||
}
|
||||
$d = '';
|
||||
jsonld_set_document_loader('jsonld_document_loader');
|
||||
try {
|
||||
$d = jsonld_normalize($data, ['algorithm' => 'URDNA2015', 'format' => 'application/nquads']);
|
||||
} catch (Exception $e) {
|
||||
logger('normalise error: ' . $e->getMessage());
|
||||
logger('normalise error: ' . print_r($data, true), LOGGER_DATA);
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ use Code\Lib\ActivityStreams;
|
|||
use Code\Lib\Activity as ZlibActivity;
|
||||
use Code\Lib\Libzot;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\ThreadListener;
|
||||
use Code\Lib\Channel;
|
||||
use App;
|
||||
|
@ -296,7 +296,7 @@ class Activity extends Controller
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-nomad+json';
|
||||
$x['signature'] = LDSignatures::sign($x, $chan);
|
||||
$x['signature'] = (new JcsEddsa2022)->sign($x, $chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
|
|
@ -8,7 +8,7 @@ use Code\Lib\Libzot;
|
|||
use Code\Lib\Activity;
|
||||
use Code\Lib\Libprofile;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Crypto;
|
||||
use Code\Lib\PConfig;
|
||||
use Code\Lib as Zlib;
|
||||
|
@ -153,7 +153,7 @@ class Channel extends Controller
|
|||
http_status_exit(403, 'Permission denied');
|
||||
}
|
||||
|
||||
as_return_and_die(Activity::encode_person($channel, true, true), $channel, '',false);
|
||||
as_return_and_die(Activity::encode_person($channel, true, true), $channel);
|
||||
}
|
||||
|
||||
// handle zot6 channel discovery
|
||||
|
|
|
@ -43,7 +43,7 @@ class Ap_probe extends Controller
|
|||
if (isset($j['type'])) {
|
||||
$AS = new ActivityStreams($j, null, true);
|
||||
if ($AS->is_valid() && isset($AS->data['type'])) {
|
||||
$html .= EOL . t('LD-Signature: ') . (($AS->sigok) ? 'true' : 'false') . EOL. EOL;
|
||||
$html .= EOL . t('Eddsa-Signature: ') . (($AS->sigok) ? 'true' : 'false') . EOL. EOL;
|
||||
if (is_array($AS->obj)
|
||||
&& isset($AS->obj['type'])
|
||||
&& !str_contains($AS->obj['type'], 'Collection')
|
||||
|
|
|
@ -13,7 +13,7 @@ use Code\Lib\Channel;
|
|||
use Code\Lib\Navbar;
|
||||
use Code\Lib\Socgraph;
|
||||
use Code\Lib\XConfig;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Extend\Hook;
|
||||
use Code\Render\Theme;
|
||||
|
@ -305,7 +305,7 @@ class Directory extends Controller
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-nomad+json';
|
||||
$x['signature'] = LDSignatures::sign($x, $chan);
|
||||
$x['signature'] = (new JcsEddsa2022)->sign($x, $chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Code\Module;
|
|||
use Code\Web\Controller;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Channel;
|
||||
use Code\Web\HTTPSig;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Code\Module;
|
|||
|
||||
use App;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Web\Controller;
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Code\Module;
|
|||
|
||||
use App;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Web\Controller;
|
||||
|
|
|
@ -6,7 +6,7 @@ use App;
|
|||
use Code\Lib\Libzot;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Crypto;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Web\Controller;
|
||||
|
@ -31,7 +31,7 @@ class Home extends Controller
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||
$x['signature'] = LDSignatures::sign($x, ['channel_address' => z_root(), 'channel_prvkey' => get_config('system', 'prvkey')]);
|
||||
$x['signature'] = (new JcsEddsa2022)->sign($x, ['channel_address' => z_root(), 'channel_prvkey' => get_config('system', 'prvkey')]);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
logger('data: ' . jindent($ret), LOGGER_DATA);
|
||||
$headers['Date'] = datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
|
||||
|
|
|
@ -138,9 +138,7 @@ class Inbox extends Controller
|
|||
$v = Activity::get_actor_hublocs($AS->actor['id']);
|
||||
|
||||
if ($v && $v[0]['hubloc_hash'] !== $hsig['portable_id']) {
|
||||
// The sender is not actually the activity actor, so verify the LD signature.
|
||||
// litepub activities (with no LD signature) will always have a matching actor and sender
|
||||
|
||||
// The sender is not actually the activity actor, so verify the object signature.
|
||||
if ($AS->signer && is_array($AS->signer) && $AS->signer['id'] !== $AS->actor['id']) {
|
||||
// the activity wasn't signed by the activity actor
|
||||
return;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Code\Module;
|
|||
use Code\Lib\Libsync;
|
||||
use Code\Lib\Activity;
|
||||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Web\HTTPSig;
|
||||
use Code\Web\Controller;
|
||||
use Code\Lib\Libzot;
|
||||
|
@ -310,7 +310,7 @@ class Item extends Controller
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-nomad+json';
|
||||
$x['signature'] = LDSignatures::sign($x, $chan);
|
||||
$x['signature'] = (new JcsEddsa2022)->sign($x, $chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
|
|
@ -8,7 +8,7 @@ use Code\Lib\Activity;
|
|||
use Code\Lib\ActivityStreams;
|
||||
use Code\Lib\ASCollection;
|
||||
use Code\Lib\Channel;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Libprofile;
|
||||
use Code\Lib\Libzot;
|
||||
use Code\Lib\Navbar;
|
||||
|
@ -369,7 +369,7 @@ class Search extends Controller
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-nomad+json';
|
||||
$x['signature'] = LDSignatures::sign($x, $chan);
|
||||
$x['signature'] = (new JcsEddsa2022)->sign($x, $chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
|
|
@ -9,7 +9,7 @@ use Code\Lib\Activity;
|
|||
use Code\Lib\ActivityPub;
|
||||
use Code\Lib\Queue;
|
||||
use Code\Lib\System;
|
||||
use Code\Lib\LDSignatures;
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Lib\Addon;
|
||||
use Code\Lib\Url;
|
||||
use Code\Web\HTTPSig;
|
||||
|
@ -21,15 +21,11 @@ use PHPMailer\PHPMailer\PHPMailer;
|
|||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
|
||||
require_once('library/jsonld/jsonld.php');
|
||||
/**
|
||||
* @file include/network.php
|
||||
* @brief Network related functions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
function json_return_and_die($x, $content_type = 'application/json', $debug = false)
|
||||
{
|
||||
header("Content-type: $content_type");
|
||||
|
@ -40,7 +36,7 @@ function json_return_and_die($x, $content_type = 'application/json', $debug = fa
|
|||
killme();
|
||||
}
|
||||
|
||||
function as_return_and_die($obj, $channel, $contextType = null, $ldsign = true)
|
||||
function as_return_and_die($obj, $channel, $contextType = null, $signObject = true)
|
||||
{
|
||||
|
||||
if (! is_array($obj)) {
|
||||
|
@ -52,8 +48,8 @@ function as_return_and_die($obj, $channel, $contextType = null, $ldsign = true)
|
|||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
|
||||
if ($ldsign) {
|
||||
$data['signature'] = LDSignatures::sign($data, $channel);
|
||||
if ($signObject) {
|
||||
$data['proof'] = (new JcsEddsa2022)->sign($data, $channel);
|
||||
}
|
||||
$json = json_encode($data, JSON_UNESCAPED_SLASHES);
|
||||
logger('data: ' . jindent($json), LOGGER_DATA);
|
||||
|
@ -1436,156 +1432,6 @@ function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false)
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform caching for jsonld normaliser.
|
||||
*
|
||||
* @param string $url
|
||||
* @return mixed|bool|array
|
||||
*/
|
||||
function jsonld_document_loader($url)
|
||||
{
|
||||
$doc = (object) [ 'contextUrl' => null, 'document' => null, 'documentUrl' => $url];
|
||||
$recursion = 0;
|
||||
|
||||
$builtins = [
|
||||
'https://www.w3.org/ns/activitystreams' => 'library/w3org/activitystreams.jsonld',
|
||||
'https://w3id.org/identity/v1' => 'library/w3org/identity-v1.jsonld',
|
||||
'https://w3id.org/security/v1' => 'library/w3org/security-v1.jsonld',
|
||||
];
|
||||
|
||||
$x = debug_backtrace();
|
||||
if ($x) {
|
||||
foreach ($x as $n) {
|
||||
if ($n['function'] === __FUNCTION__) {
|
||||
$recursion++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($recursion > 5) {
|
||||
logger('jsonld bomb detected at: ' . $url);
|
||||
killme();
|
||||
}
|
||||
|
||||
$cachepath = 'cache/ldcache';
|
||||
if (! is_dir($cachepath)) {
|
||||
Stdio::mkdir($cachepath, STORAGE_DEFAULT_PERMISSIONS, true);
|
||||
}
|
||||
|
||||
$filename = '';
|
||||
|
||||
foreach ($builtins as $key => $value) {
|
||||
if ($url === $key) {
|
||||
$doc->document = file_get_contents($value);
|
||||
return $doc;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $filename) {
|
||||
$filename = $cachepath . '/' . urlencode($url);
|
||||
}
|
||||
|
||||
if (file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) {
|
||||
logger('loading ' . $filename . ' from recent cache');
|
||||
return file_get_contents($filename);
|
||||
}
|
||||
|
||||
$r = jsonld_default_document_loader($url);
|
||||
if ($r) {
|
||||
if (!in_array($url, $builtins)) {
|
||||
file_put_contents($filename, json_encode($r));
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
if (file_exists($filename)) {
|
||||
logger('loading ' . $filename . ' from longterm cache');
|
||||
return file_get_contents($filename);
|
||||
}
|
||||
else {
|
||||
logger($filename . ' does not exist and cannot be loaded');
|
||||
}
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform caching for jsonld normaliser.
|
||||
*
|
||||
* @param string $url
|
||||
* @return mixed|bool|array
|
||||
*/
|
||||
function hz_jsonld_document_loader($url) {
|
||||
$doc = (object) [
|
||||
'contextUrl' => null,
|
||||
'document' => null,
|
||||
'documentUrl' => $url
|
||||
];
|
||||
|
||||
$recursion = 0;
|
||||
|
||||
$builtins = [
|
||||
'https://www.w3.org/ns/activitystreams' => 'library/w3org/activitystreams.jsonld',
|
||||
'https://w3id.org/identity/v1' => 'library/w3org/identity-v1.jsonld',
|
||||
'https://w3id.org/security/v1' => 'library/w3org/security-v1.jsonld',
|
||||
];
|
||||
|
||||
$x = debug_backtrace();
|
||||
if ($x) {
|
||||
foreach ($x as $n) {
|
||||
if ($n['function'] === __FUNCTION__) {
|
||||
$recursion++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($recursion > 5) {
|
||||
logger('jsonld bomb detected at: ' . $url);
|
||||
killme();
|
||||
}
|
||||
|
||||
foreach ($builtins as $key => $value) {
|
||||
if ($url === $key) {
|
||||
$doc->document = file_get_contents($value);
|
||||
return $doc;
|
||||
}
|
||||
}
|
||||
|
||||
$cachepath = 'store/[data]/[jsonld]';
|
||||
if(!is_dir($cachepath)) {
|
||||
os_mkdir($cachepath, STORAGE_DEFAULT_PERMISSIONS, true);
|
||||
}
|
||||
|
||||
$filename = $cachepath . '/' . urlencode($url);
|
||||
|
||||
if (file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) {
|
||||
logger('loading ' . $filename . ' from recent cache');
|
||||
return json_decode(file_get_contents($filename));
|
||||
}
|
||||
|
||||
$r = jsonld_default_document_loader($url);
|
||||
if ($r) {
|
||||
if (!in_array($url, $builtins)) {
|
||||
$cache_obj = $r;
|
||||
// To prevent double encoding we need to decode $cache_obj->document
|
||||
// before encoding the whole object for storage.
|
||||
$cache_obj->document = json_decode($cache_obj->document);
|
||||
file_put_contents($filename, json_encode($cache_obj));
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
if (file_exists($filename)) {
|
||||
logger('loading ' . $filename . ' from longterm cache');
|
||||
return json_decode(file_get_contents($filename));
|
||||
}
|
||||
else {
|
||||
logger($filename . ' does not exist and cannot be loaded');
|
||||
}
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
|
||||
function is_https_request()
|
||||
{
|
||||
|
|
9
tests/bootstrap.php
Normal file
9
tests/bootstrap.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
set_include_path(
|
||||
'../include' . PATH_SEPARATOR
|
||||
. '../library' . PATH_SEPARATOR
|
||||
. '../'
|
||||
);
|
||||
|
||||
require_once('../boot.php');
|
27
tests/phpunit.xml
Normal file
27
tests/phpunit.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
|
||||
bootstrap="bootstrap.php"
|
||||
cacheResultFile=".phpunit.cache/test-results"
|
||||
executionOrder="depends,defects"
|
||||
forceCoversAnnotation="false"
|
||||
beStrictAboutCoversAnnotation="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory>../tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage cacheDirectory=".phpunit.cache/code-coverage"
|
||||
processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">.</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
|
@ -1,49 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.0/phpunit.xsd"
|
||||
bootstrap="../boot.php"
|
||||
forceCoversAnnotation="false"
|
||||
beStrictAboutCoversAnnotation="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
verbose="true">
|
||||
<testsuite name="Default Test Suite">
|
||||
<directory suffix="Test.php">./unit/</directory>
|
||||
</testsuite>
|
||||
<testsuite name="API Test Suite">
|
||||
<directory suffix="Test.php" prefix="API">./unit/</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Ex-/Import Test Suite">
|
||||
<!--<directory suffix="Test.php">./unit/eximport/</directory>-->
|
||||
</testsuite>
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>postgresql</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
<!--cover reporting-->
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">../Code/</directory>
|
||||
<directory suffix=".php">../include/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="junit" target="./results/junit.xml" logIncompleteSkipped="false"/>
|
||||
<log type="coverage-clover" target="./results/coverage-clover.xml"/>
|
||||
<log type="coverage-html" target="./results/coverage-report/" lowUpperBound="35"
|
||||
highLowerBound="70"/>
|
||||
<log type="testdox-text" target="./results/testdox.txt"/>
|
||||
</logging>
|
||||
<php>
|
||||
<!-- Default test database config, only used if no environment variables
|
||||
with same names are set.
|
||||
!!! Never run against a real database, it will truncate all tables -->
|
||||
<env name="hz_db_server" value="127.0.0.1"/>
|
||||
<env name="hz_db_scheme" value="mysql"/>
|
||||
<env name="hz_db_port" value="3306"/>
|
||||
<env name="hz_db_user" value="travis_hz"/>
|
||||
<env name="hz_db_pass" value="hubzilla"/>
|
||||
<env name="hz_db_database" value="travis_hubzilla"/>
|
||||
</php>
|
||||
</phpunit>
|
|
@ -3,9 +3,10 @@
|
|||
namespace Code\Tests\Unit\Lib;
|
||||
|
||||
use Code\Lib\JcsEddsa2022;
|
||||
use Code\Tests\Unit\UnitTestCase;
|
||||
|
||||
|
||||
class JcsEddsa2022Test extends \Code\Tests\Unit\UnitTestCase
|
||||
class JcsEddsa2022Test extends UnitTestCase
|
||||
{
|
||||
|
||||
public function testVerifyFromSpec()
|
||||
|
@ -46,4 +47,132 @@ class JcsEddsa2022Test extends \Code\Tests\Unit\UnitTestCase
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
public function testSignAndVerify()
|
||||
{
|
||||
$publicKey = 'z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d';
|
||||
$channel = [
|
||||
'channel_url' => 'https://example.com/channel/klingon',
|
||||
'channel_epubkey' => 'FGdbYgr526Swuyya3e8epCBdHahlWNg9I0sBhMKCzpw',
|
||||
'channel_eprvkey' => 'StLRo8xb7VJ5XdR10OUYQM/uooP7D7fMlgvQFa1wrZIUZ1tiCvnbpLC7LJrd7x6kIF0dqGVY2D0jSwGEwoLOnA',
|
||||
'channel_address' => 'klingon@example.com',
|
||||
'channel_system' => false,
|
||||
];
|
||||
|
||||
$document = '{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
"https://www.w3.org/ns/did/v1",
|
||||
"https://w3id.org/security/multikey/v1",
|
||||
{
|
||||
"nomad": "https://example.com/apschema#",
|
||||
"toot": "http://joinmastodon.org/ns#",
|
||||
"litepub": "http://litepub.social/ns#",
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"oauthRegistrationEndpoint": "litepub:oauthRegistrationEndpoint",
|
||||
"sensitive": "as:sensitive",
|
||||
"movedTo": "as:movedTo",
|
||||
"discoverable": "toot:discoverable",
|
||||
"indexable": "toot:indexable",
|
||||
"capabilities": "litepub:capabilities",
|
||||
"acceptsJoins": "litepub:acceptsJoins",
|
||||
"Hashtag": "as:Hashtag",
|
||||
"canReply": "toot:canReply",
|
||||
"canSearch": "nomad:canSearch",
|
||||
"approval": "toot:approval",
|
||||
"expires": "nomad:expires",
|
||||
"directMessage": "nomad:directMessage",
|
||||
"Category": "nomad:Category",
|
||||
"copiedTo": "nomad:copiedTo",
|
||||
"searchContent": "nomad:searchContent",
|
||||
"searchTags": "nomad:searchTags"
|
||||
}
|
||||
],
|
||||
"type": "Person",
|
||||
"id": "https://example.com/channel/klingon",
|
||||
"preferredUsername": "klingon",
|
||||
"name": "klingon",
|
||||
"created": "2023-07-13T20:23:32Z",
|
||||
"updated": "2023-07-13T20:23:32Z",
|
||||
"icon": {
|
||||
"type": "Image",
|
||||
"mediaType": "image/png",
|
||||
"updated": "2023-07-13T20:23:32Z",
|
||||
"url": "https://example.com/photo/profile/l/2",
|
||||
"height": 300,
|
||||
"width": 300
|
||||
},
|
||||
"url": "https://example.com/channel/klingon",
|
||||
"tag": [
|
||||
{
|
||||
"type": "Note",
|
||||
"name": "Protocol",
|
||||
"content": "zot6"
|
||||
},
|
||||
{
|
||||
"type": "Note",
|
||||
"name": "Protocol",
|
||||
"content": "nomad"
|
||||
},
|
||||
{
|
||||
"type": "Note",
|
||||
"name": "Protocol",
|
||||
"content": "activitypub"
|
||||
}
|
||||
],
|
||||
"inbox": "https://example.com/inbox/klingon",
|
||||
"outbox": "https://example.com/outbox/klingon",
|
||||
"followers": "https://example.com/followers/klingon",
|
||||
"following": "https://example.com/following/klingon",
|
||||
"wall": "https://example.com/outbox/klingon",
|
||||
"endpoints": {
|
||||
"sharedInbox": "https://example.com/inbox",
|
||||
"oauthRegistrationEndpoint": "https://example.com/api/client/register",
|
||||
"oauthAuthorizationEndpoint": "https://example.com/authorize",
|
||||
"oauthTokenEndpoint": "https://example.com/token",
|
||||
"searchContent": "https://example.com/search/klingon?search={}",
|
||||
"searchTags": "https://example.com/search/klingon?tag={}"
|
||||
},
|
||||
"discoverable": true,
|
||||
"canSearch": [],
|
||||
"indexable": false,
|
||||
"publicKey": {
|
||||
"id": "https://example.com/channel/klingon?operation=rsakey",
|
||||
"owner": "https://example.com/channel/klingon",
|
||||
"signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+LXyOD/bzzVgM/nUOJ5m
|
||||
c4WrQPMlhKqWJvKrumdQw9JJYcyaZp/jmMxDx/w/EwVw+wnV5wZcD0yBVhC7NPRa
|
||||
nYc5OfNhS4MO74xgZrj+VWSTzNo3YooS/dEIIvsu6bhxfooHj17SA6pMRnZkkVpk
|
||||
ykpPRYwJw+NvKcRwzpF06rxMqjZ+Bp0ea/X37j4cHaosRoQTJiHmMKKnpByKdImF
|
||||
TR1juJ69ASh6nh8YVGcz6fz1jBQZPMx05tfNdyN5oZRTr8Nug2CiF3V7yKKS14HD
|
||||
kE9eeFeTMt58Qi+8kprATYxKrlIuTZmI4YdIRgtM+tPQsosKTFmjzbef4dYooutv
|
||||
T7XfrE+wYVZlx2pkaeFiKrJVacpmmFJe8zCIFXrofq1aOagU1kpwnXgjneCttA+M
|
||||
OJ3Y+cPamdfRQDtsBcokJUD40RTwux6OGW9zqkJIpniVB+CZu4nTOHCzMJwbxF0p
|
||||
JmGZd9kc3PR6Uf/IHAb1xeyTi4FyyYTbRDYuJyqRKbe880QUwgCBcogIbNy4xxsH
|
||||
UTMy0ucWaDSBRahKUIHl3FRglvnI754NJSXBDIQOwC9oRRH27Vmm1Jy8sltmFLFr
|
||||
ENJCGgOH8Bhpk+y1jtw1jpTig76wIvw+6zQtgNSfPnrNGIHt5mcoy4pFFXLv2lK2
|
||||
/u26hUGQAq71Ra0DwgXIWFECAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
"
|
||||
},
|
||||
"assertionMethod": [
|
||||
{
|
||||
"id": "https://example.com/channel/klingon#z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d",
|
||||
"type": "Multikey",
|
||||
"controller": "https://example.com/channel/klingon",
|
||||
"publicKeyMultibase": "z6MkfpucGTDbMZADwM6vEa8pS3s8Z9xqSEn6HihijZ4fVs9d"
|
||||
}
|
||||
],
|
||||
"manuallyApprovesFollowers": true
|
||||
}';
|
||||
|
||||
$algorithm = new JcsEddsa2022();
|
||||
$documentArray = json_decode($document,true);
|
||||
$documentArray['proof'] = $algorithm->sign($documentArray, $channel);
|
||||
|
||||
$verified = (new JcsEddsa2022())->verify($documentArray, $publicKey);
|
||||
$this->assertTrue($verified, 'Verify encode and decode eddsa-jcs-2022');
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue