update signature checking requirements for inbox

This commit is contained in:
nobody 2020-10-31 16:11:35 -07:00
parent a246942ea5
commit 466f65a27d
2 changed files with 79 additions and 44 deletions

View file

@ -106,9 +106,26 @@ class Activity {
}
if ($x['success']) {
$y = json_decode($x['body'],true);
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
// check for a valid signature, but only if this is not an actor object. If it is signed, it must be valid.
// Ignore actors because of the potential for infinite recursion if we perform this step while
// fetching an actor key to validate a signature elsewhere. This should validate relayed activities
// over litepub which arrived at our inbox that do not use LD signatures
if (($y['type']) && (! ActivityStreams::is_an_actor($y['type']))) {
$sigblock = HTTPSig::verify($x);
if (($sigblock['header_signed']) && (! $sigblock['header_valid'])) {
return null;
}
}
return json_decode($x['body'], true);
}
else {
logger('fetch failed: ' . $url);

View file

@ -80,43 +80,6 @@ class Inbox extends Controller {
return;
}
// $observer_hash in this case is the sender
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
$observer_hash = $hsig['portable_id'];
// fetch the portable_id for the actor, which may or may not be the sender
$v = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s'",
dbesc($AS->actor['id']),
dbesc($AS->actor['id'])
);
// only allow relayed activities if the activity is signed with LDSigs
// AND the signature is valid AND the signer is the actor.
if ($v && $v[0]['hubloc_hash'] !== $observer_hash) {
if ($AS->signer && $AS->signer !== $AS->actor['id']) {
return;
}
if (! $AS->sigok) {
return;
}
}
}
else {
$observer_hash = $AS->actor['id'];
}
if (! $observer_hash) {
return;
}
$m = parse_url($observer_hash);
if ($m && $m['scheme'] && $m['host']) {
if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) {
http_status_exit(403,'Permission denied');
}
}
if (! check_channelallowed($observer_hash)) {
http_status_exit(403,'Permission denied');
}
if (is_array($AS->actor) && array_key_exists('id',$AS->actor)) {
Activity::actor_store($AS->actor['id'],$AS->actor);
@ -133,22 +96,77 @@ class Inbox extends Controller {
}
}
// Validate that the channel that sent us this activity has authority to do so.
// Require a valid HTTPSignature with a signed Digest header.
// Only permit relayed activities if the activity is signed with LDSigs
// AND the signature is valid AND the signer is the actor.
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
// fetch the portable_id for the actor, which may or may not be the sender
$v = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s'",
dbesc($AS->actor['id']),
dbesc($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
if ($AS->signer && $AS->signer !== $AS->actor['id']) {
// the activity wasn't signed by the activity actor
return;
}
if (! $AS->sigok) {
// The activity signature isn't valid.
return;
}
}
if ($v) {
// The sender has been validated and stored
$observer_hash = $hsig['portable_id'];
}
}
if (! $observer_hash) {
return;
}
// verify that this site has permitted communication with the sender.
$m = parse_url($observer_hash);
if ($m && $m['scheme'] && $m['host']) {
if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) {
http_status_exit(403,'Permission denied');
}
// this site obviously isn't dead because they are trying to communicate with us.
$test = q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ",
dbesc($m['scheme'] . '://' . $m['host'])
);
}
if (! check_channelallowed($observer_hash)) {
http_status_exit(403,'Permission denied');
}
// update the hubloc_connected timestamp, ignore failures
$test = q("update hubloc set hubloc_connected = '%s' where hubloc_hash = '%s' and hubloc_network = 'activitypub'",
dbesc(datetime_convert()),
dbesc($observer_hash)
);
$m = parse_url($observer_hash);
if ($m['scheme'] && $m['host']) {
$test = q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ",
dbesc($m['scheme'] . '://' . $m['host'])
);
}
// Now figure out who the recipients are
if ($is_public) {
if ($AS->type === 'Follow' && is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
if (in_array($AS->type, [ 'Follow', 'Join' ]) && is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
$channels = q("SELECT * from channel where channel_address = '%s' and channel_removed = 0 ",
dbesc(basename($AS->obj['id']))
);