Merge branch 'develop' of https://github.com/shish/shimmie2 into develop

This commit is contained in:
Shish 2019-05-26 16:25:36 +01:00
commit 445687111e
18 changed files with 178 additions and 56 deletions

View file

@ -191,7 +191,13 @@ class Image {
return null;
}
fwrite($fp, json_encode($req));
$data = fgets($fp, 1024);
$data = "";
while (($buffer = fgets($fp, 4096)) !== false) {
$data .= $buffer;
}
if (!feof($fp)) {
die("Error: unexpected fgets() fail in query_accelerator($req)\n");
}
fclose($fp);
return json_decode($data);
}

View file

@ -41,6 +41,7 @@ _d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,set
_d("EXTRA_EXTS", ""); // string optional extra extensions
_d("BASE_URL", null); // string force a specific base URL (default is auto-detect)
_d("MIN_PHP_VERSION", '7.0');// string minimum supported PHP version
_d("SLOW_PAGES", null); // float log pages which take more time than this
_d("ENABLED_MODS", "imageboard");
/*

View file

@ -105,11 +105,19 @@ class User {
$user = User::by_name($name);
if($user) {
if($user->passhash == md5(strtolower($name) . $pass)) {
log_info("core-user", "Migrating from md5 to bcrypt for ".html_escape($name));
$user->set_password($pass);
}
if(password_verify($pass, $user->passhash)) {
log_info("core-user", "Logged in as ".html_escape($name)." ({$user->class->name})");
return $user;
}
else {
log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid password)");
}
}
else {
log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid username)");
}
return null;
}

View file

@ -350,6 +350,18 @@ function get_debug_info(): string {
return $debug;
}
function log_slow() {
global $_shm_load_start;
if(!is_null(SLOW_PAGES)) {
$_time = microtime(true) - $_shm_load_start;
if($_time > SLOW_PAGES) {
$_query = _get_query();
$_dbg = get_debug_info();
file_put_contents("data/slow-pages.log", "$_time $_query $_dbg\n", FILE_APPEND | LOCK_EX);
}
}
}
function score_assert_handler($file, $line, $code, $desc = null) {
$file = basename($file);
print("Assertion failed at $file:$line: $code ($desc)");
@ -389,7 +401,7 @@ function _sanitise_environment() {
date_default_timezone_set(TIMEZONE);
}
ini_set('zend.assertions', 1); // generate assertions
# ini_set('zend.assertions', 1); // generate assertions
ini_set('assert.exception', 1); // throw exceptions when failed
if(DEBUG) {
error_reporting(E_ALL);

View file

@ -130,16 +130,15 @@ class AdminPage extends Extension {
$reason = @$_POST['reason'];
assert(strlen($query) > 1);
log_warning("admin", "Mass deleting: $query");
$count = 0;
foreach(Image::find_images(0, 1000000, Tag::explode($query)) as $image) {
$images = Image::find_images(0, 1000000, Tag::explode($query));
$count = count($images);
log_warning("admin", "Mass-deleting $count images from $query", true);
foreach($images as $image) {
if($reason && class_exists("ImageBan")) {
send_event(new AddImageHashBanEvent($image->hash, $reason));
}
send_event(new ImageDeletionEvent($image));
$count++;
}
log_debug("admin", "Deleted $count images", true);
$page->set_mode("redirect");
$page->set_redirect(make_link("post/list"));

View file

@ -14,10 +14,24 @@ class AutoComplete extends Extension {
if($event->page_matches("api/internal/autocomplete")) {
if(!isset($_GET["s"])) return;
$page->set_mode("data");
$page->set_type("application/json");
$s = strtolower($_GET["s"]);
if(
$s == '' ||
$s[0] == '_' ||
$s[0] == '%' ||
strlen($s) > 32
) {
$page->set_data("{}");
return;
}
//$limit = 0;
$cache_key = "autocomplete-" . strtolower($_GET["s"]);
$cache_key = "autocomplete-$s";
$limitSQL = "";
$SQLarr = array("search"=>$_GET["s"]."%");
$SQLarr = array("search"=>"$s%");
if(isset($_GET["limit"]) && $_GET["limit"] !== 0){
$limitSQL = "LIMIT :limit";
$SQLarr['limit'] = $_GET["limit"];
@ -37,8 +51,6 @@ class AutoComplete extends Extension {
$database->cache->set($cache_key, $res, 600);
}
$page->set_mode("data");
$page->set_type("application/json");
$page->set_data(json_encode($res));
}

View file

@ -64,7 +64,7 @@ class VideoFileHandler extends DataHandlerExtension {
$orig_size = $this->video_size($inname);
$scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1]);
$cmd = escapeshellcmd(Tag::implode([
$cmd = escapeshellcmd(implode(" ", [
escapeshellarg($ffmpeg),
"-y", "-i", escapeshellarg($inname),
"-vf", "scale={$scaled_size[0]}:{$scaled_size[1]}",
@ -76,12 +76,13 @@ class VideoFileHandler extends DataHandlerExtension {
exec($cmd, $output, $ret);
if ((int)$ret == (int)1) {
if ((int)$ret == (int)0) {
$ok = true;
log_error('handle_video', "Generating thumbnail with command `$cmd`, returns $ret");
}
else {
log_debug('handle_video', "Generating thumbnail with command `$cmd`, returns $ret");
}
// error_log("Generating thumbnail with command `$cmd`, returns $ret");
log_debug('handle_video', "Generating thumbnail with command `$cmd`, returns $ret");
return $ok;
}
@ -89,7 +90,7 @@ class VideoFileHandler extends DataHandlerExtension {
protected function video_size(string $filename) {
global $config;
$ffmpeg = $config->get_string("thumb_ffmpeg_path");
$cmd = escapeshellcmd(Tag::implode([
$cmd = escapeshellcmd(implode(" ", [
escapeshellarg($ffmpeg),
"-y", "-i", escapeshellarg($filename),
"-vstats"
@ -100,15 +101,17 @@ class VideoFileHandler extends DataHandlerExtension {
$regex_sizes = "/Video: .* ([0-9]{1,4})x([0-9]{1,4})/";
if (preg_match($regex_sizes, $output, $regs)) {
if (preg_match("/displaymatrix: rotation of (90|270).00 degrees/", $output)) {
return [$regs[2], $regs[1]];
$size = [$regs[2], $regs[1]];
}
else {
return [$regs[1], $regs[2]];
$size = [$regs[1], $regs[2]];
}
}
else {
return [1, 1];
$size = [1, 1];
}
log_debug('handle_video', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]");
return $size;
}
/**

View file

@ -43,7 +43,11 @@ class IPBan extends Extension {
if($config->get_int("ext_ipban_version") < 8) {
$this->install();
}
$config->set_default_string("ipban_message", "If you couldn't possibly be guilty of what you're banned for, the person we banned probably had a dynamic IP address and so do you. See <a href='http://whatismyipaddress.com/dynamic-static'>http://whatismyipaddress.com/dynamic-static</a> for more information.\n");
$config->set_default_string("ipban_message",
'<p>IP <b>$IP</b> has been banned until <b>$DATE</b> by <b>$ADMIN</b> because of <b>$REASON</b>
<p>If you couldn\'t possibly be guilty of what you\'re banned for, the person we banned probably had a dynamic IP address and so do you.
<p>See <a href="http://whatismyipaddress.com/dynamic-static">http://whatismyipaddress.com/dynamic-static</a> for more information.
<p>$CONTACT');
$this->check_ip_ban();
}
@ -84,7 +88,7 @@ class IPBan extends Extension {
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("IP Ban");
$sb->add_longtext_option("ipban_message", 'Message to show to banned users:');
$sb->add_longtext_option("ipban_message", 'Message to show to banned users:<br>(with $IP, $DATE, $ADMIN, $REASON, and $CONTACT)');
$event->panel->add_block($sb);
}
@ -226,14 +230,20 @@ class IPBan extends Extension {
$admin = User::by_id($row[$prefix.'banner_id']);
$date = date("Y-m-d", $row[$prefix.'end_timestamp']);
$msg = $config->get_string("ipban_message");
header("HTTP/1.0 403 Forbidden");
print "IP <b>$ip</b> has been banned until <b>$date</b> by <b>{$admin->name}</b> because of <b>$reason</b>\n";
print "<p>$msg";
$msg = str_replace('$IP', $ip, $msg);
$msg = str_replace('$DATE', $date, $msg);
$msg = str_replace('$ADMIN', $admin->name, $msg);
$msg = str_replace('$REASON', $reason, $msg);
$contact_link = contact_link();
if(!empty($contact_link)) {
print "<p><a href='$contact_link'>Contact the staff (be sure to include this message)</a>";
$msg = str_replace('$CONTACT', "<a href='$contact_link'>Contact the staff (be sure to include this message)</a>", $msg);
}
else {
$msg = str_replace('$CONTACT', "", $msg);
}
header("HTTP/1.0 403 Forbidden");
print "$msg";
exit;
}
}

View file

@ -91,13 +91,13 @@ class RSS_Images extends Extension {
$link = make_http(make_link("post/view/{$image->id}"));
$tags = html_escape($image->get_tag_list());
$owner = $image->get_owner();
$thumb_url = $image->get_thumb_link();
$image_url = $image->get_image_link();
$posted = date(DATE_RSS, strtotime($image->posted));
$content = html_escape(
"<div>" .
"<p>" . $this->theme->build_thumb_html($image) . "</p>" .
"<p>Uploaded by " . html_escape($owner->name) . "</p>"
"</div>"
);
$data = "

View file

@ -1,16 +1,25 @@
$(function() {
if(Cookies.get("ui-tnc-agreed") !== "true") {
$("BODY").html(""+
"<div align='center' style='font-size: 2em; position: absolute; z-index: 99999999999999999999999999;'>"+
$("BODY").addClass("censored");
$("BODY").append("<div class='tnc_bg'></div>");
$("BODY").append(""+
"<div class='tnc'>"+
"<p>For legal reasons, we need to point out that:"+
"<p>A) this site contains material not suitable for minors"+
"<br>B) cookies may be used"+
"<p><a href='/tnc_agreed'>Click here if you're an adult, and you're ok with that</a>"+
"<p><a onclick='tnc_agree();'>Click here if you're an adult, and you're ok with that</a>"+
"</div>"+
"");
}
});
function tnc_agree() {
Cookies.set("ui-tnc-agreed", "true", {path: '/', expires: 365});
$("BODY").removeClass("censored");
$(".tnc_bg").hide();
$(".tnc").hide();
}
function image_hash_ban(id) {
var reason = prompt("WHY?", "DNP");
if(reason) {

35
ext/rule34/style.css Normal file
View file

@ -0,0 +1,35 @@
BODY.censored #header,
BODY.censored NAV,
BODY.censored ARTICLE,
BODY.censored FOOTER {
filter: blur(10px);
}
.tnc_bg {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: #ACE4A3;
opacity: 0.75;
z-index: 999999999999999999999;
}
.tnc {
position: fixed;
top: 20%;
left: 20%;
right: 20%;
text-align: center;
font-size: 2em;
background: #ACE4A3;
border: 1px solid #7EB977;
z-index: 9999999999999999999999;
}
@media (max-width: 1024px) {
.tnc {
top: 5%;
left: 5%;
right: 5%;
font-size: 3vw;
}
}

View file

@ -66,19 +66,19 @@ class StatsDInterface extends Extension {
}
public function onUserCreation(UserCreationEvent $event) {
StatsDInterface::$stats["shimmie.events.user_creations"] = "1|c";
StatsDInterface::$stats["shimmie_events.user_creations"] = "1|c";
}
public function onDataUpload(DataUploadEvent $event) {
StatsDInterface::$stats["shimmie.events.uploads"] = "1|c";
StatsDInterface::$stats["shimmie_events.uploads"] = "1|c";
}
public function onCommentPosting(CommentPostingEvent $event) {
StatsDInterface::$stats["shimmie.events.comments"] = "1|c";
StatsDInterface::$stats["shimmie_events.comments"] = "1|c";
}
public function onImageInfoSet(ImageInfoSetEvent $event) {
StatsDInterface::$stats["shimmie.events.info-sets"] = "1|c";
StatsDInterface::$stats["shimmie_events.info-sets"] = "1|c";
}
/**

View file

@ -497,6 +497,8 @@ class TagList extends Extension {
private function add_refine_block(Page $page, array $search) {
global $database, $config;
if(count($search) > 5) return;
$wild_tags = $search;
$str_search = Tag::implode($search);
$related_tags = $database->cache->get("related_tags:$str_search");
@ -509,7 +511,7 @@ class TagList extends Extension {
foreach($wild_tags as $tag) {
$tag = str_replace("*", "%", $tag);
$tag = str_replace("?", "_", $tag);
$tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag", array("tag"=>$tag));
$tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag AND count < 25000", array("tag"=>$tag));
// $search_tags = array_merge($search_tags,
// $database->get_col("SELECT tag FROM tags WHERE tag LIKE :tag", array("tag"=>$tag)));
$tag_id_array = array_merge($tag_id_array, $tag_ids);
@ -518,6 +520,8 @@ class TagList extends Extension {
}
$tag_id_list = join(', ', $tag_id_array);
if(count($tag_id_array) > 5) return;
if($tags_ok) {
$query = "
SELECT t2.tag AS tag, COUNT(it2.image_id) AS calc_count

View file

@ -82,18 +82,6 @@ class Upload extends Extension {
}
}
public function onPostListBuilding(PostListBuildingEvent $event) {
global $user, $page;
if($user->can("create_image")) {
if($this->is_full) {
$this->theme->display_full($page);
}
else {
$this->theme->display_block($page);
}
}
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$tes = array();
$tes["Disabled"] = "none";
@ -130,6 +118,15 @@ class Upload extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $database, $page, $user;
if($user->can("create_image")) {
if($this->is_full) {
$this->theme->display_full($page);
}
else {
$this->theme->display_block($page);
}
}
if($event->page_matches("upload/replace")) {
// check if the user is an administrator and can upload files.
if(!$user->can("replace_image")) {

View file

@ -19,9 +19,9 @@ class UploadTheme extends Themelet {
$html = "
".make_form(make_link("upload"), "POST", $multipart=True, 'file_upload')."
<table id='large_upload_form' class='vert'>
<tr><td width='20'>Common&nbsp;Tags<td colspan='5'><input name='tags' type='text' placeholder='tagme' class='autocomplete_tags' autocomplete='off'></td></tr>
<tr><td>Common&nbsp;Source</td><td colspan='5'><input name='source' type='text'></td></tr>
$upload_list
<tr><td width='20'>Tags<td colspan='5'><input name='tags' type='text' placeholder='tagme' class='autocomplete_tags' autocomplete='off'></td></tr>
<tr><td>Source</td><td colspan='5'><input name='source' type='text'></td></tr>
<tr><td colspan='6'><input id='uploadbutton' type='submit' value='Post'></td></tr>
</table>
</form>

View file

@ -240,7 +240,9 @@ class UserPage extends Extension {
$this->theme->display_ip_list(
$page,
$this->count_upload_ips($event->display_user),
$this->count_comment_ips($event->display_user));
$this->count_comment_ips($event->display_user),
$this->count_log_ips($event->display_user)
);
}
}
@ -344,7 +346,6 @@ class UserPage extends Extension {
if(!is_null($duser)) {
$user = $duser;
$this->set_login_cookie($duser->name, $pass);
log_info("user", "{$user->class->name} logged in");
$page->set_mode("redirect");
// Try returning to previous page
@ -358,7 +359,6 @@ class UserPage extends Extension {
}
}
else {
log_warning("user", "Failed to log in as ".html_escape($name));
$this->theme->display_error(401, "Error", "No user with those details was found");
}
}
@ -587,6 +587,21 @@ class UserPage extends Extension {
return $rows;
}
private function count_log_ips(User $duser): array {
if(!class_exists('LogDatabase')) return array();
global $database;
$rows = $database->get_pairs("
SELECT
address,
COUNT(id) AS count,
MAX(date_sent) AS most_recent
FROM score_log
WHERE username=:username
GROUP BY address
ORDER BY most_recent DESC", array("username"=>$duser->name));
return $rows;
}
private function delete_user(Page $page, bool $with_images=false, bool $with_comments=false) {
global $user, $config, $database;

View file

@ -168,7 +168,7 @@ class UserPageTheme extends Themelet {
$page->add_block(new Block("Login", $html, "left", 90));
}
public function display_ip_list(Page $page, array $uploads, array $comments) {
public function display_ip_list(Page $page, array $uploads, array $comments, array $events) {
$html = "<table id='ip-history'>";
$html .= "<tr><td>Uploaded from: ";
$n = 0;
@ -190,8 +190,18 @@ class UserPageTheme extends Themelet {
}
}
$html .= "</td><td>Logged Events:";
$n = 0;
foreach($events as $ip => $count) {
$html .= '<br>'.$ip.' ('.$count.')';
if(++$n >= 20) {
$html .= "<br>...";
break;
}
}
$html .= "</td></tr>";
$html .= "<tr><td colspan='2'>(Most recent at top)</td></tr></table>";
$html .= "<tr><td colspan='3'>(Most recent at top)</td></tr></table>";
$page->add_block(new Block("IPs", $html, "main", 70));
}

View file

@ -107,4 +107,5 @@ catch(Exception $e) {
_fatal_error($e);
$_shm_ctx->log_ender();
}
log_slow();