diff --git a/chat.php b/chat.php index 81fc8e7..b12969b 100644 --- a/chat.php +++ b/chat.php @@ -35,7 +35,6 @@ send_headers(); // initialize and load variables/configuration $F=[];// Fonts -$H=[];// HTML-stuff $I=[];// Translations $L=[];// Languages $U=[];// This user data @@ -49,7 +48,6 @@ if(!isSet($_REQUEST['session']) && isSet($_COOKIE[COOKIENAME])){ } load_fonts(); load_lang(); -load_html(); check_db(); route(); @@ -80,7 +78,7 @@ function route(){ } } }elseif(isSet($_REQUEST['message']) && isSet($_REQUEST['sendto'])){ - validate_input(); + send_post(validate_input()); } send_post(); }elseif($_REQUEST['action']==='login'){ @@ -263,7 +261,7 @@ function print_stylesheet($init=false){ //default css echo '"; echo ''; @@ -2119,15 +2125,14 @@ function send_fatal_error($err){ } function print_notifications(){ - global $H, $I, $U, $db; + global $I, $U, $db; echo ''; if($U['status']>=2 && $U['eninbox']!=0){ $stmt=$db->prepare('SELECT COUNT(*) FROM ' . PREFIX . 'inbox WHERE recipient=?;'); $stmt->execute([$U['nickname']]); $tmp=$stmt->fetch(PDO::FETCH_NUM); if($tmp[0]>0){ - echo "

<$H[form]>$H[commonform]".hidden('action', 'inbox'); - echo submit(sprintf($I['inboxmsgs'], $tmp[0])).'

'; + echo '

'.form('inbox').submit(sprintf($I['inboxmsgs'], $tmp[0])).'

'; } } if($U['status']>=5 && get_setting('guestaccess')==3){ @@ -2135,7 +2140,7 @@ function print_notifications(){ $temp=$result->fetch(PDO::FETCH_NUM); if($temp[0]>0){ echo '

'; - frmadm('approve'); + echo form('admin', 'approve'); echo submit(sprintf($I['approveguests'], $temp[0])).'

'; } } @@ -2311,6 +2316,7 @@ function check_login(){ setcookie(COOKIENAME, $U['session']); }else{ setcookie(COOKIENAME, false); + $_REQUEST['session']=''; send_error($I['expire']); } @@ -2352,6 +2358,7 @@ function kill_session(){ check_expired(); check_kicked(); setcookie(COOKIENAME, false); + $_REQUEST['session']=''; $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'sessions WHERE session=?;'); $stmt->execute([$U['session']]); if($U['status']==1){ @@ -2444,6 +2451,7 @@ function check_expired(){ global $I, $U; if(!isSet($U['session'])){ setcookie(COOKIENAME, false); + $_REQUEST['session']=''; send_error($I['expire']); } } @@ -2458,6 +2466,7 @@ function check_kicked(){ global $I, $U; if($U['status']==0){ setcookie(COOKIENAME, false); + $_REQUEST['session']=''; send_error("$I[kicked]
$U[kickmessage]"); } } @@ -2857,43 +2866,43 @@ function validate_input(){ global $U, $db; $inbox=false; $maxmessage=get_setting('maxmessage'); - $U['message']=mb_substr($_REQUEST['message'], 0, $maxmessage); - $U['rejected']=mb_substr($_REQUEST['message'], $maxmessage); + $message=mb_substr($_REQUEST['message'], 0, $maxmessage); + $rejected=mb_substr($_REQUEST['message'], $maxmessage); if($U['postid']===$_REQUEST['postid']){// ignore double post=reload from browser or proxy - $U['message']=''; + $message=''; }elseif((time()-$U['lastpost'])<=1){// time between posts too short, reject! - $U['rejected']=$_REQUEST['message']; - $U['message']=''; + $rejected=$_REQUEST['message']; + $message=''; } - if(!empty($U['rejected'])){ - $U['rejected']=trim($U['rejected']); - $U['rejected']=htmlspecialchars($U['rejected']); + if(!empty($rejected)){ + $rejected=trim($rejected); + $rejected=htmlspecialchars($rejected); } - $U['message']=htmlspecialchars($U['message']); - $U['message']=preg_replace("/(\r?\n|\r\n?)/u", '
', $U['message']); + $message=htmlspecialchars($message); + $message=preg_replace("/(\r?\n|\r\n?)/u", '
', $message); if(isSet($_REQUEST['multi'])){ - $U['message']=preg_replace('/\s*
/u', '
', $U['message']); - $U['message']=preg_replace('/
(
)+/u', '

', $U['message']); - $U['message']=preg_replace('/

\s*$/u', '
', $U['message']); - $U['message']=preg_replace('/^
\s*$/u', '', $U['message']); + $message=preg_replace('/\s*
/u', '
', $message); + $message=preg_replace('/
(
)+/u', '

', $message); + $message=preg_replace('/

\s*$/u', '
', $message); + $message=preg_replace('/^
\s*$/u', '', $message); }else{ - $U['message']=str_replace('
', ' ', $U['message']); + $message=str_replace('
', ' ', $message); } - $U['message']=trim($U['message']); - $U['message']=preg_replace('/\s+/u', ' ', $U['message']); - $U['recipient']=''; + $message=trim($message); + $message=preg_replace('/\s+/u', ' ', $message); + $recipient=''; if($_REQUEST['sendto']==='s *'){ - $U['poststatus']=1; - $U['displaysend']=sprintf(get_setting('msgsendall'), style_this(htmlspecialchars($U['nickname']), $U['style'])); + $poststatus=1; + $displaysend=sprintf(get_setting('msgsendall'), style_this(htmlspecialchars($U['nickname']), $U['style'])); }elseif($_REQUEST['sendto']==='s ?' && $U['status']>=3){ - $U['poststatus']=3; - $U['displaysend']=sprintf(get_setting('msgsendmem'), style_this(htmlspecialchars($U['nickname']), $U['style'])); + $poststatus=3; + $displaysend=sprintf(get_setting('msgsendmem'), style_this(htmlspecialchars($U['nickname']), $U['style'])); }elseif($_REQUEST['sendto']==='s #' && $U['status']>=5){ - $U['poststatus']=5; - $U['displaysend']=sprintf(get_setting('msgsendmod'), style_this(htmlspecialchars($U['nickname']), $U['style'])); + $poststatus=5; + $displaysend=sprintf(get_setting('msgsendmod'), style_this(htmlspecialchars($U['nickname']), $U['style'])); }elseif($_REQUEST['sendto']==='s &' && $U['status']>=6){ - $U['poststatus']=6; - $U['displaysend']=sprintf(get_setting('msgsendadm'), style_this(htmlspecialchars($U['nickname']), $U['style'])); + $poststatus=6; + $displaysend=sprintf(get_setting('msgsendadm'), style_this(htmlspecialchars($U['nickname']), $U['style'])); }else{// known nick in room? if(get_setting('disablepm')){ return; @@ -2901,28 +2910,32 @@ function validate_input(){ $stmt=$db->prepare('SELECT * FROM (SELECT nickname, style, 1 AS inbox FROM ' . PREFIX . 'members WHERE nickname=? AND eninbox!=0 AND eninbox<=? AND nickname NOT IN (SELECT nickname FROM ' . PREFIX . 'sessions) UNION SELECT nickname, style, 0 AS inbox FROM ' . PREFIX . 'sessions WHERE nickname=?) AS t WHERE nickname NOT IN (SELECT ign FROM ' . PREFIX . 'ignored WHERE ignby=? UNION SELECT ignby FROM ' . PREFIX . 'ignored WHERE ign=?);'); $stmt->execute([$_REQUEST['sendto'], $U['status'], $_REQUEST['sendto'], $U['nickname'], $U['nickname']]); if($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){ - $U['recipient']=$_REQUEST['sendto']; - $U['poststatus']=9; - $U['displaysend']=sprintf(get_setting('msgsendprv'), style_this(htmlspecialchars($U['nickname']), $U['style']), style_this(htmlspecialchars($U['recipient']), $tmp['style'])); + $recipient=$_REQUEST['sendto']; + $poststatus=9; + $displaysend=sprintf(get_setting('msgsendprv'), style_this(htmlspecialchars($U['nickname']), $U['style']), style_this(htmlspecialchars($recipient), $tmp['style'])); $inbox=$tmp['inbox']; } - if(empty($U['recipient'])){// nick left already or ignores us - $U['message']=''; - $U['rejected']=''; + if(empty($recipient)){// nick left already or ignores us + $message=''; + $rejected=''; return; } } - apply_filter(); - create_hotlinks(); - apply_linkfilter(); + if($poststatus!==9 && preg_match('~^/me~iu', $message)){ + $displaysend=style_this(htmlspecialchars($U['nickname']), $U['style']); + $message=preg_replace("~^/me~iu", '', $message); + } + $message=apply_filter($message, $poststatus, $U['nickname']); + $message=create_hotlinks($message); + $message=apply_linkfilter($message); if(isSet($_FILES['file']) && get_setting('enfileupload')){ if($_FILES['file']['error']===UPLOAD_ERR_OK && $_FILES['file']['size']<=(1024*get_setting('maxuploadsize'))){ $hash=sha1_file($_FILES['file']['tmp_name']); $name=htmlspecialchars($_FILES['file']['name']); - $U['message']=sprintf(get_setting('msgattache'), "$name", $U['message']); + $message=sprintf(get_setting('msgattache'), "$name", $message); } } - if(add_message()){ + if(add_message($message, $recipient, $U['nickname'], $U['status'], $poststatus, $displaysend, $U['style'])){ $U['lastpost']=time(); $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET lastpost=?, postid=? WHERE session=?;'); $stmt->execute([$U['lastpost'], $_REQUEST['postid'], $U['session']]); @@ -2930,17 +2943,17 @@ function validate_input(){ $stmt->execute([$U['nickname']]); $id=$stmt->fetch(PDO::FETCH_NUM); if($inbox && $id){ - $message=[ + $newmessage=[ 'postdate' =>time(), 'poster' =>$U['nickname'], - 'recipient' =>$U['recipient'], - 'text' =>"$U[displaysend]".style_this($U['message'], $U['style']).'' + 'recipient' =>$recipient, + 'text' =>"$displaysend".style_this($message, $U['style']).'' ]; if(MSGENCRYPTED){ - $message['text']=openssl_encrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456'); + $newmessage['text']=openssl_encrypt($newmessage['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456'); } $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'inbox (postdate, postid, poster, recipient, text) VALUES(?, ?, ?, ?, ?)'); - $stmt->execute([$message['postdate'], $id[0], $message['poster'], $message['recipient'], $message['text']]); + $stmt->execute([$newmessage['postdate'], $id[0], $newmessage['poster'], $newmessage['recipient'], $newmessage['text']]); } if(isset($hash) && $id){ if(!empty($_FILES['file']['type'])){ @@ -2953,16 +2966,99 @@ function validate_input(){ unlink($_FILES['file']['tmp_name']); } } + return $rejected; } -function apply_filter(){ - global $I, $U; - if($U['poststatus']!==9 && preg_match('~^/me~iu', $U['message'])){ - $U['displaysend']=style_this(htmlspecialchars($U['nickname']), $U['style']); - $U['message']=preg_replace("~^/me~iu", '', $U['message']); +function apply_filter($message, $poststatus, $nickname){ + global $I; + $message=str_replace('
', "\n", $message); + $message=apply_mention($message); + $filters=get_filters(); + foreach($filters as $filter){ + if($poststatus!==9 || !$filter['allowinpm']){ + if($filter['cs']){ + $message=preg_replace("/$filter[match]/u", $filter['replace'], $message, -1, $count); + }else{ + $message=preg_replace("/$filter[match]/iu", $filter['replace'], $message, -1, $count); + } + } + if(isSet($count) && $count>0 && $filter['kick']){ + kick_chatter([$nickname], $filter['replace'], false); + setcookie(COOKIENAME, false); + $_REQUEST['session']=''; + send_error("$I[kicked]
$filter[replace]"); + } } - $U['message']=str_replace('
', "\n", $U['message']); - $U['message']=preg_replace_callback('/\@([^\s]+)/iu', function ($matched){ + $message=str_replace("\n", '
', $message); + return $message; +} + +function apply_linkfilter($message){ + $filters=get_linkfilters(); + foreach($filters as $filter){ + $message=preg_replace_callback("/(.*?(?=<\/a>))<\/a>/iu", + function ($matched) use(&$filter){ + return "".preg_replace("/$filter[match]/iu", $filter['replace'], $matched[2]).''; + } + , $message); + } + $redirect=get_setting('redirect'); + if(get_setting('imgembed')){ + $message=preg_replace_callback('/\[img\]\s?(.*?(?=<\/a>))<\/a>/iu', + function ($matched){ + return str_ireplace('[/img]', '', "

"); + } + , $message); + } + if(empty($redirect)){ + $redirect="$_SERVER[SCRIPT_NAME]?action=redirect&url="; + } + if(get_setting('forceredirect')){ + $message=preg_replace_callback('/(.*?(?=<\/a>))<\/a>/u', + function ($matched) use($redirect){ + return "$matched[2]"; + } + , $message); + }elseif(preg_match_all('/(.*?(?=<\/a>))<\/a>/u', $message, $matches)){ + foreach($matches[1] as $match){ + if(!preg_match('~^http(s)?://~u', $match)){ + $message=preg_replace_callback('/(.*?(?=<\/a>))<\/a>/u', + function ($matched) use($redirect){ + return "$matched[2]"; + } + , $message); + } + } + } + return $message; +} + +function create_hotlinks($message){ + //Make hotlinks for URLs, redirect through dereferrer script to prevent session leakage + // 1. all explicit schemes with whatever xxx://yyyyyyy + $message=preg_replace('~(^|[^\w"])(\w+://[^\s<>]+)~iu', "$1<<$2>>", $message); + // 2. valid URLs without scheme: + $message=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d*)?/[^\s<>]*)(?![^<>]*>)~iu', "<<$1>>", $message); // server/path given + $message=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+:\d+)(?![^<>]*>)~iu', "<<$1>>", $message); // server:port given + $message=preg_replace('~([^\s<>]*:[^\s<>]*@[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d+)?)(?![^<>]*>)~iu', "<<$1>>", $message); // au:th@server given + // 3. likely servers without any hints but not filenames like *.rar zip exe etc. + $message=preg_replace('~((?:[a-z0-9\-]+\.)*[a-z2-7]{16}\.onion)(?![^<>]*>)~iu', "<<$1>>", $message);// *.onion + $message=preg_replace('~([a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?:\.(?!rar|zip|exe|gz|7z|bat|doc)[a-z]{2,}))(?=[^a-z0-9\-\.]|$)(?![^<>]*>)~iu', "<<$1>>", $message);// xxx.yyy.zzz + // Convert every <<....>> into proper links: + $message=preg_replace_callback('/<<([^<>]+)>>/u', + function ($matches){ + if(strpos($matches[1], '://')===false){ + return "$matches[1]"; + }else{ + return "$matches[1]"; + } + } + , $message); + return $message; +} + +function apply_mention($message){ + return preg_replace_callback('/\@([^\s]+)/iu', function ($matched){ global $db; $nick=htmlspecialchars_decode($matched[1]); $rest=''; @@ -2998,109 +3094,29 @@ function apply_filter(){ $nick=mb_substr($nick, 0, -1); } return $matched[0]; - }, $U['message']); - $filters=get_filters(); - foreach($filters as $filter){ - if($U['poststatus']!==9 || !$filter['allowinpm']){ - if($filter['cs']){ - $U['message']=preg_replace("/$filter[match]/u", $filter['replace'], $U['message'], -1, $count); - }else{ - $U['message']=preg_replace("/$filter[match]/iu", $filter['replace'], $U['message'], -1, $count); - } - } - if(isSet($count) && $count>0 && $filter['kick']){ - kick_chatter([$U['nickname']], $filter['replace'], false); - setcookie(COOKIENAME, false); - send_error("$I[kicked]
$filter[replace]"); - } - } - $U['message']=str_replace("\n", '
', $U['message']); + }, $message); } -function apply_linkfilter(){ - global $U; - $filters=get_linkfilters(); - foreach($filters as $filter){ - $U['message']=preg_replace_callback("/(.*?(?=<\/a>))<\/a>/iu", - function ($matched) use(&$filter){ - return "".preg_replace("/$filter[match]/iu", $filter['replace'], $matched[2]).''; - } - , $U['message']); - } - $redirect=get_setting('redirect'); - if(get_setting('imgembed')){ - $U['message']=preg_replace_callback('/\[img\]\s?(.*?(?=<\/a>))<\/a>/iu', - function ($matched){ - return str_ireplace('[/img]', '', "

"); - } - , $U['message']); - } - if(empty($redirect)){ - $redirect="$_SERVER[SCRIPT_NAME]?action=redirect&url="; - } - if(get_setting('forceredirect')){ - $U['message']=preg_replace_callback('/(.*?(?=<\/a>))<\/a>/u', - function ($matched) use($redirect){ - return "$matched[2]"; - } - , $U['message']); - }elseif(preg_match_all('/(.*?(?=<\/a>))<\/a>/u', $U['message'], $matches)){ - foreach($matches[1] as $match){ - if(!preg_match('~^http(s)?://~u', $match)){ - $U['message']=preg_replace_callback('/(.*?(?=<\/a>))<\/a>/u', - function ($matched) use($redirect){ - return "$matched[2]"; - } - , $U['message']); - } - } - } -} - -function create_hotlinks(){ - global $U; - //Make hotlinks for URLs, redirect through dereferrer script to prevent session leakage - // 1. all explicit schemes with whatever xxx://yyyyyyy - $U['message']=preg_replace('~(^|[^\w"])(\w+://[^\s<>]+)~iu', "$1<<$2>>", $U['message']); - // 2. valid URLs without scheme: - $U['message']=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d*)?/[^\s<>]*)(?![^<>]*>)~iu', "<<$1>>", $U['message']); // server/path given - $U['message']=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+:\d+)(?![^<>]*>)~iu', "<<$1>>", $U['message']); // server:port given - $U['message']=preg_replace('~([^\s<>]*:[^\s<>]*@[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d+)?)(?![^<>]*>)~iu', "<<$1>>", $U['message']); // au:th@server given - // 3. likely servers without any hints but not filenames like *.rar zip exe etc. - $U['message']=preg_replace('~((?:[a-z0-9\-]+\.)*[a-z2-7]{16}\.onion)(?![^<>]*>)~iu', "<<$1>>", $U['message']);// *.onion - $U['message']=preg_replace('~([a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?:\.(?!rar|zip|exe|gz|7z|bat|doc)[a-z]{2,}))(?=[^a-z0-9\-\.]|$)(?![^<>]*>)~iu', "<<$1>>", $U['message']);// xxx.yyy.zzz - // Convert every <<....>> into proper links: - $U['message']=preg_replace_callback('/<<([^<>]+)>>/u', - function ($matches){ - if(strpos($matches[1], '://')===false){ - return "$matches[1]"; - }else{ - return "$matches[1]"; - } - } - , $U['message']); -} - -function add_message(){ - global $U, $db; - if(empty($U['message'])){ +function add_message($message, $recipient, $poster, $delstatus, $poststatus, $displaysend, $style){ + global $db; + if(empty($message)){ return false; } - $message=[ + $newmessage=[ 'postdate' =>time(), - 'poststatus' =>$U['poststatus'], - 'poster' =>$U['nickname'], - 'recipient' =>$U['recipient'], - 'text' =>"$U[displaysend]".style_this($U['message'], $U['style']).'', - 'delstatus' =>$U['status'] + 'poststatus' =>$poststatus, + 'poster' =>$poster, + 'recipient' =>$recipient, + 'text' =>"$displaysend".style_this($message, $style).'', + 'delstatus' =>$delstatus ]; //prevent posting the same message twice, if no other message was posted in-between. $stmt=$db->prepare('SELECT id FROM ' . PREFIX . 'messages WHERE poststatus=? AND poster=? AND recipient=? AND text=? AND id IN (SELECT * FROM (SELECT id FROM ' . PREFIX . 'messages ORDER BY id DESC LIMIT 1) AS t);'); - $stmt->execute([$message['poststatus'], $message['poster'], $message['recipient'], $message['text']]); + $stmt->execute([$newmessage['poststatus'], $newmessage['poster'], $newmessage['recipient'], $newmessage['text']]); if($stmt->fetch(PDO::FETCH_NUM)){ return false; } - write_message($message); + write_message($newmessage); return true; } @@ -3479,8 +3495,9 @@ function check_init(){ } function destroy_chat($C){ - global $H, $I, $db, $language, $memcached; + global $I, $db, $language, $memcached; setcookie(COOKIENAME, false); + $_REQUEST['session']=''; print_start('destory'); $db->exec('DROP TABLE ' . PREFIX . 'captcha;'); $db->exec('DROP TABLE ' . PREFIX . 'files;'); @@ -3503,12 +3520,12 @@ function destroy_chat($C){ $memcached->delete(DBNAME . '-' . PREFIX . 'settings-msgencrypted'); } echo "

$I[destroyed]




"; - echo "<$H[form]>".hidden('lang', $language).hidden('action', 'setup').submit($I['init'])."$H[credit]"; + echo form('setup').hidden('lang', $language).submit($I['init']).''.credit(); print_end(); } function init_chat(){ - global $H, $I, $db; + global $I, $db; $suwrite=''; if(check_init()){ $suwrite=$I['initdbexist']; @@ -3597,7 +3614,7 @@ function init_chat(){ } print_start('init'); echo "

$I[init]


$I[sulogin]

$suwrite


"; - echo "<$H[form]>$H[commonform]".hidden('action', 'setup').submit($I['initgosetup'])."$H[credit]"; + echo form('setup').submit($I['initgosetup']).''.credit(); print_end(); } @@ -4017,23 +4034,6 @@ function load_fonts(){ ]; } -function load_html(){ - global $H, $I, $language; - $H=[// default HTML - 'form' =>"form action=\"$_SERVER[SCRIPT_NAME]\" enctype=\"multipart/form-data\" method=\"post\"", - 'meta_html' =>'', - 'credit' =>'

LE CHAT-PHP - ' . VERSION . '
', - 'commonform' =>hidden('lang', $language).hidden('nc', substr(time(), -6)) - ]; - if(isSet($_REQUEST['session'])){ - $H['commonform'].=hidden('session', $_REQUEST['session']); - } - $H=$H+[ - 'backtologin' =>"<$H[form] target=\"_parent\">".hidden('lang', $language).submit($I['backtologin'], 'class="backbutton"').'', - 'backtochat' =>"<$H[form]>$H[commonform]".hidden('action', 'view').submit($I['backtochat'], 'class="backbutton"').'' - ]; -} - function load_lang(){ global $I, $L, $language; $L=[