{'is_' . $m[1] . '_or_higher'}()) { return true; } else { $this->access_denied(); return false; } } # For many actions, GET invokes the HTML UI, and a POST actually invokes # the action, so we often want to require higher access for POST (so the UI # can invoke the login dialog). elseif (preg_match("/^post_(\w+)_only$/", $method, $m)) { if (!$this->request()->isPost()) return true; elseif (current_user()->{'is_' . $m[1] . '_or_higher'}()) return true; else { $this->access_denied(); return false; } } return parent::__call($method, $params); } /** * This is found in SessionHelper in Moebooru */ public function page_number() { if (!isset($this->page_number)) $this->page_number = $this->params()->page ?: 1; return $this->page_number; } # LoginSystem { protected function access_denied() { $previous_url = $this->params()->url || $this->request()->fullPath(); $this->respondTo([ 'html' => function()use($previous_url) { $this->notice('Access denied'); $this->redirectTo("user#login", array('url' => $previous_url)); }, 'xml' => function() { $this->render(array('xml' => array('success' => false, 'reason' => "access denied"), 'root' => "response", 'status' => 403)); }, 'json' => function() { $this->render(array('json' => array('success' => false, 'reason' => "access denied"), 'status' => 403)); } ]); } public function user_can_see_posts() { if (!current_user()->can_see_posts()) { $this->access_denied(); } } protected function set_current_user() { $user = null; $AnonymousUser = array( 'id' => 0, 'level' => 0, 'name' => "Anonymous", 'show_samples' => true, 'language' => '', 'secondary_languages' => '', 'pool_browse_mode' => 1, 'always_resize_images' => true, 'ip_addr' => $this->request()->remoteIp() ); if (!current_user() && $this->session()->user_id) { $user = User::where(['id' => $this->session()->user_id])->first(); } else { if ($this->cookies()->login && $this->cookies()->pass_hash) { $user = User::authenticate_hash($this->cookies()->login, $this->cookies()->pass_hash); } elseif (isset($this->params()->login) && isset($this->params()->password_hash)) { $user = User::authenticate($this->params()->login, $this->params()->password_hash); } elseif (isset($this->params()->user['name']) && isset($this->params()->user['password'])) { $user = User::authenticate($this->params()->user['name'], $this->params()->user['password']); } $user && $user->updateAttribute('last_logged_in_at', date('Y-m-d H:i:s')); } if ($user) { if ($user->is_blocked() && $user->ban && $user->ban->expires_at < date('Y-m-d H:i:s')) { $user->updateAttribute('level', CONFIG()->starting_level); Ban::destroyAll("user_id = ".$user->id); } $this->session()->user_id = $user->id; } else { $user = new User(); $user->assignAttributes($AnonymousUser, ['without_protection' => true]); } User::set_current_user($user); $this->current_user = $user; # For convenient access in activerecord models $user->ip_addr = $this->request()->remoteIp(); Moebooru\Versioning\Versioning::init_history(); if (!current_user()->is_anonymous()) current_user()->log($this->request()->remoteIp()); } # iTODO: protected function set_country() { current_user()->country = '--'; // current_user()->country = Rails::cache()->fetch(['type' => 'geoip', 'ip' => $this->request()->remote_ip()], ['expires_in' => '+1 month']) do // begin // GeoIP->new(Rails.root.join('db', 'GeoIP.dat').to_s).country($this->request()->remote_ip()).country_code2 // rescue // '--' // end // end } # } RespondToHelpers { protected function respond_to_success($notice, $redirect_to_params, array $options = array()) { $extra_api_params = isset($options['api']) ? $options['api'] : array(); $this->respondTo(array( 'html' => function() use ($notice, $redirect_to_params) { $this->notice($notice); $this->redirectTo($redirect_to_params); }, 'json' => function() use ($extra_api_params) { $this->render(array('json' => array_merge($extra_api_params, array('success' => true)))); }, 'xml' => function() use ($extra_api_params) { $this->render(array('xml' => array_merge($extra_api_params, array('success' => true)), 'root' => "response")); } )); } protected function respond_to_error($obj, $redirect_to_params, $options = array()) { !is_array($redirect_to_params) && $redirect_to_params = array($redirect_to_params); $extra_api_params = isset($options['api']) ? $options['api'] : array(); $status = isset($options['status']) ? $options['status'] : 500; if ($obj instanceof Rails\ActiveRecord\Base) { $obj = $obj->errors()->fullMessages(", "); $status = 420; } if ($status == 420) $status = "420 Invalid Record"; elseif ($status == 421) $status = "421 User Throttled"; elseif ($status == 422) $status = "422 Locked"; elseif ($status == 423) $status = "423 Already Exists"; elseif ($status == 424) $status = "424 Invalid Parameters"; $this->respondTo(array( 'html' => function()use($obj, $redirect_to_params) { $this->notice("Error: " . $obj); $this->redirectTo($redirect_to_params); }, 'json' => function()use($obj, $extra_api_params, $status) { $this->render(array('json' => array_merge($extra_api_params, array('success' => false, 'reason' => $obj)), 'status' => $status)); }, 'xml' => function()use($obj, $extra_api_params, $status) { $this->render(array('xml' => array_merge($extra_api_params, array('success' => false, 'reason' => $obj)), 'root' => "response", 'status' => $status)); } )); } protected function respond_to_list($inst_var_name, array $formats = array()) { $inst_var = $this->$inst_var_name; $this->respondTo(array( 'html', isset($formats['atom']) ? 'atom' : null, 'json' => function() use ($inst_var) { $this->render(array('json' => $inst_var->toJson())); }, 'xml' => function() use ($inst_var, $inst_var_name) { $this->render(array('xml' => $inst_var, 'root' => $inst_var_name)); } )); } protected function _render_error($record) { $this->record = $record; $this->render(['inline' => 'record->errors()->fullMessages("
") ?>', 'layout' => "bare", 'status' => 500]); } # } // protected :build_cache_key // protected :get_cache_key public function get_ip_ban() { $ban = IpBans::where("ip_addr = ?", $this->request()->remoteIp())->first(); return $ban ?: null; } protected function check_ip_ban() { if ($this->request()->controller() == "banned" and $this->request()->action() == "index") { return; } $ban = $this->get_ip_ban(); if (!$ban) { return; } if ($ban->expires_at && $ban->expires_at < date('Y-m-d H:i:s')) { IpBans::destroyAll("ip_addr = '{$this->request()->remoteIp()}'"); return; } $this->redirectTo('banned#index'); } protected function save_tags_to_cookie() { if ($this->params()->tags || (is_array($this->params()->post) && isset($this->params()->post['tags']))) { $post_tags = isset($this->params()->post['tags']) ? (string)$this->params()->post['tags'] : ''; $tags = TagAlias::to_aliased(explode(' ', (strtolower($this->params()->tags ?: $post_tags)))); if ($recent_tags = trim($this->cookies()->recent_tags)) $tags = array_merge($tags, explode(' ', $recent_tags)); $this->cookies()->recent_tags = implode(" ", array_slice($tags, 0, 20)); } } public function set_cache_headers() { $this->response()->headers()->add("Cache-Control", "max-age=300"); } # iTODO: public function cache_action() { // if ($this->request()->method() == 'get' && !preg_match('/Googlebot/', $this->request()->env()) && $this->params()->format != "xml" && $this->params()->format != "json") { // list($key, $expiry) = $this->get_cache_key($this->controller_name(), $this->action_name(), $this->params(), 'user' => current_user()); // if ($key && count($key) < 200) { // $cached = Rails::cache()->read($key); // if ($cached) { // $this->render(['text' => $cached, 'layout' => false]); // return; // } // } // $this->yield(); // if ($key && strpos($this->response->headers['Status'], '200') === 0) { // Rails::cache()->write($key, $this->response->body, ['expires_in' => $expiry]); // } // } else { // $this->yield(); // } } protected function init_cookies() { if ($this->request()->format() == "xml" || $this->request()->format() == "json") return; $forum_posts = ForumPost::where("parent_id IS NULL")->order("updated_at DESC")->limit(10)->take(); $this->cookies()->current_forum_posts = json_encode(array_map(function($fp) { if (current_user()->is_anonymous()) { $updated = false; } else { $updated = $fp->updated_at > current_user()->last_forum_topic_read_at; } return [$fp->title, $fp->id, $updated, ceil($fp->response_count / 30.0)]; }, $forum_posts->members())); $this->cookies()->country = current_user()->country; if (!current_user()->is_anonymous()) { $this->cookies()->user_id = (string)current_user()->id; $this->cookies()->user_info = current_user()->user_info_cookie(); $this->cookies()->has_mail = (current_user()->has_mail ? "1" : "0"); $this->cookies()->forum_updated = (current_user()->is_privileged_or_higher() && ForumPost::updated(current_user()) ? "1" : "0"); $this->cookies()->comments_updated = (current_user()->is_privileged_or_higher() && Comment::updated(current_user()) ? "1" : "0"); if (current_user()->is_janitor_or_higher()) { $mod_pending = Post::where("status = 'flagged' OR status = 'pending'")->count(); $this->cookies()->mod_pending = (string)$mod_pending; } if (current_user()->is_blocked()) { if (current_user()->ban) $this->cookies()->block_reason = "You have been blocked. Reason: ".current_user()->ban->reason.". Expires: ".substr(current_user()->ban->expires_at, 0, 10); else $this->cookies()->block_reason = "You have been blocked."; } else $this->cookies()->block_reason = ""; $this->cookies()->resize_image = (current_user()->always_resize_images ? "1" : "0"); $this->cookies()->show_advanced_editing = (current_user()->show_advanced_editing ? "1" : "0"); $this->cookies()->my_tags = current_user()->my_tags; $this->cookies()->blacklisted_tags = json_encode(current_user()->blacklisted_tags_array()); $this->cookies()->held_post_count = (string)current_user()->held_post_count(); } else { $this->cookies()->delete('user_info'); $this->cookies()->delete('login'); $this->cookies()->blacklisted_tags = json_encode(CONFIG()->default_blacklists); } } protected function set_title($title = null) { if (!$title) $title = CONFIG()->app_name; else $title .= ' | ' . CONFIG()->app_name; $this->page_title = $title; } protected function notice($str) { $this->cookies()->notice = $str; } protected function set_locale() { if ($this->params()->locale and in_array($this->params()->locale, CONFIG()->available_locales)) { $this->cookies()->locale = [ 'value' => $this->params()->locale, 'expires' => '+1 year' ]; $this->I18n()->setLocale($this->params()->locale); } elseif ($this->cookies()->locale and in_array($this->cookies()->locale, CONFIG()->available_locales)) { $this->I18n()->setLocale($this->cookies()->locale); } else $this->I18n()->setLocale(CONFIG()->default_locale); } protected function sanitize_params() { if ($this->params()->page) { if ($this->params()->page < 1) $this->params()->page = 1; } else $this->params()->page = 1; } protected function admin_only() { if (!current_user()->is_admin()) $this->access_denied(); } protected function member_only() { if (!current_user()->is_member_or_higher()) $this->access_denied(); } protected function post_privileged_only() { if (!current_user()->is_privileged_or_higher()) $this->access_denied(); } protected function post_member_only() { if (!current_user()->is_member_or_higher()) $this->access_denied(); } protected function no_anonymous() { if (current_user()->is_anonymous()) $this->access_denied(); } protected function sanitize_id() { $this->params()->id = (int)$this->params()->id; } # iTODO: protected function filters() { return [ 'before' => [ 'set_current_user', 'set_country', 'set_locale', 'set_title', 'sanitize_params', 'check_ip_ban' ], 'after' => [ 'init_cookies' ] ]; } }