X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FOStatus%2Flib%2Fsalmon.php;h=2f5772a84497eac45d0cf86cdb73faea50899301;hb=1d15145993a00d1db1057dacf71f3783cd16c119;hp=ef7719a40c3861513549b11dc6096e89d25d56b5;hpb=433c43c99986f04b3bbe04cee7426f1248e1e96e;p=quix0rs-gnu-social.git diff --git a/plugins/OStatus/lib/salmon.php b/plugins/OStatus/lib/salmon.php index ef7719a40c..2f5772a844 100644 --- a/plugins/OStatus/lib/salmon.php +++ b/plugins/OStatus/lib/salmon.php @@ -31,17 +31,19 @@ class Salmon const REL_SALMON = 'salmon'; const REL_MENTIONED = 'mentioned'; - // XXX: these are deprecated + // XXX: these are deprecated const NS_REPLIES = "http://salmon-protocol.org/ns/salmon-replies"; const NS_MENTIONS = "http://salmon-protocol.org/ns/salmon-mention"; - + /** * Sign and post the given Atom entry as a Salmon message. * - * @fixme pass through the actor for signing? + * Side effects: may generate a keypair on-demand for the given user, + * which can be very slow on some systems. * * @param string $endpoint_uri - * @param string $xml + * @param string $xml string representation of payload + * @param Profile $actor local user profile whose keys to sign with * @return boolean success */ public function post($endpoint_uri, $xml, $actor) @@ -50,34 +52,65 @@ class Salmon return false; } - try { - $xml = $this->createMagicEnv($xml, $actor); - } catch (Exception $e) { - common_log(LOG_ERR, "Salmon unable to sign: " . $e->getMessage()); - return false; - } - - $headers = array('Content-Type: application/magic-envelope+xml'); + foreach ($this->formatClasses() as $class) { + try { + $envelope = $this->createMagicEnv($xml, $actor, $class); + } catch (Exception $e) { + common_log(LOG_ERR, "Salmon unable to sign: " . $e->getMessage()); + return false; + } + + $headers = array('Content-Type: application/magic-envelope+xml'); + + try { + $client = new HTTPClient(); + $client->setBody($envelope); + $response = $client->post($endpoint_uri, $headers); + } catch (HTTP_Request2_Exception $e) { + common_log(LOG_ERR, "Salmon ($class) post to $endpoint_uri failed: " . $e->getMessage()); + continue; + } + if ($response->getStatus() != 200) { + common_log(LOG_ERR, "Salmon ($class) at $endpoint_uri returned status " . + $response->getStatus() . ': ' . $response->getBody()); + continue; + } - try { - $client = new HTTPClient(); - $client->setBody($xml); - $response = $client->post($endpoint_uri, $headers); - } catch (HTTP_Request2_Exception $e) { - common_log(LOG_ERR, "Salmon post to $endpoint_uri failed: " . $e->getMessage()); - return false; - } - if ($response->getStatus() != 200) { - common_log(LOG_ERR, "Salmon at $endpoint_uri returned status " . - $response->getStatus() . ': ' . $response->getBody()); - return false; + // Success! + return true; } - return true; + return false; + } + + /** + * List the magic envelope signature class variants in the order we try them. + * Multiples are needed for backwards-compat with StatusNet prior to 0.9.7, + * which used a draft version of the magic envelope spec. + */ + protected function formatClasses() { + return array('MagicEnvelope', 'MagicEnvelopeCompat'); } - public function createMagicEnv($text, $actor) + /** + * Encode the given string as a signed MagicEnvelope XML document, + * using the keypair for the given local user profile. + * + * Side effects: will create and store a keypair on-demand if one + * hasn't already been generated for this user. This can be very slow + * on some systems. + * + * @param string $text XML fragment to sign, assumed to be Atom + * @param Profile $actor Profile of a local user to use as signer + * @param string $class to override the magic envelope signature version, pass a MagicEnvelope subclass here + * + * @return string XML string representation of magic envelope + * + * @throws Exception on bad profile input or key generation problems + * @fixme if signing fails, this seems to return the original text without warning. Is there a reason for this? + */ + public function createMagicEnv($text, $actor, $class='MagicEnvelope') { - $magic_env = new MagicEnvelope(); + $magic_env = new $class(); $user = User::staticGet('id', $actor->id); if ($user->id) { @@ -87,9 +120,10 @@ class Salmon // No keypair yet, let's generate one. $magickey = new Magicsig(); $magickey->generate($user->id); - } + } } else { - throw new Exception("Salmon invalid actor for signing"); + // TRANS: Exception. + throw new Exception(_m('Salmon invalid actor for signing.')); } try { @@ -100,13 +134,32 @@ class Salmon return $magic_env->toXML($env); } - + /** + * Check if the given magic envelope is well-formed and correctly signed. + * Needs to have network access to fetch public keys over the web. + * Both current and back-compat signature formats will be checked. + * + * Side effects: exceptions and caching updates may occur during network + * fetches. + * + * @param string $text XML fragment of magic envelope + * @return boolean + * + * @throws Exception on bad profile input or key generation problems + * @fixme could hit fatal errors or spew output on invalid XML + */ public function verifyMagicEnv($text) { - $magic_env = new MagicEnvelope(); - - $env = $magic_env->parse($text); + foreach ($this->formatClasses() as $class) { + $magic_env = new $class(); + + $env = $magic_env->parse($text); + + if ($magic_env->verify($env)) { + return true; + } + } - return $magic_env->verify($env); + return false; } }