From 85fb34e20ff167aa2f484ca25129b4a6dedfa8df Mon Sep 17 00:00:00 2001 From: Shish Date: Tue, 14 Feb 2012 06:33:59 +0000 Subject: [PATCH 1/7] allow failed upgrades --- ext/upgrade/main.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index a61b0860..cb2847b1 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -25,18 +25,21 @@ class Upgrade extends Extension { // now done again as v9 with PDO if($config->get_int("db_version") < 8) { - // if this fails, don't try again $config->set_bool("in_upgrade", true); $config->set_int("db_version", 8); + $database->execute($database->engine->scoreql_to_sql( "ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" )); + log_info("upgrade", "Database at version 8"); $config->set_bool("in_upgrade", false); } if($config->get_int("db_version") < 9) { $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 9); + if($database->db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { $tables = $database->get_col("SHOW TABLES"); foreach($tables as $table) { @@ -44,18 +47,18 @@ class Upgrade extends Extension { $database->execute("ALTER TABLE $table TYPE=INNODB"); } } - $config->set_int("db_version", 9); + log_info("upgrade", "Database at version 9"); $config->set_bool("in_upgrade", false); } if($config->get_int("db_version") < 10) { $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 10); log_info("upgrade", "Adding foreign keys to images"); $database->Execute("ALTER TABLE images ADD CONSTRAINT foreign_images_owner_id FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT"); - $config->set_int("db_version", 10); log_info("upgrade", "Database at version 10"); $config->set_bool("in_upgrade", false); } From 629e998f45b0ae305a75ddef09b14dfb7c371199 Mon Sep 17 00:00:00 2001 From: Shish Date: Tue, 14 Feb 2012 06:41:45 +0000 Subject: [PATCH 2/7] more work on user classes --- core/user.class.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/core/user.class.php b/core/user.class.php index fc32e689..3e781aea 100644 --- a/core/user.class.php +++ b/core/user.class.php @@ -15,7 +15,7 @@ class User { var $name; var $email; var $join_date; - var $admin; + var $class; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Initialisation * @@ -35,8 +35,12 @@ class User { $this->name = $row['name']; $this->email = $row['email']; $this->join_date = $row['joindate']; - $this->admin = ($row['admin'] == 'Y'); $this->passhash = $row['pass']; + + global $config; + if($row['admin'] == 'Y') $this->class = "admin"; + else if($this->id != $config->get_int('anon_id')) $this->class = "user"; + else $this->class = "anonymous"; } public static function by_session(/*string*/ $name, /*string*/ $session) { @@ -165,14 +169,7 @@ class User { ), ); - return $user_classes[$this->get_class()][$ability]; - } - - // FIXME: this should be a column in the users table - public function get_class() { - if($this->is_admin()) return "admin"; - else if($this->is_logged_in()) return "user"; - else return"anonymous"; + return $user_classes[$this->class][$ability]; } @@ -202,7 +199,7 @@ class User { * @retval bool */ public function is_admin() { - return $this->admin; + return ($this->class === "admin"); } public function set_admin(/*bool*/ $admin) { From 3c1b20e05b562c296869ff29905e1aa7a9197b0d Mon Sep 17 00:00:00 2001 From: Shish Date: Tue, 14 Feb 2012 20:38:19 +0000 Subject: [PATCH 3/7] user classes --- core/default_config.inc.php | 42 +++++++++++++++++ core/user.class.php | 92 ++++--------------------------------- ext/upgrade/main.php | 13 ++++++ ext/user/main.php | 16 ++++--- ext/user/theme.php | 15 +++++- 5 files changed, 85 insertions(+), 93 deletions(-) diff --git a/core/default_config.inc.php b/core/default_config.inc.php index c6a44b57..fc9245c7 100644 --- a/core/default_config.inc.php +++ b/core/default_config.inc.php @@ -30,5 +30,47 @@ _d("WH_SPLITS", 1); // int how many levels of subfolders to put in _d("VERSION", 'trunk'); // string shimmie version _d("SCORE_VERSION", 's2hack/'.VERSION); // string SCore version _d("TIMEZONE", null); // string timezone +_d("EXTRA_USER_CLASSES", serialize(array())); // array extra classes that a user can be* +/** + * Defining extra user classes: + * see core/userclass.class.php for flags + * + * This is a kind of ugly way of doing things... + * + +define("EXTRA_USER_CLASSES", serialize(array( + // a regular user, with some extra powers + array( + "moderator", # name for the new class + "user", # class to base it on + array( # parts of the base class to override + "lock_image" => True, + "view_ip" => True, + "ban_ip" => True, + "delete_image" => True, + "delete_comment" => True, + "manage_alias_list" => True, + "mass_tag_edit" => True, + "edit_image_tag" => True, + "edit_image_source" => True, + "edit_image_owner" => True, + "view_image_report" => True, + ) + ), + // an admin, minus the ability to create / remove other admins + array( + "manager", # name for the new class + "admin", # class to base it on + array( # parts of the base class to override + "override_config" => False, + "change_password" => False, + "change_user_info" => False, + "delete_user" => False, + "manage_extension_list" => False, + ) + ), +))); + + */ ?> diff --git a/core/user.class.php b/core/user.class.php index 3e781aea..bc3d56c2 100644 --- a/core/user.class.php +++ b/core/user.class.php @@ -31,16 +31,14 @@ class User { * would be to use User::by_id, User::by_session, etc */ public function User($row) { + global $_user_classes; + $this->id = int_escape($row['id']); $this->name = $row['name']; $this->email = $row['email']; $this->join_date = $row['joindate']; $this->passhash = $row['pass']; - - global $config; - if($row['admin'] == 'Y') $this->class = "admin"; - else if($this->id != $config->get_int('anon_id')) $this->class = "user"; - else $this->class = "anonymous"; + $this->class = $_user_classes[$row["class"]]; } public static function by_session(/*string*/ $name, /*string*/ $session) { @@ -96,80 +94,7 @@ class User { * useful user object functions start here */ public function can($ability) { - global $config; - - // TODO: make this into an editable database table - $user_classes = array( - "anonymous" => array( - "change_setting" => False, # web-level settings, eg the config table - "override_config" => False, # sys-level config, eg config.php - "big_search" => False, # more than 3 tags (speed mode only) - "lock_image" => False, - "view_ip" => False, # view IP addresses associated with things - "ban_ip" => False, - "change_password" => False, - "change_user_info" => False, - "delete_user" => False, - "delete_image" => False, - "delete_comment" => False, - "replace_image" => False, - "manage_extension_list" => False, - "manage_alias_list" => False, - "edit_image_tag" => $config->get_bool("tag_edit_anon"), - "edit_image_source" => $config->get_bool("source_edit_anon"), - "edit_image_owner" => False, - "mass_tag_edit" => False, - "report_image" => $config->get_bool('report_image_anon'), - "view_image_report" => False, - ), - "user" => array( - "change_setting" => False, - "override_config" => False, - "big_search" => True, - "lock_image" => False, - "view_ip" => False, - "ban_ip" => False, - "change_password" => False, - "change_user_info" => False, - "delete_user" => False, - "delete_image" => False, - "delete_comment" => False, - "change_image_owner" => False, - "replace_image" => False, - "manage_extension_list" => False, - "manage_alias_list" => False, - "edit_image_tag" => True, - "edit_image_source" => True, - "edit_image_owner" => False, - "mass_tag_edit" => False, - "report_image" => True, - "view_image_report" => False, - ), - "admin" => array( - "change_setting" => True, - "override_config" => True, - "big_search" => True, - "lock_image" => True, - "view_ip" => True, - "ban_ip" => True, - "change_password" => True, - "change_user_info" => True, - "delete_user" => True, - "delete_image" => True, - "delete_comment" => True, - "replace_image" => True, - "manage_extension_list" => True, - "manage_alias_list" => True, - "edit_image_tag" => True, - "edit_image_source" => True, - "edit_image_owner" => True, - "mass_tag_edit" => True, - "report_image" => True, - "view_image_report" => True, - ), - ); - - return $user_classes[$this->class][$ability]; + return $this->class->can($ability); } @@ -202,12 +127,11 @@ class User { return ($this->class === "admin"); } - public function set_admin(/*bool*/ $admin) { - assert(is_bool($admin)); + public function set_class(/*string*/ $class) { + assert(is_string($class)); global $database; - $yn = $admin ? 'Y' : 'N'; - $database->Execute("UPDATE users SET admin=:yn WHERE id=:id", array("yn"=>$yn, "id"=>$this->id)); - log_info("core-user", 'Made '.$this->name.' admin='.$yn); + $database->Execute("UPDATE users SET class=:class WHERE id=:id", array("class"=>$class, "id"=>$this->id)); + log_info("core-user", 'Set class for '.$this->name.' to '.$class); } public function set_password(/*string*/ $password) { diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index cb2847b1..a77494e9 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -62,6 +62,19 @@ class Upgrade extends Extension { log_info("upgrade", "Database at version 10"); $config->set_bool("in_upgrade", false); } + + if($config->get_int("db_version") < 11) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 11); + + log_info("upgrade", "Converting user flags to classes"); + $database->execute("ALTER TABLE users ADD COLUMN class VARCHAR(32) NOT NULL default :user", array("user" => "user")); + $database->execute("UPDATE users SET class = :name WHERE id=:id", array("name"=>"anonymous", "id"=>$config->get_int('anon_id'))); + $database->execute("UPDATE users SET class = :name WHERE admin=:admin", array("name"=>"admin", "admin"=>'Y')); + + log_info("upgrade", "Database at version 11"); + $config->set_bool("in_upgrade", false); + } } public function get_priority() {return 5;} diff --git a/ext/user/main.php b/ext/user/main.php index 96f5ac69..80f73471 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -131,7 +131,7 @@ class UserPage extends Extension { } } else if($event->get_arg(0) == "set_more") { - $this->set_more_wrapper($page); + $this->set_more_wrapper(); } else if($event->get_arg(0) == "list") { // select users.id,name,joindate,admin, @@ -411,10 +411,8 @@ class UserPage extends Extension { } } - private function set_more_wrapper(Page $page) { - global $user; - global $config; - global $database; + private function set_more_wrapper() { + global $config, $database, $page, $user; $page->set_title("Error"); $page->set_heading("Error"); @@ -427,10 +425,14 @@ class UserPage extends Extension { "You need to specify the account number to edit")); } else { - $admin = (isset($_POST['admin']) && ($_POST['admin'] == "on")); + global $_user_classes; + $class = $_POST['class']; + if(!array_key_exists($class, $_user_classes)) { + throw Exception("Invalid user class: ".html_escape($class)); + } $duser = User::by_id($_POST['id']); - $duser->set_admin($admin); + $duser->set_class($class); $page->set_mode("redirect"); if($duser->id == $user->id) { diff --git a/ext/user/theme.php b/ext/user/theme.php index a4639cd7..7e919fab 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -179,7 +179,17 @@ class UserPageTheme extends Themelet { $html .= "

".make_form(make_link("user_admin/set_more"))." - Admin: + Class: @@ -191,7 +201,8 @@ class UserPageTheme extends Themelet { ".make_form(make_link("user_admin/delete_user_with_images"))." - "; + + "; } } return $html; From ff40907fe30895986b838600ecc86cfe0081421c Mon Sep 17 00:00:00 2001 From: Shish Date: Tue, 14 Feb 2012 21:11:23 +0000 Subject: [PATCH 4/7] and commit the file... --- core/userclass.class.php | 94 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 core/userclass.class.php diff --git a/core/userclass.class.php b/core/userclass.class.php new file mode 100644 index 00000000..472145e3 --- /dev/null +++ b/core/userclass.class.php @@ -0,0 +1,94 @@ +name = $name; + $this->parent = $parent; + $this->abilities = $abilities; + } + + public function can(/*string*/ $ability) { + global $config; + + if(array_key_exists($ability, $this->abilities)) { + $val = $this->abilities[$ability]; + if(is_bool($val)) return $val; + else return $config->get_bool($val, false); + } + else if(!is_null($this->parent)) { + return $this->parent->can($ability); + } + else { + die("Unknown ability: ".html_escape($ability)); + } + } +} + +$_user_class_base = new UserClass("base", null, array( + "change_setting" => False, # web-level settings, eg the config table + "override_config" => False, # sys-level config, eg config.php + "big_search" => False, # more than 3 tags (speed mode only) + "lock_image" => False, + "view_ip" => False, # view IP addresses associated with things + "ban_ip" => False, + "change_password" => False, + "change_user_info" => False, + "delete_user" => False, + "delete_image" => False, + "delete_comment" => False, + "replace_image" => False, + "manage_extension_list" => False, + "manage_alias_list" => False, + "edit_image_tag" => False, + "edit_image_source" => False, + "edit_image_owner" => False, + "mass_tag_edit" => False, + "report_image" => False, + "view_image_report" => False, +)); +$_user_classes["anonymous"] = new UserClass("anonymous", $_user_class_base, array( + "edit_image_tag" => "tag_edit_anon", + "edit_image_source" => "source_edit_anon", + "report_image" => "report_image_anon", +)); +$_user_classes["user"] = new UserClass("user", $_user_class_base, array( + "big_search" => True, + "edit_image_tag" => True, + "edit_image_source" => True, + "report_image" => True, +)); +$_user_classes["admin"] = new UserClass("admin", $_user_class_base, array( + "change_setting" => True, + "override_config" => True, + "big_search" => True, + "lock_image" => True, + "view_ip" => True, + "ban_ip" => True, + "change_password" => True, + "change_user_info" => True, + "delete_user" => True, + "delete_image" => True, + "delete_comment" => True, + "replace_image" => True, + "manage_extension_list" => True, + "manage_alias_list" => True, + "edit_image_tag" => True, + "edit_image_source" => True, + "edit_image_owner" => True, + "mass_tag_edit" => True, + "report_image" => True, + "view_image_report" => True, +)); + +foreach(unserialize(EXTRA_USER_CLASSES) as $class_info) { + $name = $class_info[0]; + $base = $_user_classes[$class_info[1]]; + $abilities = $class_info[2]; + $_user_classes[$name] = new UserClass($name, $base, $abilities); +} +?> From e79d26ae8c4bc92d9586fc5db14763d92c16a281 Mon Sep 17 00:00:00 2001 From: Shish Date: Tue, 14 Feb 2012 21:15:19 +0000 Subject: [PATCH 5/7] check against the class /name/... --- core/user.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/user.class.php b/core/user.class.php index bc3d56c2..b5642d10 100644 --- a/core/user.class.php +++ b/core/user.class.php @@ -124,7 +124,7 @@ class User { * @retval bool */ public function is_admin() { - return ($this->class === "admin"); + return ($this->class->name === "admin"); } public function set_class(/*string*/ $class) { From 662c5e877882e8d8bfcb0c1bd80a463a51be2be2 Mon Sep 17 00:00:00 2001 From: Shish Date: Wed, 15 Feb 2012 08:23:00 +0000 Subject: [PATCH 6/7] More ban explanations, and un-cacheable --- contrib/ipban/main.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/ipban/main.php b/contrib/ipban/main.php index ceaa0f6a..0e0fa295 100644 --- a/contrib/ipban/main.php +++ b/contrib/ipban/main.php @@ -195,7 +195,9 @@ class IPBan extends Extension { $reason = $row[$prefix.'reason']; $admin = User::by_id($row[$prefix.'banner_id']); $date = date("Y-m-d", $row[$prefix.'end_timestamp']); - print "IP $ip has been banned until $date by {$admin->name} because of $reason"; + header("Cache-control: no-cache, max-age=0"); + print "IP $ip has been banned until $date by {$admin->name} because of $reason\n"; + print "

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 http://whatismyipaddress.com/dynamic-static for more information.\n"; $contact_link = $config->get_string("contact_link"); if(!empty($contact_link)) { From 8af44574fdd4538a116b33302c91d1e8a60e6eef Mon Sep 17 00:00:00 2001 From: Shish Date: Wed, 15 Feb 2012 08:51:13 +0000 Subject: [PATCH 7/7] 403 is more appropriate --- contrib/ipban/main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ipban/main.php b/contrib/ipban/main.php index 0e0fa295..415e7d1b 100644 --- a/contrib/ipban/main.php +++ b/contrib/ipban/main.php @@ -195,7 +195,7 @@ class IPBan extends Extension { $reason = $row[$prefix.'reason']; $admin = User::by_id($row[$prefix.'banner_id']); $date = date("Y-m-d", $row[$prefix.'end_timestamp']); - header("Cache-control: no-cache, max-age=0"); + header("HTTP/1.0 403 Forbidden"); print "IP $ip has been banned until $date by {$admin->name} because of $reason\n"; print "

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 http://whatismyipaddress.com/dynamic-static for more information.\n";