Compare commits

..

31 Commits
5.0 ... 5.0.2

Author SHA1 Message Date
Mario
25620081a1 translation 2020-11-16 09:36:27 +00:00
Mario
0daccead12 changellog 2020-11-16 09:29:49 +00:00
Mario
e7c83a81c7 work around an edge case in acl selector 2020-11-16 09:28:18 +00:00
Mario
dcf8830752 Merge branch 'dev' 2020-11-16 08:26:44 +00:00
Mario
3d519f478a changelog 2020-11-15 13:49:25 +00:00
Mario
3f0fc40ef8 fix ping_site() 2020-11-15 13:44:13 +00:00
Mario
820494c7a6 deprecate daemon/ratenotif 2020-11-15 12:34:10 +00:00
Mario
60b82d3690 more changelog 2020-11-15 11:49:16 +00:00
Mario
57d9b1b332 fix directory post url 2020-11-15 11:48:23 +00:00
Mario
67f8b78a7d changelog 2020-11-15 11:35:26 +00:00
Mario
aada997601 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-11-15 11:03:47 +00:00
Mario
e5dd108bd7 outq_hash is unique - no need for limit 2020-11-15 11:03:17 +00:00
Mario
ad91ab68ce cleanup 2020-11-15 11:02:21 +00:00
Max Kostikov
66c3c32154 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1883
2020-11-15 11:17:59 +01:00
Max Kostikov
c9ce562369 Update hmessages.po 2020-11-15 11:10:49 +01:00
Max Kostikov
a1f01529a7 Update hstrings.php 2020-11-15 11:10:28 +01:00
Max Kostikov
38985dc4e2 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!1
2020-11-15 11:09:44 +01:00
Mario
e74c52094f remove dot 2020-11-14 21:37:49 +00:00
Mario
e05f1f95cf bump version 2020-11-14 21:31:45 +00:00
Mario
b63c5f2785 Polling fallback to server sent events. Polling is the default. SSE must be enabled in /admin/site > Advanced > Enable SSE Notifications if desired. 2020-11-14 21:28:50 +00:00
Mario
685c569eaf minor queue adjustments 2020-11-13 13:49:39 +00:00
Mario
b6e3469519 update to fix more broken hublocs and version bump 2020-11-13 09:26:04 +00:00
Mario
16071f300e better check for valid inbox 2020-11-13 09:18:54 +00:00
Mario
a8de999b7c do not store actors without an inbox - they are not valid 2020-11-12 20:17:03 +00:00
Mario
0dcbcf93c2 some work on include/import 2020-11-12 11:50:00 +00:00
Mario
06273e980e Merge branch 'dev' 2020-11-12 09:00:56 +00:00
Mario
c879e5de44 changelog and version bump 2020-11-12 08:57:51 +00:00
Mario
890290fff0 log the body if fetch failed 2020-11-11 12:10:35 +00:00
Mario
cddae14352 do not log exception - it could exhaust memory 2020-11-09 11:31:20 +00:00
Mario
b3e6a3c1e2 make share titles h3 to reflect the original titlÃe size 2020-11-08 19:07:44 +00:00
Mario
255b6a14a8 less hubloc confusion 2020-11-08 12:55:32 +00:00
31 changed files with 1258 additions and 1142 deletions

View File

@@ -1,3 +1,28 @@
Hubzilla 5.0.2 (2020-11-16)
- Fix edge case in acl selector
- Fix ping_site()
- Fix directory post url
- Update russian translation
- Implement polling for notifications (default) - SSE can be enabled in /admin/site if desired
- DB update to remove hublocs with no hubloc_hash or no hubloc_callback
- Do not save actors without an inbox
- Fix import_hublocs()
Addons
- Pubcrawl: do not save actors without an inbox
- Diaspora: fix issue with diaspora where hublocs without hubloc_hash were stored
Hubzilla 5.0.1 (2020-11-12)
- Fix share title size
- Fix issue where hublocs could get mixed up between different protocols
Addons
- Pubcrawl: implement authenticated profile fetches which are now partly required in mastodon
- Sse: call xchan_query() just once per item
- Pubcrawl: reject messages where sender is not the author if ld-signature is not ok
Hubzilla 5.0 (2020-11-05)
- Remove unmaintained and deprecated schemas
- Deprecate HTML5_Parser library

View File

@@ -2,8 +2,7 @@
namespace Zotlabs\Daemon;
require_once('include/zot.php');
require_once('include/hubloc.php');
class Checksites {

View File

@@ -2,12 +2,8 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\DReport;
require_once('include/zot.php');
require_once('include/queue_fn.php');
class Deliver {
static public function run($argc,$argv) {
@@ -22,72 +18,16 @@ class Deliver {
if(! $argv[$x])
continue;
$dresult = null;
$r = q("select * from outq where outq_hash = '%s' limit 1",
$r = q("select * from outq where outq_hash = '%s'",
dbesc($argv[$x])
);
if($r) {
$notify = json_decode($r[0]['outq_notify'],true);
// Messages without an outq_msg will need to go via the web, even if it's a
// local delivery. This includes conversation requests and refresh packets.
if(($r[0]['outq_posturl'] === z_root() . '/post') && ($r[0]['outq_msg'])) {
logger('deliver: local delivery', LOGGER_DEBUG);
// local delivery
// we should probably batch these and save a few delivery processes
if($r[0]['outq_msg']) {
$m = json_decode($r[0]['outq_msg'],true);
if(array_key_exists('message_list',$m)) {
foreach($m['message_list'] as $mm) {
$msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $mm)))));
zot_import($msg,z_root());
}
}
else {
$msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m)))));
$dresult = zot_import($msg,z_root());
}
remove_queue_item($r[0]['outq_hash']);
if($dresult && is_array($dresult)) {
// delivery reports for local deliveries do not require encryption
foreach($dresult as $xx) {
if(is_array($xx) && array_key_exists('message_id',$xx)) {
if(DReport::is_storable($xx)) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
dbesc($xx['message_id']),
dbesc($xx['location']),
dbesc($xx['recipient']),
dbesc(($xx['name']) ? $xx['name'] : EMPTY_STR),
dbesc($xx['status']),
dbesc(datetime_convert($xx['date'])),
dbesc($xx['sender'])
);
}
}
}
}
q("delete from dreport where dreport_queue = '%s'",
dbesc($argv[$x])
);
continue;
}
}
// otherwise it's a remote delivery - call queue_deliver() with the $immediate flag
queue_deliver($r[0],true);
}
}
}
}

View File

@@ -58,7 +58,8 @@ class Directory {
// otherwise send the changes upstream
$directory = Libzotdir::find_upstream_directory($dirmode);
$url = $directory['url'] . '/post';
$url = $directory['url'] . '/zot';
// ensure the upstream directory is updated

View File

@@ -4,6 +4,7 @@ namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Queue;
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
@@ -734,15 +735,17 @@ class Notifier {
}
if($packet) {
queue_insert(array(
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
'driver' => $hub['hubloc_network'],
'notify' => $packet,
'msg' => (($pmsg) ? json_encode($pmsg) : '')
));
Queue::insert(
[
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
'driver' => $hub['hubloc_network'],
'notify' => $packet,
'msg' => (($pmsg) ? json_encode($pmsg) : '')
]
);
}
else {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
@@ -803,7 +806,7 @@ class Notifier {
}
}
queue_insert(
Queue::insert(
[
'hash' => $hash,
'account_id' => $target_item['aid'],

View File

@@ -10,6 +10,11 @@ class Ratenotif {
static public function run($argc,$argv) {
// Deprecated
return;
require_once("datetime.php");
require_once('include/items.php');

View File

@@ -104,6 +104,7 @@ class Activity {
}
else {
logger('fetch failed: ' . $url);
logger($x['body']);
}
return null;
}
@@ -1492,6 +1493,14 @@ class Activity {
if(! is_array($person_obj))
return;
$inbox = $person_obj['inbox'];
// invalid identity
if (! $inbox || strpos($inbox,z_root()) !== false) {
return;
}
$name = $person_obj['name'];
if(! $name)
$name = $person_obj['preferredUsername'];
@@ -1539,8 +1548,6 @@ class Activity {
$profile = $url;
}
$inbox = $person_obj['inbox'];
$collections = [];
if($inbox) {

View File

@@ -51,7 +51,7 @@ class JSalmon {
. base64url_encode($x['encoding'],true) . '.'
. base64url_encode($x['alg'],true);
$key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id']));
$key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id']));
logger('key: ' . print_r($key,true));
if($key['portable_id'] && $key['public_key']) {
if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {

View File

@@ -93,7 +93,8 @@ class LDSignatures {
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
}
catch (\Exception $e) {
logger('normalise error:' . print_r($e,true));
// Don't log the exception - this can exhaust memory
// logger('normalise error:' . print_r($e,true));
logger('normalise error: ' . print_r($data,true));
}

View File

@@ -133,7 +133,7 @@ class Share {
"' message_id='" . $this->item['mid'] .
"']";
if($this->item['title'])
$bb .= '[b]'.$this->item['title'].'[/b]'."\r\n";
$bb .= '[h3][b]'.$this->item['title'].'[/b][/h3]'."\r\n";
$bb .= (($is_photo) ? $photo_bb . "\r\n" . $this->item['body'] : $this->item['body']);
$bb .= "[/share]";
}

View File

@@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig;
class Zotfinger {
static function exec($resource,$channel = null) {
static function exec($resource,$channel = null, $verify = true) {
if(! $resource) {
return false;
@@ -41,8 +41,9 @@ class Zotfinger {
logger('fetch: ' . print_r($x,true));
if($x['success']) {
$result['signature'] = HTTPSig::verify($x);
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');
}
$result['data'] = json_decode($x['body'],true);

View File

@@ -62,6 +62,9 @@ class Site {
$from_email = ((array_key_exists('from_email',$_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . \App::get_hostname());
$from_email_name = ((array_key_exists('from_email_name',$_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : \Zotlabs\Lib\System::get_site_name());
$sse_enabled = ((x($_POST,'sse_enabled')) ? true : false);
$verifyssl = ((x($_POST,'verifyssl')) ? True : False);
$proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : '');
$proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : '');
@@ -151,6 +154,9 @@ class Site {
set_config('system','no_community_page', $no_community_page);
set_config('system','no_utf', $no_utf);
set_config('system','sse_enabled', $sse_enabled);
set_config('system','verifyssl', $verifyssl);
set_config('system','proxyuser', $proxyuser);
set_config('system','proxy', $proxy);
@@ -331,6 +337,8 @@ class Site {
'$directory_server' => (($dir_choices) ? array('directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices) : null),
'$sse_enabled' => array('sse_enabled', t('Enable SSE Notifications'), get_config('system', 'sse_enabled', 0), t('If disabled, traditional polling will be used. Warning: this setting might not be suited for shared hosting')),
'$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""),
'$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""),
'$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")),

View File

@@ -60,7 +60,7 @@ class Channel extends Controller {
if(Libzot::is_zot_request()) {
$sigdata = HTTPSig::verify(file_get_contents('php://input'));
$sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6');
if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ]));

View File

@@ -294,8 +294,8 @@ class Connedit extends Controller {
intval($channel['channel_id'])
);
if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) {
$xarr = array();
$xarr['verb'] = ACTIVITY_FRIEND;
$xarr = [];
$xarr['item_wall'] = 1;
$xarr['item_origin'] = 1;
$xarr['item_thread_top'] = 1;
@@ -305,17 +305,6 @@ class Connedit extends Controller {
$xarr['deny_cid'] = $channel['channel_deny_cid'];
$xarr['deny_gid'] = $channel['channel_deny_gid'];
$xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0);
$obj = array(
'type' => ACTIVITY_OBJ_PERSON,
'title' => App::$poi['xchan_name'],
'id' => App::$poi['xchan_hash'],
'link' => array(
array('rel' => 'alternate', 'type' => 'text/html', 'href' => App::$poi['xchan_url']),
array('rel' => 'photo', 'type' => App::$poi['xchan_photo_mimetype'], 'href' => App::$poi['xchan_photo_l'])
),
);
$xarr['obj'] = json_encode($obj);
$xarr['obj_type'] = ACTIVITY_OBJ_PERSON;
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]';

View File

@@ -14,6 +14,7 @@ class Sse extends Controller {
public static $ob_hash;
public static $sse_id;
public static $vnotify;
public static $sse_enabled;
function init() {
@@ -49,18 +50,86 @@ class Sse extends Controller {
$sys = get_sys_channel();
$sleep_seconds = 3;
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
header("X-Accel-Buffering: no");
self::$sse_enabled = get_config('system', 'sse_enabled', 0);
while(true) {
if(self::$sse_enabled) {
/**
* Update chat presence indication (if applicable)
*/
// Server Sent Events
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
header("X-Accel-Buffering: no");
while(true) {
if(! self::$sse_id) {
// Update chat presence indication
$r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1",
dbesc(self::$ob_hash),
dbesc($_SERVER['REMOTE_ADDR'])
);
$basic_presence = false;
if($r) {
$basic_presence = true;
q("update chatpresence set cp_last = '%s' where cp_id = %d",
dbesc(datetime_convert()),
intval($r[0]['cp_id'])
);
}
if(! $basic_presence) {
q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client)
values( '%s', '%s', '%s', '%s' ) ",
dbesc(self::$ob_hash),
dbesc(datetime_convert()),
dbesc('online'),
dbesc($_SERVER['REMOTE_ADDR'])
);
}
}
XConfig::Load(self::$ob_hash);
$result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []);
$lock = XConfig::Get(self::$ob_hash, 'sse', 'lock');
if($result && !$lock) {
echo "event: notifications\n";
echo 'data: ' . json_encode($result);
echo "\n\n";
XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
unset($result);
}
// always send heartbeat to detect disconnected clients
echo "event: heartbeat\n";
echo 'data: {}';
echo "\n\n";
ob_end_flush();
flush();
if(connection_status() != CONNECTION_NORMAL || connection_aborted()) {
//TODO: this does not seem to be triggered
XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE);
break;
}
sleep($sleep_seconds);
}
}
else {
// Fallback to traditional polling
if(! self::$sse_id) {
// Update chat presence indication
$r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1",
dbesc(self::$ob_hash),
dbesc($_SERVER['REMOTE_ADDR'])
@@ -90,29 +159,11 @@ class Sse extends Controller {
$lock = XConfig::Get(self::$ob_hash, 'sse', 'lock');
if($result && !$lock) {
echo "event: notifications\n";
echo 'data: ' . json_encode($result);
echo "\n\n";
XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
unset($result);
json_return_and_die($result);
}
// always send heartbeat to detect disconnected clients
echo "event: heartbeat\n";
echo 'data: {}';
echo "\n\n";
ob_end_flush();
flush();
if(connection_status() != CONNECTION_NORMAL || connection_aborted()) {
//TODO: this does not seem to be triggered
XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE);
break;
}
sleep($sleep_seconds);
killme();
}

View File

@@ -34,7 +34,7 @@ class Zot_probe extends \Zotlabs\Web\Controller {
$o .= '<pre>' . htmlspecialchars($x['header']) . '</pre>' . EOL;
$o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x),true)) . EOL;
$o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x, EMPTY_STR, 'zot6'),true)) . EOL;
$o .= '<pre>' . htmlspecialchars(json_encode(json_decode($x['body']),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '</pre>' . EOL;

27
Zotlabs/Update/_1239.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
namespace Zotlabs\Update;
class _1239 {
function run() {
dbq("START TRANSACTION");
// remove broken activitypub hubloc entries
$r = dbq("DELETE FROM hubloc WHERE hubloc_network = 'activitypub' and hubloc_callback = ''");
// remove broken hubloc entries from friendica
$r1 = dbq("DELETE FROM hubloc WHERE hubloc_hash = ''");
if($r && $r1) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

View File

@@ -76,7 +76,7 @@ class HTTPSig {
// See draft-cavage-http-signatures-10
static function verify($data,$key = '') {
static function verify($data,$key = '', $keytype = '') {
$body = $data;
$headers = null;
@@ -151,7 +151,7 @@ class HTTPSig {
$result['signer'] = $sig_block['keyId'];
$key = self::get_key($key,$result['signer']);
$key = self::get_key($key,$keytype,$result['signer']);
if(! ($key && $key['public_key'])) {
return $result;
@@ -162,13 +162,26 @@ class HTTPSig {
logger('verified: ' . $x, LOGGER_DEBUG);
if(! $x) {
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
$sig_block['signature'] = base64_encode($sig_block['signature']);
logger('affected sigblock: ' . print_r($sig_block,true));
logger('signed_data: ' . print_r($signed_data,true));
logger('headers: ' . print_r($headers,true));
logger('server: ' . print_r($_SERVER,true));
return $result;
// try again, ignoring the local actor (xchan) cache and refetching the key
// from its source
$fkey = self::get_key($key,$keytype,$result['signer'],true);
if ($fkey && $fkey['public_key']) {
$y = rsa_verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm);
logger('verified: (cache reload) ' . $x, LOGGER_DEBUG);
}
if (! $y) {
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key'));
$sig_block['signature'] = base64_encode($sig_block['signature']);
logger('affected sigblock: ' . print_r($sig_block,true));
logger('headers: ' . print_r($headers,true));
logger('server: ' . print_r($_SERVER,true));
return $result;
}
}
$result['portable_id'] = $key['portable_id'];
@@ -187,12 +200,17 @@ class HTTPSig {
}
logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
if (! $result['content_valid']) {
logger('invalid content signature: data ' . print_r($data,true));
logger('invalid content signature: headers ' . print_r($headers,true));
logger('invalid content signature: body ' . print_r($body,true));
}
}
return $result;
}
static function get_key($key,$id) {
static function get_key($key,$keytype,$id) {
if($key) {
if(function_exists($key)) {
@@ -201,6 +219,13 @@ class HTTPSig {
return [ 'public_key' => $key ];
}
if($keytype === 'zot6') {
$key = self::get_zotfinger_key($id,$force);
if($key) {
return $key;
}
}
if(strpos($id,'#') === false) {
$key = self::get_webfinger_key($id);
}
@@ -243,7 +268,7 @@ class HTTPSig {
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'",
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network in ('zot6', 'activitypub')",
dbesc(str_replace('acct:','',$url)),
dbesc($url)
);
@@ -303,18 +328,15 @@ class HTTPSig {
return (($key['public_key']) ? $key : false);
}
function get_zotfinger_key($id) {
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'",
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network = 'zot6'",
dbesc(str_replace('acct:','',$id)),
dbesc($id)
);
$x = Libzot::zot_record_preferred($x);
if($x && $x['xchan_pubkey']) {
return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ];
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
$wf = Webfinger::exec($id);
@@ -330,13 +352,18 @@ class HTTPSig {
continue;
}
if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) {
$z = \Zotlabs\Lib\Zotfinger::exec($l['href']);
// The third argument to Zotfinger::exec() tells it not to verify signatures
// Since we're inside a function that is fetching keys with which to verify signatures,
// this is necessary to prevent infinite loops.
$z = \Zotlabs\Lib\Zotfinger::exec($l['href'],null,false);
if($z) {
$i = Libzot::import_xchan($z['data']);
if($i['success']) {
$key['portable_id'] = $i['hash'];
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' and hubloc_network = 'zot6'",
dbesc($l['href'])
);
if($x) {
@@ -485,7 +512,6 @@ class HTTPSig {
if(preg_match('/iv="(.*?)"/ism',$header,$matches))
$header = self::decrypt_sigheader($header);
if(preg_match('/keyId="(.*?)"/ism',$header,$matches))
$ret['keyId'] = $matches[1];
if(preg_match('/algorithm="(.*?)"/ism',$header,$matches))

View File

@@ -155,7 +155,7 @@ class Receiver {
$result = false;
$this->sigdata = HTTPSig::verify($this->rawdata);
$this->sigdata = HTTPSig::verify($this->rawdata, EMPTY_STR, 'zot6');
if ($this->sigdata && $this->sigdata['header_signed'] && $this->sigdata['header_valid']) {
$result = true;

View File

@@ -50,10 +50,10 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '5.0' );
define ( 'STD_VERSION', '5.0.2' );
define ( 'ZOT_REVISION', '6.0' );
define ( 'DB_UPDATE_VERSION', 1238 );
define ( 'DB_UPDATE_VERSION', 1239 );
define ( 'PROJECT_BASE', __DIR__ );
@@ -1207,6 +1207,7 @@ class App {
'$metas' => self::$meta->get(),
'$plugins' => $x['header'],
'$update_interval' => $interval,
'$sse_enabled' => get_config('system', 'sse_enabled', 0),
'$head_css' => head_get_css(),
'$head_js' => head_get_js(),
'$linkrel' => head_get_links(),

View File

@@ -288,30 +288,18 @@ function locations_by_netid($netid) {
function ping_site($url) {
$ret = array('success' => false);
$ret = array('success' => false);
$sys = get_sys_channel();
$m = zot_build_packet($sys, 'ping');
$r = zot_zot($url . '/post', $m);
if(! $r['success']) {
$ret['message'] = 'no answer from ' . $url;
return $ret;
}
$packet_result = json_decode($r['body'], true);
if(! $packet_result['success']) {
$ret['message'] = 'packet failure from ' . $url;
return $ret;
}
if($packet_result['success']) {
$ret['success'] = true;
}
else {
$ret['message'] = 'unknown error from ' . $url;
}
$r = Zotlabs\Lib\Zotfinger::exec($url);
if(! $r['data']) {
$ret['message'] = 'no answer from ' . $url;
return $ret;
}
$ret['success'] = true;
return $ret;
}

View File

@@ -210,17 +210,24 @@ function import_hublocs($channel, $hublocs, $seize, $moving = false) {
if($channel && $hublocs) {
foreach($hublocs as $hubloc) {
$hash = make_xchan_hash($hubloc['hubloc_guid'],$hubloc['hubloc_guid_sig']);
if($hubloc['hubloc_network'] === 'zot' && $hash !== $hubloc['hubloc_hash']) {
logger('forged hubloc: ' . print_r($hubloc,true));
continue;
}
// verify the hash. We can only do this if we already stored the xchan corresponding to this hubloc
// as we need the public key from there
if(! array_key_exists('hubloc_primary',$hubloc)) {
$hubloc['hubloc_primary'] = (($hubloc['hubloc_flags'] & 0x0001) ? 1 : 0);
$hubloc['hubloc_orphancheck'] = (($hubloc['hubloc_flags'] & 0x0004) ? 1 : 0);
$hubloc['hubloc_error'] = (($hubloc['hubloc_status'] & 0x0003) ? 1 : 0);
$hubloc['hubloc_deleted'] = (($hubloc['hubloc_flags'] & 0x1000) ? 1 : 0);
if ($hubloc['hubloc_network'] === 'zot6') {
$x = q("select xchan_pubkey from xchan where xchan_guid = '%s' and xchan_hash = '%s'",
dbesc($hubloc['hubloc_guid']),
dbesc($hubloc['hubloc_hash'])
);
if (! $x) {
logger('hubloc could not be verified. ' . print_r($hubloc,true));
continue;
}
$hash = Libzot::make_xchan_hash($hubloc['hubloc_guid'],$x[0]['xchan_pubkey']);
if ($hash !== $hubloc['hubloc_hash']) {
logger('forged hubloc: ' . print_r($hubloc,true));
continue;
}
}
if($moving && $hubloc['hubloc_hash'] === $channel['channel_hash'] && $hubloc['hubloc_url'] !== z_root()) {
@@ -228,17 +235,17 @@ function import_hublocs($channel, $hublocs, $seize, $moving = false) {
}
$arr = [
'guid' => $hubloc['hubloc_guid'],
'guid_sig' => $hubloc['hubloc_guid_sig'],
'url' => $hubloc['hubloc_url'],
'url_sig' => $hubloc['hubloc_url_sig'],
'sitekey' => ((array_key_exists('hubloc_sitekey',$hubloc)) ? $hubloc['hubloc_sitekey'] : '')
'id' => $hubloc['hubloc_guid'],
'id_sig' => $hubloc['hubloc_guid_sig'],
'location' => $hubloc['hubloc_url'],
'location_sig' => $hubloc['hubloc_url_sig']
];
if(($hubloc['hubloc_hash'] === $channel['channel_hash']) && intval($hubloc['hubloc_primary']) && ($seize))
if (($hubloc['hubloc_hash'] === $channel['channel_hash']) && intval($hubloc['hubloc_primary']) && ($seize)) {
$hubloc['hubloc_primary'] = 0;
}
if(($x = zot_gethub($arr,false)) === false) {
if (($x = Libzot::gethub($arr,false)) === false) {
unset($hubloc['hubloc_id']);
hubloc_store_lowlevel($hubloc);
}
@@ -1333,7 +1340,7 @@ function sync_files($channel, $files) {
'time' => $time,
'resource' => $att['hash'],
'revision' => 0,
'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey']))
'signature' => Libzot::sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])
);
$store_path = $newfname;
@@ -1419,7 +1426,7 @@ function sync_files($channel, $files) {
'time' => $time,
'resource' => $p['resource_id'],
'revision' => 0,
'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])),
'signature' => Libzot::sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey']),
'resolution' => intval($p['imgscale'])
);

View File

@@ -2,6 +2,7 @@
use Zotlabs\Lib\Zotfinger;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Queue;
/**
* @file include/network.php
@@ -1437,10 +1438,10 @@ function do_delivery($deliveries, $force = false) {
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300)) && (! $force)) {
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000)) && (! $force)) {
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
foreach($deliveries as $d) {
update_queue_item($d);
Queue::update($d);
}
return;
}

View File

@@ -3452,7 +3452,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000))) {
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
update_queue_item($hash);
continue;
@@ -4286,7 +4286,7 @@ function zot_reply_message_request($data) {
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000))) {
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
update_queue_item($hash);
continue;

View File

@@ -23,10 +23,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Language: es_ES\n"
"Plural-Forms: nplurals=2; plural=(n != 1 ? 1 : 0);\n"
#: ../../view/theme/redbasic/php/config.php:15 ../../include/text.php:3231
#: ../../Zotlabs/Module/Admin/Site.php:187
msgid "Default"
msgstr "Predeterminado"
#: ../../view/theme/redbasic/php/config.php:15
#: ../../addon/cart/submodules/orderoptions.php:335

View File

@@ -340,7 +340,13 @@ ACL.prototype.update_view = function(value) {
that.list.hide(); //hide acl-list
that.info.hide(); //show acl-info
that.selected_id = that.contact_ids[that.allow_cid[0]];
that.update_select('\\^' + that.selected_id);
if(that.acl_select.find('option[id="\\^' + that.selected_id + '"]').length === 0) {
that.update_view('custom');
}
else {
that.update_select('\\^' + that.selected_id);
}
/* jot acl */
$('#jot-perms-icon, #dialog-perms-icon, #' + that.form_id[0].id + ' .jot-perms-icon').removeClass('fa-unlock').addClass('fa-lock');

View File

@@ -31,6 +31,7 @@ var sse_offset = 0;
var sse_type;
var sse_partial_result = false;
var sse_rmids = [];
var sse_fallback_interval;
var page_cache = {};
@@ -94,37 +95,56 @@ $(document).ready(function() {
jQuery.timeago.settings.allowFuture = true;
if(typeof(window.SharedWorker) === 'undefined') {
// notifications with multiple tabs open will not work very well in this scenario
var evtSource = new EventSource('/sse');
evtSource.addEventListener('notifications', function(e) {
var obj = JSON.parse(e.data);
sse_handleNotifications(obj, false, false);
}, false);
if(sse_enabled) {
if(typeof(window.SharedWorker) === 'undefined') {
// notifications with multiple tabs open will not work very well in this scenario
var evtSource = new EventSource('/sse');
document.addEventListener('visibilitychange', function() {
if (!document.hidden) {
sse_offset = 0;
sse_bs_init();
evtSource.addEventListener('notifications', function(e) {
var obj = JSON.parse(e.data);
sse_handleNotifications(obj, false, false);
}, false);
document.addEventListener('visibilitychange', function() {
if (!document.hidden) {
sse_offset = 0;
sse_bs_init();
}
}, false);
}
else {
var myWorker = new SharedWorker('/view/js/sse_worker.js', localUser);
myWorker.port.onmessage = function(e) {
obj = e.data;
console.log(obj);
sse_handleNotifications(obj, false, false);
}
}, false);
myWorker.onerror = function(e) {
myWorker.port.close();
}
myWorker.port.start();
}
}
else {
var myWorker = new SharedWorker('/view/js/sse_worker.js', localUser);
if (!document.hidden)
sse_fallback_interval = setInterval(sse_fallback, updateInterval);
myWorker.port.onmessage = function(e) {
obj = e.data;
console.log(obj);
sse_handleNotifications(obj, false, false);
}
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
clearInterval(sse_fallback_interval);
}
else {
sse_offset = 0;
sse_bs_init();
sse_fallback_interval = setInterval(sse_fallback, updateInterval);
}
myWorker.onerror = function(e) {
myWorker.port.close();
}
myWorker.port.start();
}, false);
}
$('.notification-link').on('click', { replace: true, followup: false }, sse_bs_notifications);
@@ -224,6 +244,8 @@ $(document).ready(function() {
cache_next_page();
});
});
function getConversationSettings() {
@@ -1763,8 +1785,6 @@ function sse_bs_init() {
}
function sse_bs_counts() {
if(sse_bs_active)
return;
@@ -2022,3 +2042,15 @@ function sse_setNotificationsStatus() {
}
}
function sse_fallback() {
$.get('/sse', function(obj) {
if(! obj)
return;
console.log('sse fallback');
console.log(obj);
sse_handleNotifications(obj, false, false);
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -403,7 +403,6 @@ App::$strings["PHP"] = "";
App::$strings["Page content type"] = "Тип содержимого страницы";
App::$strings["photo"] = "фото";
App::$strings["event"] = "событие";
App::$strings["status"] = "статус";
App::$strings["comment"] = "комментарий";
App::$strings["activity"] = "активность";
App::$strings["poll"] = "голосование";
@@ -707,7 +706,7 @@ App::$strings["%d years"] = array(
App::$strings["timeago.prefixAgo"] = "";
App::$strings["timeago.prefixFromNow"] = "через";
App::$strings["timeago.suffixAgo"] = "назад";
App::$strings["timeago.suffixFromNow"] = "";
App::$strings["timeago.suffixFromNow"] = "NONE";
App::$strings["less than a minute"] = "менее чем одну минуту";
App::$strings["about a minute"] = "около минуты";
App::$strings["about an hour"] = "около часа";
@@ -803,13 +802,15 @@ App::$strings["__ctx:relative_date__ second"] = array(
App::$strings["%1\$s's birthday"] = "День рождения %1\$s";
App::$strings["Happy Birthday %1\$s"] = "С Днем рождения %1\$s !";
App::$strings["Visible to your default audience"] = "Видно вашей аудитории по умолчанию.";
App::$strings["__ctx:acl__ Profile"] = "Профиль";
App::$strings["Profile-Based Privacy Groups"] = "Группы конфиденциальности основанные на профиле";
App::$strings["Forums"] = "Форумы";
App::$strings["Private Forum"] = "Частный форум";
App::$strings["Only me"] = "Только мне";
App::$strings["Who can see this?"] = "Кто может это видеть?";
App::$strings["Share with"] = "Поделиться с";
App::$strings["Custom selection"] = "Настраиваемый выбор";
App::$strings["Select \"Show\" to allow viewing. \"Don't show\" lets you override and limit the scope of \"Show\"."] = "Нажмите \"Показать\" чтобы разрешить просмотр. \"Не показывать\" позволит вам переопределить и ограничить область показа.";
App::$strings["Show"] = "Показать";
App::$strings["Don't show"] = "Не показывать";
App::$strings["Select \"Allow\" to allow viewing. \"Don't allow\" lets you override and limit the scope of \"Allow\"."] = "Выберите \"Разрешить\" для разрешения просмотра. \"Не разрешать\" позволяет вам переопределить и ограничить разрешения.";
App::$strings["Allow"] = "Разрешить";
App::$strings["Don't allow"] = "Не разрешать";
App::$strings["Permissions"] = "Разрешения";
App::$strings["Close"] = "Закрыть";
App::$strings["Post permissions %s cannot be changed %s after a post is shared.</br />These permissions set who is allowed to view the post."] = "Разрешения публикации %s не могут быть изменены %s после того, как ею поделились. Эти разрешения устанавливают кому разрешено просматривать эту публикацию.";
@@ -1007,6 +1008,7 @@ App::$strings["Validation token"] = "Проверочный токен";
App::$strings["No channel."] = "Канала нет.";
App::$strings["No connections in common."] = "Общих контактов нет.";
App::$strings["View Common Connections"] = "Просмотр общий контактов";
App::$strings["__ctx:acl__ Profile"] = "Профиль";
App::$strings["network"] = "сеть";
App::$strings["Unable to locate original post."] = "Не удалось найти оригинальную публикацию.";
App::$strings["Empty post discarded."] = "Пустая публикация отклонена.";
@@ -1345,7 +1347,6 @@ App::$strings["Failed to remove event"] = "Не удалось удалить с
App::$strings["Unknown App"] = "Неизвестное приложение";
App::$strings["Authorize"] = "Авторизовать";
App::$strings["Do you authorize the app %s to access your channel data?"] = "Авторизуете ли вы приложение %s для доступа к данным вашего канала?";
App::$strings["Allow"] = "Разрешить";
App::$strings["Deny"] = "Запретить";
App::$strings["Public Stream App"] = "Приложение \"Публичный поток\"";
App::$strings["The unmoderated public stream of this hub"] = "Немодерируемый публичный поток с этого хаба";
@@ -1686,6 +1687,7 @@ App::$strings["Invalid request."] = "Неверный запрос.";
App::$strings["thing"] = "предмет";
App::$strings["Channel unavailable."] = "Канал недоступен.";
App::$strings["Previous action reversed."] = "Предыдущее действие отменено.";
App::$strings["status"] = "статус";
App::$strings["%1\$s agrees with %2\$s's %3\$s"] = "%1\$s согласен с %2\$s %3\$s";
App::$strings["%1\$s doesn't agree with %2\$s's %3\$s"] = "%1\$s не согласен с %2\$s %3\$s";
App::$strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = "%1\$s воздерживается от решения по %2\$s%3\$s";
@@ -1701,7 +1703,8 @@ App::$strings["My Bookmarks"] = "Мои закладки";
App::$strings["My Connections Bookmarks"] = "Закладки моих контактов";
App::$strings["Update to Hubzilla 5.0 step 2"] = "Обновление Hubzilla 5.0, этап 2";
App::$strings["To complete the update please run"] = "Для завершения обновления пожалуйста выполните";
App::$strings["INFO: this command can take a very long time depending on your DB size."] = "К сведению: эта команда может выполняться очень долго в зависимости от размеры базы данных.";
App::$strings["php util/z6convert.php"] = "";
App::$strings["from the terminal."] = "из терминала.";
App::$strings["Item not available."] = "Элемент недоступен.";
App::$strings["Remote Diagnostics App"] = "Приложение \"Удалённая диагностика\"";
App::$strings["Perform diagnostics on remote channels"] = "Производит диагностику удалённых каналов";
@@ -1711,8 +1714,6 @@ App::$strings["Channel removals are not allowed within 48 hours of changing the
App::$strings["Remove This Channel"] = "Удалить этот канал";
App::$strings["This channel will be completely removed from the network. "] = "Этот канал будет полностью удалён из сети. ";
App::$strings["This action is permanent and can not be undone!"] = "Это действие необратимо и не может быть отменено!";
App::$strings["Remove this channel and all its clones from the network"] = "Удалить этот канал и все его клоны из сети";
App::$strings["By default only the instance of the channel located on this hub will be removed from the network"] = "По умолчанию только представление канала расположенное на данном хабе будет удалено из сети";
App::$strings["Unable to update menu."] = "Невозможно обновить меню.";
App::$strings["Unable to create menu."] = "Невозможно создать меню.";
App::$strings["Menu Name"] = "Название меню";
@@ -2028,6 +2029,8 @@ App::$strings["Sender (From) email address for system generated email."] = "Ад
App::$strings["Name of email sender for system generated email."] = "Имя отправителя для генерируемых системой сообщений.";
App::$strings["Directory Server URL"] = "URL сервера каталогов";
App::$strings["Default directory server"] = "Сервер каталогов по умолчанию";
App::$strings["Enable SSE Notifications"] = "Включить уведомления SSE";
App::$strings["If disabled, traditional polling will be used. Warning: this setting might not be suited for shared hosting"] = "Если выключено будет использоваться традиционный периодический опрос. Предупреждение: этот режим не подходит для виртуального (shared) хостинга";
App::$strings["Proxy user"] = "Имя пользователя proxy-сервера";
App::$strings["Proxy URL"] = "URL proxy-сервера";
App::$strings["Network timeout"] = "Время ожидания сети";
@@ -2453,7 +2456,6 @@ App::$strings["Move this channel (disable all previous locations)"] = "Пере
App::$strings["Use this channel nickname instead of the one provided"] = "Использовать псевдоним этого канала вместо предоставленного";
App::$strings["Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site."] = "Оставьте пустым для сохранения существующего псевдонима канала. Вам будет случайным образом назначен похожий псевдоним если такое имя уже выделено на этом сайте.";
App::$strings["This process may take several minutes to complete. Please submit the form only once and leave this page open until finished."] = "Процесс может занять несколько минут. Пожалуйста, отправьте форму только один раз и оставьте эту страницу открытой до завершения.";
App::$strings["Hub not found."] = "Узел не найден.";
App::$strings["Warning: Database versions differ by %1\$d updates."] = "Предупреждение: Версия базы данных отличается от %1\$d обновления.";
App::$strings["Import completed"] = "Импорт завершён.";
App::$strings["Import Items"] = "Импортировать объекты";
@@ -2474,8 +2476,6 @@ App::$strings["Add Card"] = "Добавить карточку";
App::$strings["Account removals are not allowed within 48 hours of changing the account password."] = "Удаление канала не разрешается в течении 48 часов после смены пароля у аккаунта.";
App::$strings["Remove This Account"] = "Удалить этот аккаунт";
App::$strings["This account and all its channels will be completely removed from the network. "] = "Этот аккаунт и все его каналы будут полностью удалены из сети.";
App::$strings["Remove this account, all its channels and all its channel clones from the network"] = "Удалить этот аккаунт, все его каналы и их клоны из сети.";
App::$strings["By default only the instances of the channels located on this hub will be removed from the network"] = "По умолчанию только представление канала расположенное на данном хабе будет удалено из сети";
App::$strings["Unable to find your hub."] = "Невозможно найти ваш сервер";
App::$strings["Post successful."] = "Успешно опубликовано.";
App::$strings["Authentication failed."] = "Ошибка аутентификации.";
@@ -2497,7 +2497,6 @@ App::$strings["Visit your channel homepage"] = "Посетить страниц
App::$strings["View your connections and/or add somebody whose address you already know"] = "Просмотреть ваши контакты и / или добавить кого-то чей адрес в уже знаете";
App::$strings["View your personal stream (this may be empty until you add some connections)"] = "Ваш персональный поток (может быть пуст пока вы не добавите контакты)";
App::$strings["View the public stream. Warning: this content is not moderated"] = "Просмотр публичного потока. Предупреждение: этот контент не модерируется";
App::$strings["Forums"] = "Форумы";
App::$strings["Notes"] = "Записки";
App::$strings["Suggestions"] = "Рекомендации";
App::$strings["See more..."] = "Просмотреть больше...";
@@ -2602,6 +2601,7 @@ App::$strings["via"] = "через";
App::$strings["Attendance Options"] = "Параметры посещаемости";
App::$strings["Voting Options"] = "Параметры голосования";
App::$strings["Pinned post"] = "Прикреплённая заметка";
App::$strings["Don't show"] = "Не показывать";
App::$strings["Events Tools"] = "Инструменты для событий";
App::$strings["Export Calendar"] = "Экспортировать календарь";
App::$strings["Import Calendar"] = "Импортировать календарь";
@@ -2630,7 +2630,7 @@ App::$strings["Show posts to this forum"] = "Показывать публика
App::$strings["Show forums"] = "Показывать форумы";
App::$strings["Starred Posts"] = "Отмеченные публикации";
App::$strings["Show posts that I have starred"] = "Показывать публикации которые я отметил";
App::$strings["Personal Posts"] = "Личные публикации";
App::$strings["Personal Posts"] = "Свои публикации";
App::$strings["Show posts that mention or involve me"] = "Показывать публикации где вы были упомянуты или привлечены";
App::$strings["Show posts that I have filed to %s"] = "Показывать публикации которые я добавил в %s";
App::$strings["Show filed post categories"] = "Показывать категории добавленных публикаций";
@@ -2753,6 +2753,7 @@ App::$strings["commented on %s's post"] = "прокомментировал пу
App::$strings["repeated %s's post"] = "разместил публикацию %s";
App::$strings["edited a post dated %s"] = "отредактировал публикацию датированную %s";
App::$strings["edited a comment dated %s"] = "отредактировал комментарий датированный %s";
App::$strings["created an event"] = "создано событие";
App::$strings["(No Title)"] = "(нет заголовка)";
App::$strings["Wiki page create failed."] = "Не удалось создать страницу Wiki.";
App::$strings["Wiki not found."] = "Wiki не найдена.";

View File

@@ -95,6 +95,7 @@
</div>
<h3>{{$advanced}}</h3>
{{include file="field_checkbox.tpl" field=$sse_enabled}}
{{include file="field_input.tpl" field=$imagick_path}}
{{include file="field_input.tpl" field=$proxy}}
{{include file="field_input.tpl" field=$proxyuser}}

View File

@@ -9,6 +9,7 @@
{{$plugins}}
<script>
var updateInterval = {{$update_interval}};
var sse_enabled = {{$sse_enabled}};
var localUser = {{if $local_channel}}{{$local_channel}}{{else}}false{{/if}};
var zid = {{if $zid}}'{{$zid}}'{{else}}null{{/if}};
var justifiedGalleryActive = false;