Reworked OStatus communication part to better support Mastodon.
This commit is contained in:
		
					parent
					
						
							
								25d70c39c6
							
						
					
				
			
			
				commit
				
					
						e16fb74b0c
					
				
			
		
					 5 changed files with 117 additions and 123 deletions
				
			
		| 
						 | 
				
			
			@ -59,11 +59,11 @@ function bb_attachment($Text, $simplehtml = false, $tryoembed = true) {
 | 
			
		|||
		if (($data["title"] != "") AND ((strpos($test1,$test2) !== false) OR
 | 
			
		||||
			(similar_text($test1,$test2) / strlen($data["title"])) > 0.9))
 | 
			
		||||
			$title2 = $data["url"];
 | 
			
		||||
		$text = sprintf('<a href="%s" title="%s" class="attachment thumbnail" rel="nofollow external">%s</a><br />',
 | 
			
		||||
		$text = sprintf('<a href="%s" title="%s" class="attachment" rel="nofollow external">%s</a><br />',
 | 
			
		||||
				$data["url"], $data["title"], $title2);
 | 
			
		||||
	} elseif (($simplehtml != 4) AND ($simplehtml != 0))
 | 
			
		||||
	} elseif (($simplehtml != 4) AND ($simplehtml != 0)) {
 | 
			
		||||
		$text = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]);
 | 
			
		||||
	else {
 | 
			
		||||
	} else {
 | 
			
		||||
		$text = sprintf('<span class="type-%s">', $data["type"]);
 | 
			
		||||
 | 
			
		||||
		$bookmark = array(sprintf('[bookmark=%s]%s[/bookmark]', $data["url"], $data["title"]), $data["url"], $data["title"]);
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ function bb_attachment($Text, $simplehtml = false, $tryoembed = true) {
 | 
			
		|||
				$text .= sprintf('<blockquote>%s</blockquote></span>', trim(bbcode($data["description"])));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return $data["text"].$text.$data["after"];
 | 
			
		||||
	return trim($data["text"].' '.$text.' '.$data["after"]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function bb_remove_share_information($Text, $plaintext = false, $nolink = false) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1480,14 +1480,6 @@ class ostatus {
 | 
			
		|||
		$siteinfo = get_attached_data($item["body"]);
 | 
			
		||||
 | 
			
		||||
		switch($siteinfo["type"]) {
 | 
			
		||||
			case 'link':
 | 
			
		||||
				$attributes = array("rel" => "enclosure",
 | 
			
		||||
						"href" => $siteinfo["url"],
 | 
			
		||||
						"type" => "text/html; charset=UTF-8",
 | 
			
		||||
						"length" => "",
 | 
			
		||||
						"title" => $siteinfo["title"]);
 | 
			
		||||
				xml::add_element($doc, $root, "link", "", $attributes);
 | 
			
		||||
				break;
 | 
			
		||||
			case 'photo':
 | 
			
		||||
				$imgdata = get_photo_info($siteinfo["image"]);
 | 
			
		||||
				$attributes = array("rel" => "enclosure",
 | 
			
		||||
| 
						 | 
				
			
			@ -1509,29 +1501,31 @@ class ostatus {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if (($siteinfo["type"] != "photo") AND isset($siteinfo["image"])) {
 | 
			
		||||
			$photodata = get_photo_info($siteinfo["image"]);
 | 
			
		||||
			$imgdata = get_photo_info($siteinfo["image"]);
 | 
			
		||||
			$attributes = array("rel" => "enclosure",
 | 
			
		||||
					"href" => $siteinfo["image"],
 | 
			
		||||
					"type" => $imgdata["mime"],
 | 
			
		||||
					"length" => intval($imgdata["size"]));
 | 
			
		||||
 | 
			
		||||
			$attributes = array("rel" => "preview", "href" => $siteinfo["image"], "media:width" => $photodata[0], "media:height" => $photodata[1]);
 | 
			
		||||
			xml::add_element($doc, $root, "link", "", $attributes);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$arr = explode('[/attach],',$item['attach']);
 | 
			
		||||
		if(count($arr)) {
 | 
			
		||||
			foreach($arr as $r) {
 | 
			
		||||
		$arr = explode('[/attach],', $item['attach']);
 | 
			
		||||
		if (count($arr)) {
 | 
			
		||||
			foreach ($arr as $r) {
 | 
			
		||||
				$matches = false;
 | 
			
		||||
				$cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches);
 | 
			
		||||
				if($cnt) {
 | 
			
		||||
				$cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|', $r, $matches);
 | 
			
		||||
				if ($cnt) {
 | 
			
		||||
					$attributes = array("rel" => "enclosure",
 | 
			
		||||
							"href" => $matches[1],
 | 
			
		||||
							"type" => $matches[3]);
 | 
			
		||||
 | 
			
		||||
					if(intval($matches[2]))
 | 
			
		||||
					if (intval($matches[2])) {
 | 
			
		||||
						$attributes["length"] = intval($matches[2]);
 | 
			
		||||
 | 
			
		||||
					if(trim($matches[4]) != "")
 | 
			
		||||
					}
 | 
			
		||||
					if (trim($matches[4]) != "") {
 | 
			
		||||
						$attributes["title"] = trim($matches[4]);
 | 
			
		||||
 | 
			
		||||
					}
 | 
			
		||||
					xml::add_element($doc, $root, "link", "", $attributes);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -2089,7 +2083,13 @@ class ostatus {
 | 
			
		|||
		if (intval($item["parent"]) > 0) {
 | 
			
		||||
			$conversation = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"];
 | 
			
		||||
			xml::add_element($doc, $entry, "link", "", array("rel" => "ostatus:conversation", "href" => $conversation));
 | 
			
		||||
			xml::add_element($doc, $entry, "ostatus:conversation", $conversation);
 | 
			
		||||
 | 
			
		||||
			$attributes = array(
 | 
			
		||||
					"href" => $conversation,
 | 
			
		||||
					"local_id" => $item["parent"],
 | 
			
		||||
					"ref" => $conversation);
 | 
			
		||||
 | 
			
		||||
			xml::add_element($doc, $entry, "ostatus:conversation", $conversation, $attributes);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$tags = item_getfeedtags($item);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,21 +3,20 @@
 | 
			
		|||
require_once('include/crypto.php');
 | 
			
		||||
require_once('include/Probe.php');
 | 
			
		||||
 | 
			
		||||
function get_salmon_key($uri,$keyhash) {
 | 
			
		||||
function get_salmon_key($uri, $keyhash) {
 | 
			
		||||
	$ret = array();
 | 
			
		||||
 | 
			
		||||
	logger('Fetching salmon key for '.$uri);
 | 
			
		||||
 | 
			
		||||
	$arr = Probe::lrdd($uri);
 | 
			
		||||
 | 
			
		||||
	if(is_array($arr)) {
 | 
			
		||||
		foreach($arr as $a) {
 | 
			
		||||
			if($a['@attributes']['rel'] === 'magic-public-key') {
 | 
			
		||||
	if (is_array($arr)) {
 | 
			
		||||
		foreach ($arr as $a) {
 | 
			
		||||
			if ($a['@attributes']['rel'] === 'magic-public-key') {
 | 
			
		||||
				$ret[] = $a['@attributes']['href'];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	} else {
 | 
			
		||||
		return '';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,11 +25,11 @@ function get_salmon_key($uri,$keyhash) {
 | 
			
		|||
 | 
			
		||||
	if (count($ret) > 0) {
 | 
			
		||||
		for ($x = 0; $x < count($ret); $x ++) {
 | 
			
		||||
			if (substr($ret[$x],0,5) === 'data:') {
 | 
			
		||||
				if (strstr($ret[$x],',')) {
 | 
			
		||||
					$ret[$x] = substr($ret[$x],strpos($ret[$x],',')+1);
 | 
			
		||||
			if (substr($ret[$x], 0, 5) === 'data:') {
 | 
			
		||||
				if (strstr($ret[$x], ',')) {
 | 
			
		||||
					$ret[$x] = substr($ret[$x], strpos($ret[$x], ',') + 1);
 | 
			
		||||
				} else {
 | 
			
		||||
					$ret[$x] = substr($ret[$x],5);
 | 
			
		||||
					$ret[$x] = substr($ret[$x], 5);
 | 
			
		||||
				}
 | 
			
		||||
			} elseif (normalise_link($ret[$x]) == 'http://') {
 | 
			
		||||
				$ret[$x] = fetch_url($ret[$x]);
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +38,7 @@ function get_salmon_key($uri,$keyhash) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	logger('Key located: ' . print_r($ret,true));
 | 
			
		||||
	logger('Key located: ' . print_r($ret, true));
 | 
			
		||||
 | 
			
		||||
	if (count($ret) == 1) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,10 +49,9 @@ function get_salmon_key($uri,$keyhash) {
 | 
			
		|||
		// have one key we'll be right.
 | 
			
		||||
 | 
			
		||||
		return $ret[0];
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	} else {
 | 
			
		||||
		foreach ($ret as $a) {
 | 
			
		||||
			$hash = base64url_encode(hash('sha256',$a));
 | 
			
		||||
			$hash = base64url_encode(hash('sha256', $a));
 | 
			
		||||
			if ($hash == $keyhash) {
 | 
			
		||||
				return $a;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -65,17 +63,17 @@ function get_salmon_key($uri,$keyhash) {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function slapper($owner,$url,$slap) {
 | 
			
		||||
function slapper($owner, $url, $slap) {
 | 
			
		||||
 | 
			
		||||
	// does contact have a salmon endpoint?
 | 
			
		||||
 | 
			
		||||
	if(! strlen($url))
 | 
			
		||||
	if (! strlen($url)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if(! $owner['sprvkey']) {
 | 
			
		||||
	if (! $owner['sprvkey']) {
 | 
			
		||||
		logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
 | 
			
		||||
		$owner['username'],$owner['uid']));
 | 
			
		||||
		$owner['username'], $owner['uid']));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,30 +85,33 @@ function slapper($owner,$url,$slap) {
 | 
			
		|||
	$data_type = 'application/atom+xml';
 | 
			
		||||
	$encoding  = 'base64url';
 | 
			
		||||
	$algorithm = 'RSA-SHA256';
 | 
			
		||||
	$keyhash   = base64url_encode(hash('sha256',salmon_key($owner['spubkey'])),true);
 | 
			
		||||
	$keyhash   = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
 | 
			
		||||
 | 
			
		||||
	// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
 | 
			
		||||
	$precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
 | 
			
		||||
 | 
			
		||||
	$precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
 | 
			
		||||
	// GNU Social format
 | 
			
		||||
	$signature   = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
 | 
			
		||||
 | 
			
		||||
	$signature   = base64url_encode(rsa_sign(str_replace('=','',$data . $precomputed),$owner['sprvkey']));
 | 
			
		||||
	// Compliant format
 | 
			
		||||
	$signature2  = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
 | 
			
		||||
 | 
			
		||||
	$signature2  = base64url_encode(rsa_sign($data . $precomputed,$owner['sprvkey']));
 | 
			
		||||
	// Old Status.net format
 | 
			
		||||
	$signature3  = base64url_encode(rsa_sign($data, $owner['sprvkey']));
 | 
			
		||||
 | 
			
		||||
	$signature3  = base64url_encode(rsa_sign($data,$owner['sprvkey']));
 | 
			
		||||
	// At first try the non compliant method that works for GNU Social
 | 
			
		||||
	$xmldata = array("me:env" => array("me:data" => $data,
 | 
			
		||||
			"@attributes" => array("type" => $data_type),
 | 
			
		||||
			"me:encoding" => $encoding,
 | 
			
		||||
			"me:alg" => $algorithm,
 | 
			
		||||
			"me:sig" => $signature,
 | 
			
		||||
			"@attributes2" => array("key_id" => $keyhash)));
 | 
			
		||||
 | 
			
		||||
	$salmon_tpl = get_markup_template('magicsig.tpl');
 | 
			
		||||
	$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
 | 
			
		||||
 | 
			
		||||
	$salmon = replace_macros($salmon_tpl,array(
 | 
			
		||||
		'$data'      => $data,
 | 
			
		||||
		'$encoding'  => $encoding,
 | 
			
		||||
		'$algorithm' => $algorithm,
 | 
			
		||||
		'$keyhash'   => $keyhash,
 | 
			
		||||
		'$signature' => $signature
 | 
			
		||||
	));
 | 
			
		||||
	$salmon = xml::from_array($xmldata, $xml, false, $namespaces);
 | 
			
		||||
 | 
			
		||||
	// slap them
 | 
			
		||||
	post_url($url,$salmon, array(
 | 
			
		||||
	post_url($url, $salmon, array(
 | 
			
		||||
		'Content-type: application/magic-envelope+xml',
 | 
			
		||||
		'Content-length: ' . strlen($salmon)
 | 
			
		||||
	));
 | 
			
		||||
| 
						 | 
				
			
			@ -120,60 +121,59 @@ function slapper($owner,$url,$slap) {
 | 
			
		|||
 | 
			
		||||
	// check for success, e.g. 2xx
 | 
			
		||||
 | 
			
		||||
	if($return_code > 299) {
 | 
			
		||||
	if ($return_code > 299) {
 | 
			
		||||
 | 
			
		||||
		logger('compliant salmon failed. Falling back to status.net hack2');
 | 
			
		||||
		logger('GNU Social salmon failed. Falling back to compliant mode');
 | 
			
		||||
 | 
			
		||||
		// Entirely likely that their salmon implementation is
 | 
			
		||||
		// non-compliant. Let's try once more, this time only signing
 | 
			
		||||
		// the data, without stripping '=' chars
 | 
			
		||||
		// Now try the compliant mode that normally isn't used for GNU Social
 | 
			
		||||
		$xmldata = array("me:env" => array("me:data" => $data,
 | 
			
		||||
				"@attributes" => array("type" => $data_type),
 | 
			
		||||
				"me:encoding" => $encoding,
 | 
			
		||||
				"me:alg" => $algorithm,
 | 
			
		||||
				"me:sig" => $signature2,
 | 
			
		||||
				"@attributes2" => array("key_id" => $keyhash)));
 | 
			
		||||
 | 
			
		||||
		$salmon = replace_macros($salmon_tpl,array(
 | 
			
		||||
			'$data'      => $data,
 | 
			
		||||
			'$encoding'  => $encoding,
 | 
			
		||||
			'$algorithm' => $algorithm,
 | 
			
		||||
			'$keyhash'   => $keyhash,
 | 
			
		||||
			'$signature' => $signature2
 | 
			
		||||
		));
 | 
			
		||||
		$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
 | 
			
		||||
 | 
			
		||||
		$salmon = xml::from_array($xmldata, $xml, false, $namespaces);
 | 
			
		||||
 | 
			
		||||
		// slap them
 | 
			
		||||
		post_url($url,$salmon, array(
 | 
			
		||||
		post_url($url, $salmon, array(
 | 
			
		||||
			'Content-type: application/magic-envelope+xml',
 | 
			
		||||
			'Content-length: ' . strlen($salmon)
 | 
			
		||||
		));
 | 
			
		||||
		$return_code = $a->get_curl_code();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		if($return_code > 299) {
 | 
			
		||||
 | 
			
		||||
			logger('compliant salmon failed. Falling back to status.net hack3');
 | 
			
		||||
 | 
			
		||||
			// Entirely likely that their salmon implementation is
 | 
			
		||||
			// non-compliant. Let's try once more, this time only signing
 | 
			
		||||
			// the data, without the precomputed blob
 | 
			
		||||
 | 
			
		||||
			$salmon = replace_macros($salmon_tpl,array(
 | 
			
		||||
				'$data'      => $data,
 | 
			
		||||
				'$encoding'  => $encoding,
 | 
			
		||||
				'$algorithm' => $algorithm,
 | 
			
		||||
				'$keyhash'   => $keyhash,
 | 
			
		||||
				'$signature' => $signature3
 | 
			
		||||
			));
 | 
			
		||||
 | 
			
		||||
			// slap them
 | 
			
		||||
			post_url($url,$salmon, array(
 | 
			
		||||
				'Content-type: application/magic-envelope+xml',
 | 
			
		||||
				'Content-length: ' . strlen($salmon)
 | 
			
		||||
			));
 | 
			
		||||
			$return_code = $a->get_curl_code();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	logger('slapper for '.$url.' returned ' . $return_code);
 | 
			
		||||
	if(! $return_code)
 | 
			
		||||
		return(-1);
 | 
			
		||||
	if(($return_code == 503) && (stristr($a->get_curl_headers(),'retry-after')))
 | 
			
		||||
		return(-1);
 | 
			
		||||
 | 
			
		||||
	if ($return_code > 299) {
 | 
			
		||||
		logger('compliant salmon failed. Falling back to old status.net');
 | 
			
		||||
 | 
			
		||||
		// Last try. This will most likely fail as well.
 | 
			
		||||
		$xmldata = array("me:env" => array("me:data" => $data,
 | 
			
		||||
				"@attributes" => array("type" => $data_type),
 | 
			
		||||
				"me:encoding" => $encoding,
 | 
			
		||||
				"me:alg" => $algorithm,
 | 
			
		||||
				"me:sig" => $signature3,
 | 
			
		||||
				"@attributes2" => array("key_id" => $keyhash)));
 | 
			
		||||
 | 
			
		||||
		$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
 | 
			
		||||
 | 
			
		||||
		$salmon = xml::from_array($xmldata, $xml, false, $namespaces);
 | 
			
		||||
 | 
			
		||||
		// slap them
 | 
			
		||||
		post_url($url, $salmon, array(
 | 
			
		||||
			'Content-type: application/magic-envelope+xml',
 | 
			
		||||
			'Content-length: ' . strlen($salmon)
 | 
			
		||||
		));
 | 
			
		||||
		$return_code = $a->get_curl_code();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger('slapper for '.$url.' returned ' . $return_code);
 | 
			
		||||
	if (! $return_code) {
 | 
			
		||||
		return(-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (($return_code == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
 | 
			
		||||
		return(-1);
 | 
			
		||||
	}
 | 
			
		||||
	return ((($return_code >= 200) && ($return_code < 300)) ? 0 : 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,7 +79,7 @@ function salmon_post(App $a) {
 | 
			
		|||
 | 
			
		||||
	$signed_data = $data  . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
 | 
			
		||||
 | 
			
		||||
	$compliant_format = str_replace('=','',$signed_data);
 | 
			
		||||
	$compliant_format = str_replace('=', '', $signed_data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// decode the data
 | 
			
		||||
| 
						 | 
				
			
			@ -115,24 +115,28 @@ function salmon_post(App $a) {
 | 
			
		|||
 | 
			
		||||
	// We should have everything we need now. Let's see if it verifies.
 | 
			
		||||
 | 
			
		||||
	$verify = rsa_verify($compliant_format,$signature,$pubkey);
 | 
			
		||||
	// Try GNU Social format
 | 
			
		||||
	$verify = rsa_verify($signed_data, $signature, $pubkey);
 | 
			
		||||
	$mode = 1;
 | 
			
		||||
 | 
			
		||||
	if(! $verify) {
 | 
			
		||||
		logger('mod-salmon: message did not verify using protocol. Trying padding hack.');
 | 
			
		||||
	    $verify = rsa_verify($signed_data,$signature,$pubkey);
 | 
			
		||||
	if (! $verify) {
 | 
			
		||||
		logger('mod-salmon: message did not verify using protocol. Trying compliant format.');
 | 
			
		||||
		$verify = rsa_verify($compliant_format, $signature, $pubkey);
 | 
			
		||||
		$mode = 2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(! $verify) {
 | 
			
		||||
		logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.');
 | 
			
		||||
	    $verify = rsa_verify($stnet_signed_data,$signature,$pubkey);
 | 
			
		||||
	if (! $verify) {
 | 
			
		||||
		logger('mod-salmon: message did not verify using padding. Trying old statusnet format.');
 | 
			
		||||
		$verify = rsa_verify($stnet_signed_data, $signature, $pubkey);
 | 
			
		||||
		$mode = 3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(! $verify) {
 | 
			
		||||
	if (! $verify) {
 | 
			
		||||
		logger('mod-salmon: Message did not verify. Discarding.');
 | 
			
		||||
		http_status_exit(400);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger('mod-salmon: Message verified.');
 | 
			
		||||
	logger('mod-salmon: Message verified with mode '.$mode);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +0,0 @@
 | 
			
		|||
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<me:env xmlns:me="http://salmon-protocol.org/ns/magic-env">
 | 
			
		||||
<me:data type="application/atom+xml">
 | 
			
		||||
{{$data}}
 | 
			
		||||
</me:data>
 | 
			
		||||
<me:encoding>{{$encoding}}</me:encoding>
 | 
			
		||||
<me:alg>{{$algorithm}}</me:alg>
 | 
			
		||||
<me:sig key_id="{{$keyhash}}">{{$signature}}</me:sig>
 | 
			
		||||
</me:env>
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue