post signatures

This commit is contained in:
friendica 2013-10-02 21:04:48 -07:00
parent 8ce09e84c6
commit 78a8d176ac
10 changed files with 147 additions and 64 deletions

View File

@ -45,7 +45,7 @@ define ( 'RED_PLATFORM', 'Red Matrix' );
define ( 'RED_VERSION', trim(file_get_contents('version.inc')) . 'R');
define ( 'ZOT_REVISION', 1 );
define ( 'DB_UPDATE_VERSION', 1076 );
define ( 'DB_UPDATE_VERSION', 1077 );
define ( 'EOL', '<br />' . "\r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
@ -497,6 +497,7 @@ define ( 'ITEM_RELAY', 0x0200); // used only in the communication lay
define ( 'ITEM_MENTIONSME', 0x0400);
define ( 'ITEM_NOCOMMENT', 0x0800); // commenting/followups are disabled
define ( 'ITEM_OBSCURED', 0x1000); // bit-mangled to protect from casual browsing by site admin
define ( 'ITEM_VERIFIED', 0x2000); // Signature verification was successful
/**
*

View File

@ -156,6 +156,12 @@ class Item extends BaseObject {
$indent = 'comment';
}
$verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message is verified') : '');
$unverified = '' ; // (($this->is_wall_to_wall() && (! ($item['item_flags'] & ITEM_VERIFIED))) ? t('Message cannot be verified') : '');
// FIXME - check this permission
if($conv->get_profile_owner() == local_user()) {
$tagger = array(
@ -210,6 +216,8 @@ class Item extends BaseObject {
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'lock' => $lock,
'verified' => $verified,
'unverified' => $unverified,
'location' => $location,
'indent' => $indent,
'owner_url' => $this->get_owner_url(),

View File

@ -638,6 +638,11 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') {
$likebuttons = false;
$shareable = false;
$verified = (($item['item_flags'] & ITEM_VERIFIED) ? t('Message is verified') : '');
$unverified = '';
$tags=array();
$terms = get_terms_oftype($item['term'],array(TERM_HASHTAG,TERM_MENTION,TERM_UNKNOWN));
if(count($terms))
@ -665,6 +670,8 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional') {
'tags' => $tags,
'hashtags' => $hashtags,
'mentions' => $mentions,
'verified' => $verified,
'unverified' => $unverified,
'txt_cats' => t('Categories:'),
'txt_folders' => t('Filed under:'),
'has_cats' => ((count($categories)) ? 'true' : ''),

View File

@ -546,6 +546,7 @@ function title_is_body($title, $body) {
function get_item_elements($x) {
// logger('get_item_elements');
$arr = array();
$arr['body'] = (($x['body']) ? htmlentities($x['body'],ENT_COMPAT,'UTF-8',false) : '');
@ -580,6 +581,9 @@ function get_item_elements($x) {
$arr['tgt_type'] = (($x['target_type']) ? htmlentities($x['target_type'], ENT_COMPAT,'UTF-8',false) : '');
$arr['comment_policy'] = (($x['comment_scope']) ? htmlentities($x['comment_scope'], ENT_COMPAT,'UTF-8',false) : 'contacts');
$arr['sig'] = (($x['signature']) ? htmlentities($x['signature'], ENT_COMPAT,'UTF-8',false) : '');
$arr['object'] = activity_sanitise($x['object']);
$arr['target'] = activity_sanitise($x['target']);
@ -590,18 +594,6 @@ function get_item_elements($x) {
$arr['item_flags'] = 0;
// if it's a private post, encrypt it in the DB.
// We have to do that here because we need to cleanse the input and prevent bad stuff from getting in,
// and we need plaintext to do that.
if(intval($arr['item_private'])) {
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
$key = get_config('system','pubkey');
if($arr['title'])
$arr['title'] = json_encode(aes_encapsulate($arr['title'],$key));
if($arr['body'])
$arr['body'] = json_encode(aes_encapsulate($arr['body'],$key));
}
if(array_key_exists('flags',$x) && in_array('deleted',$x['flags']))
$arr['item_restrict'] = ITEM_DELETED;
@ -628,6 +620,31 @@ function get_item_elements($x) {
}
if($arr['sig']) {
$r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
if($r && rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey']))
$arr['item_flags'] |= ITEM_VERIFIED;
else
logger('get_item_elements: message verification failed.');
}
// if it's a private post, encrypt it in the DB.
// We have to do that here because we need to cleanse the input and prevent bad stuff from getting in,
// and we need plaintext to do that.
if(intval($arr['item_private'])) {
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
$key = get_config('system','pubkey');
if($arr['title'])
$arr['title'] = json_encode(aes_encapsulate($arr['title'],$key));
if($arr['body'])
$arr['body'] = json_encode(aes_encapsulate($arr['body'],$key));
}
return $arr;
}
@ -656,7 +673,7 @@ function encode_item($item) {
$x = array();
$x['type'] = 'activity';
logger('encode_item: ' . print_r($item,true));
// logger('encode_item: ' . print_r($item,true));
$r = q("select channel_r_stream, channel_w_comment from channel where channel_id = %d limit 1",
intval($item['uid'])
@ -707,6 +724,7 @@ function encode_item($item) {
$x['permalink'] = $item['plink'];
$x['location'] = $item['location'];
$x['longlat'] = $item['coord'];
$x['signature'] = $item['sig'];
$x['owner'] = encode_item_xchan($item['owner']);
$x['author'] = encode_item_xchan($item['author']);
@ -730,6 +748,8 @@ function encode_item($item) {
if($item['term'])
$x['tags'] = encode_item_terms($item['term']);
logger('encode_item: ' . print_r($x,true));
return $x;
}
@ -1446,17 +1466,27 @@ function item_store($arr,$allow_exec = false) {
$arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 );
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
$arr['title'] = escape_tags($arr['title']);
// only detect language if we have text content, and if the post is private but not yet
// obscured, make it so.
if(! ($arr['item_flags'] & ITEM_OBSCURED)) {
$arr['lang'] = detect_language($arr['body']);
// apply the input filter here - if it is obscured it has been filtered already
$arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']);
if(local_user() && (! $arr['sig'])) {
$channel = get_app()->get_channel();
if($channel['channel_hash'] === $arr['author_xchan']) {
$arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
$arr['item_flags'] |= ITEM_VERIFIED;
}
}
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
@ -1767,22 +1797,6 @@ function item_store_update($arr,$allow_exec = false) {
$uid = $arr['uid'];
unset($arr['uid']);
$arr['lang'] = detect_language($arr['body']);
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
$ret['message'] = 'language not accepted';
return $ret;
}
$arr = $translate['item'];
}
$arr['mimetype'] = ((x($arr,'mimetype')) ? notags(trim($arr['mimetype'])) : 'text/bbcode');
if(($arr['mimetype'] == 'application/x-php') && (! $allow_exec)) {
@ -1791,30 +1805,60 @@ function item_store_update($arr,$allow_exec = false) {
return $ret;
}
if(! ($arr['item_flags'] & ITEM_OBSCURED)) {
// Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin.
$arr['lang'] = detect_language($arr['body']);
// apply the input filter here - if it is obscured it has been filtered already
$arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']);
if($arr['mimetype'] != 'text/html' && $arr['mimetype'] != 'application/x-php') {
if(local_user() && (! $arr['sig'])) {
$channel = get_app()->get_channel();
if($channel['channel_hash'] === $arr['author_xchan']) {
$arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
$arr['item_flags'] |= ITEM_VERIFIED;
}
}
if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
$arr['body'] = escape_tags($arr['body']);
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((x($arr,'object')) && is_array($arr['object'])) {
activity_sanitise($arr['object']);
$arr['object'] = json_encode($arr['object']);
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
$ret['message'] = 'language not accepted';
return $ret;
}
$arr = $translate['item'];
}
if($arr['item_private']) {
$key = get_config('system','pubkey');
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
if($arr['title'])
$arr['title'] = json_encode(aes_encapsulate($arr['title'],$key));
if($arr['body'])
$arr['body'] = json_encode(aes_encapsulate($arr['body'],$key));
}
if((x($arr,'target')) && is_array($arr['target'])) {
activity_sanitise($arr['target']);
$arr['target'] = json_encode($arr['target']);
}
if((x($arr,'attach')) && is_array($arr['attach'])) {
activity_sanitise($arr['attach']);
$arr['attach'] = json_encode($arr['attach']);
}
}
if((x($arr,'object')) && is_array($arr['object'])) {
activity_sanitise($arr['object']);
$arr['object'] = json_encode($arr['object']);
}
if((x($arr,'target')) && is_array($arr['target'])) {
activity_sanitise($arr['target']);
$arr['target'] = json_encode($arr['target']);
}
if((x($arr,'attach')) && is_array($arr['attach'])) {
activity_sanitise($arr['attach']);
$arr['attach'] = json_encode($arr['attach']);
}
$orig = q("select * from item where id = %d and uid = %d limit 1",
intval($orig_post_id),
intval($uid)
@ -1860,6 +1904,7 @@ function item_store_update($arr,$allow_exec = false) {
$arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : $orig[0]['item_restrict'] );
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : $orig[0]['item_flags'] );
$arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
call_hooks('post_remote_update',$arr);

View File

@ -1328,6 +1328,14 @@ function process_mail_delivery($sender,$arr,$deliveries) {
$result = array();
if($sender['hash'] != $arr['from_xchan']) {
logger('process_mail_delivery: sender is not mail author');
return;
}
foreach($deliveries as $d) {
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])

View File

@ -441,7 +441,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`resource_id` char(255) NOT NULL DEFAULT '',
`resource_type` char(16) NOT NULL DEFAULT '',
`attach` mediumtext NOT NULL,
`inform` mediumtext NOT NULL,
`sig` text NOT NULL DEFAULT '',
`location` char(255) NOT NULL DEFAULT '',
`coord` char(255) NOT NULL DEFAULT '',
`comment_policy` char(255) NOT NULL DEFAULT '',

View File

@ -1,6 +1,6 @@
<?php
define( 'UPDATE_VERSION' , 1076 );
define( 'UPDATE_VERSION' , 1077 );
/**
*
@ -859,3 +859,10 @@ ADD INDEX ( `channel_a_republish` )");
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}
function update_r1076() {
$r = q("ALTER TABLE `item` CHANGE `inform` `sig` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ");
if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}

View File

@ -588,7 +588,6 @@ function item_post(&$a) {
$datarray['app'] = $app;
$datarray['location'] = $location;
$datarray['coord'] = $coord;
$datarray['inform'] = $inform;
$datarray['verb'] = $verb;
$datarray['allow_cid'] = $str_contact_allow;
$datarray['allow_gid'] = $str_group_allow;
@ -642,6 +641,13 @@ function item_post(&$a) {
$datarray['body'] = z_input_filter($datarray['uid'],$datarray['body'],$datarray['mimetype']);
if(local_user()) {
if($channel['channel_hash'] === $datarray['author_xchan']) {
$datarray['sig'] = base64url_encode(rsa_sign($datarray['body'],$channel['channel_prvkey']));
$datarray['item_flags'] = $datarray['item_flags'] | ITEM_VERIFIED;
}
}
logger('Encrypting local storage');
$key = get_config('system','pubkey');
$datarray['item_flags'] = $datarray['item_flags'] | ITEM_OBSCURED;
@ -651,17 +657,16 @@ function item_post(&$a) {
$datarray['body'] = json_encode(aes_encapsulate($datarray['body'],$key));
}
if($orig_post) {
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `mimetype` = '%s', `attach` = '%s', `edited` = '%s', layout_mid = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `mimetype` = '%s', `attach` = '%s', `edited` = '%s', layout_mid = '%s', sig = '%s', item_flags = %d WHERE `id` = %d AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
dbesc($datarray['body']),
dbesc($datarray['mimetype']),
dbesc($datarray['attach']),
dbesc(datetime_convert()),
dbesc($layout_mid),
dbesc($datarray['sig']),
intval($item_flags),
intval($post_id),
intval($profile_uid)
);

View File

@ -454,15 +454,15 @@ function photos_post(&$a) {
if(strlen($newinform) && strlen($inform))
$newinform .= ',';
$newinform .= $inform;
$r = q("UPDATE `item` SET `tag` = '%s', `inform` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
dbesc($newtag),
dbesc($newinform),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item_id),
intval($page_owner_uid)
);
//FIXME - inform is gone
// $r = q("UPDATE `item` SET `tag` = '%s', `inform` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
// dbesc($newtag),
// dbesc($newinform),
// dbesc(datetime_convert()),
// dbesc(datetime_convert()),
// intval($item_id),
// intval($page_owner_uid)
// );
$best = 0;
foreach($p as $scales) {

View File

@ -34,6 +34,8 @@
{{if $item.lock}}<div class="wall-item-lock"><img src="images/lock_icon.gif" class="lockview" alt="{{$item.lock}}" onclick="lockview(event,{{$item.id}});" /></div>
{{else}}<div class="wall-item-lock"></div>{{/if}}
<div class="wall-item-location" id="wall-item-location-{{$item.id}}">{{$item.location}}</div>
{{if $item.verified}}<img src="images/lock_icon.gif" alt="{{$item.verified}}" title="{{$item.verified}}" height="10" width="10" />{{/if}}
{{if $item.unverified}}<img src="images/unlock_icon.gif" alt="{{$item.unverified}}" title="{{$item.unverified}}" height="10" width="10" />{{/if}}
</div>
</div>
<div class="wall-item-author">