Ejemplo n.º 1
0
 public function post_test()
 {
     access::allow(identity::everybody(), "edit", item::root());
     $request = new stdClass();
     $request->params = new stdClass();
     $request->params->name = "test tag";
     $this->assert_equal(array("url" => url::site("rest/tag/1")), tags_rest::post($request));
 }
Ejemplo n.º 2
0
 public function post_test()
 {
     $tag = test::random_tag();
     // Create an editable item to be tagged
     $album = test::random_album();
     access::allow(identity::everybody(), "edit", $album);
     // Add the album to the tag
     $request->url = rest::url("tag", $tag);
     $request->params->url = rest::url("item", $album);
     $this->assert_equal_array(array("url" => rest::url("tag_item", $tag, $album)), tag_rest::post($request));
 }
 private function _get_proxy()
 {
     $album = test::random_album();
     $photo = test::random_photo($album);
     access::deny(identity::everybody(), "view_full", $album);
     access::deny(identity::registered_users(), "view_full", $album);
     $proxy = ORM::factory("digibug_proxy");
     $proxy->uuid = random::hash();
     $proxy->item_id = $photo->id;
     return $proxy->save();
 }
Ejemplo n.º 4
0
 public function viewable_test()
 {
     $root = ORM::factory("item", 1);
     $album = album::create($root, rand(), rand(), rand());
     $item = self::_create_random_item($album);
     identity::set_active_user(identity::guest());
     // We can see the item when permissions are granted
     access::allow(identity::everybody(), "view", $album);
     $this->assert_equal(1, ORM::factory("item")->viewable()->where("id", "=", $item->id)->count_all());
     // We can't see the item when permissions are denied
     access::deny(identity::everybody(), "view", $album);
     $this->assert_equal(0, ORM::factory("item")->viewable()->where("id", "=", $item->id)->count_all());
 }
Ejemplo n.º 5
0
 public function viewable_test()
 {
     $album = test::random_album();
     $item = test::random_photo($album);
     $album->reload();
     identity::set_active_user(identity::guest());
     // We can see the item when permissions are granted
     access::allow(identity::everybody(), "view", $album);
     $this->assert_equal(1, ORM::factory("item")->viewable()->where("id", "=", $item->id)->count_all());
     // We can't see the item when permissions are denied
     access::deny(identity::everybody(), "view", $album);
     $this->assert_equal(0, ORM::factory("item")->viewable()->where("id", "=", $item->id)->count_all());
 }
Ejemplo n.º 6
0
 public function cant_view_comments_for_unviewable_items_test()
 {
     $root = ORM::factory("item", 1);
     $album = album::create($root, rand(), rand(), rand());
     $comment = comment::create($album, identity::guest(), "text", "name", "email", "url");
     identity::set_active_user(identity::guest());
     // We can see the comment when permissions are granted on the album
     access::allow(identity::everybody(), "view", $album);
     $this->assert_equal(1, ORM::factory("comment")->viewable()->where("comments.id", "=", $comment->id)->count_all());
     // We can't see the comment when permissions are denied on the album
     access::deny(identity::everybody(), "view", $album);
     $this->assert_equal(0, ORM::factory("comment")->viewable()->where("comments.id", "=", $comment->id)->count_all());
 }
 public function post_fails_without_permissions_test()
 {
     access::deny(identity::everybody(), "edit", item::root());
     identity::set_active_user(identity::guest());
     try {
         $request->params->name = "test tag";
         tags_rest::post($request);
     } catch (Exception $e) {
         $this->assert_equal(403, $e->getCode());
         return;
     }
     $this->assert_true(false, "Shouldnt get here");
 }
Ejemplo n.º 8
0
 public function setup()
 {
     $this->_server = $_SERVER;
     $root = ORM::factory("item", 1);
     $this->_album = album::create($root, rand(), "test album");
     access::deny(identity::everybody(), "view_full", $this->_album);
     access::deny(identity::registered_users(), "view_full", $this->_album);
     $rand = rand();
     $this->_item = photo::create($this->_album, MODPATH . "gallery/tests/test.jpg", "{$rand}.jpg", $rand, $rand);
     $this->_proxy = ORM::factory("digibug_proxy");
     $this->_proxy->uuid = md5(rand());
     $this->_proxy->item_id = $this->_item->id;
     $this->_proxy->save();
 }
 public function change_album_no_csrf_fails_test()
 {
     $controller = new Albums_Controller();
     $album = test::random_album();
     $_POST["name"] = "new name";
     $_POST["title"] = "new title";
     $_POST["description"] = "new description";
     access::allow(identity::everybody(), "edit", item::root());
     try {
         $controller->update($album->id);
         $this->assert_true(false, "This should fail");
     } catch (Exception $e) {
         // pass
         $this->assert_same("@todo FORBIDDEN", $e->getMessage());
     }
 }
Ejemplo n.º 10
0
 public function change_album_no_csrf_fails_test()
 {
     $controller = new Albums_Controller();
     $root = ORM::factory("item", 1);
     $this->_album = album::create($root, "test", "test", "test");
     $_POST["name"] = "new name";
     $_POST["title"] = "new title";
     $_POST["description"] = "new description";
     access::allow(identity::everybody(), "edit", $root);
     try {
         $controller->_update($this->_album);
         $this->assert_true(false, "This should fail");
     } catch (Exception $e) {
         // pass
     }
 }
Ejemplo n.º 11
0
 public function cant_view_comments_for_unviewable_items_test()
 {
     $album = test::random_album();
     $comment = ORM::factory("comment");
     $comment->item_id = $album->id;
     $comment->author_id = identity::admin_user()->id;
     $comment->text = "text";
     $comment->save();
     identity::set_active_user(identity::guest());
     // We can see the comment when permissions are granted on the album
     access::allow(identity::everybody(), "view", $album);
     $this->assert_true(ORM::factory("comment")->viewable()->where("comments.id", "=", $comment->id)->count_all());
     // We can't see the comment when permissions are denied on the album
     access::deny(identity::everybody(), "view", $album);
     $this->assert_false(ORM::factory("comment")->viewable()->where("comments.id", "=", $comment->id)->count_all());
 }
Ejemplo n.º 12
0
 public function change_photo_no_csrf_fails_test()
 {
     $controller = new Photos_Controller();
     $root = ORM::factory("item", 1);
     $photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test.jpg", "test", "test");
     $_POST["name"] = "new name";
     $_POST["title"] = "new title";
     $_POST["description"] = "new description";
     access::allow(identity::everybody(), "edit", $root);
     try {
         $controller->_update($photo);
         $this->assert_true(false, "This should fail");
     } catch (Exception $e) {
         // pass
     }
 }
Ejemplo n.º 13
0
 public function illegal_access_test()
 {
     $album = test::random_album();
     $photo = test::random_photo($album);
     $album->reload();
     access::deny(identity::everybody(), "view", $album);
     identity::set_active_user(identity::guest());
     $request = new stdClass();
     $request->url = rest::url("data", $photo, "thumb");
     $request->params = new stdClass();
     $request->params->size = "thumb";
     try {
         data_rest::get($request);
         $this->assert_true(false);
     } catch (Kohana_404_Exception $e) {
         // pass
     }
 }
Ejemplo n.º 14
0
 public function print_photo($id)
 {
     access::verify_csrf();
     $item = ORM::factory("item", $id);
     access::required("view", $item);
     if (access::group_can(identity::everybody(), "view_full", $item)) {
         $full_url = $item->file_url(true);
         $thumb_url = $item->thumb_url(true);
     } else {
         $proxy = ORM::factory("digibug_proxy");
         $proxy->uuid = random::hash();
         $proxy->item_id = $item->id;
         $proxy->save();
         $full_url = url::abs_site("digibug/print_proxy/full/{$proxy->uuid}/{$item->id}");
         $thumb_url = url::abs_site("digibug/print_proxy/thumb/{$proxy->uuid}/{$item->id}");
     }
     $v = new View("digibug_form.html");
     $v->order_params = array("digibug_api_version" => "100", "company_id" => module::get_var("digibug", "company_id"), "event_id" => module::get_var("digibug", "event_id"), "cmd" => "addimg", "partner_code" => "69", "return_url" => url::abs_site("digibug/close_window"), "num_images" => "1", "image_1" => $full_url, "thumb_1" => $thumb_url, "image_height_1" => $item->height, "image_width_1" => $item->width, "thumb_height_1" => $item->thumb_height, "thumb_width_1" => $item->thumb_width, "title_1" => html::purify($item->title));
     print $v;
 }
Ejemplo n.º 15
0
 private function _get_admin_view($form, $errors)
 {
     $v = new Admin_View("admin.html");
     $v->page_title = t("User registration");
     $v->content = new View("admin_register.html");
     $v->content->action = "admin/register/update";
     $v->content->policy_list = array("admin_only" => t("Only site administrators can create new user accounts."), "visitor" => t("Visitors can create accounts and no administrator approval is required."), "admin_approval" => t("Visitors can create accounts but administrator approval is required."));
     $admin = identity::admin_user();
     $v->content->disable_email = empty($admin->email) || $form["policy"] == "admin_only" ? "disabled" : "";
     if (empty($admin->email)) {
         module::set_var("registration", "email_verification", false);
     }
     // below lines added Shad Laws, v2
     $v->content->disable_admin_notify = empty($admin->email) || $form["policy"] !== "admin_approval" ? "disabled" : "";
     if (empty($admin->email)) {
         module::set_var("registration", "admin_notify", false);
     }
     $v->content->group_list = array();
     foreach (identity::groups() as $group) {
         if ($group->id != identity::everybody()->id && $group->id != identity::registered_users()->id) {
             $v->content->group_list[$group->id] = $group->name;
         }
     }
     $hidden = array("name" => "csrf", "value" => access::csrf_token());
     if (count($v->content->group_list)) {
         $v->content->group_list = array("" => t("Choose the default group")) + $v->content->group_list;
     } else {
         $hidden["group"] = "";
     }
     $v->content->hidden = $hidden;
     $v->content->pending = ORM::factory("pending_user")->find_all();
     $v->content->activate = "admin/register/activate";
     $v->content->form = $form;
     $v->content->errors = $errors;
     return $v;
 }
Ejemplo n.º 16
0
 /**
  * Import a single group.
  */
 static function import_group(&$queue)
 {
     $messages = array();
     $g2_group_id = array_shift($queue);
     if (self::map($g2_group_id)) {
         return;
     }
     try {
         $g2_group = g2(GalleryCoreApi::loadEntitiesById($g2_group_id));
     } catch (Exception $e) {
         throw new G2_Import_Exception(t("Failed to import Gallery 2 group with id: %id,", array("id" => $g2_group_id)), $e);
     }
     switch ($g2_group->getGroupType()) {
         case GROUP_NORMAL:
             try {
                 $group = identity::create_group($g2_group->getGroupName());
                 $messages[] = t("Group '%name' was imported", array("name" => $g2_group->getGroupname()));
             } catch (Exception $e) {
                 // Did it fail because of a duplicate group name?
                 $group = identity::lookup_group_by_name($g2_group->getGroupname());
                 if ($group) {
                     $messages[] = t("Group '%name' was mapped to the existing group group of the same name.", array("name" => $g2_group->getGroupname()));
                 } else {
                     throw new G2_Import_Exception(t("Failed to import group '%name'", array("name" => $g2_group->getGroupname())), $e);
                 }
             }
             break;
         case GROUP_ALL_USERS:
             $group = identity::registered_users();
             $messages[] = t("Group 'Registered' was converted to '%name'", array("name" => $group->name));
             break;
         case GROUP_SITE_ADMINS:
             $messages[] = t("Group 'Admin' does not exist in Gallery 3, skipping");
             break;
             // This is not a group in G3
         // This is not a group in G3
         case GROUP_EVERYBODY:
             $group = identity::everybody();
             $messages[] = t("Group 'Everybody' was converted to '%name'", array("name" => $group->name));
             break;
     }
     if (isset($group)) {
         self::set_map($g2_group->getId(), $group->id, "group");
     }
     return $messages;
 }
Ejemplo n.º 17
0
 public function moved_items_inherit_new_permissions_test()
 {
     identity::set_active_user(identity::lookup_user_by_name("admin"));
     $public_album = test::random_album();
     $public_photo = test::random_photo($public_album);
     access::allow(identity::everybody(), "view", $public_album);
     access::allow(identity::everybody(), "edit", $public_album);
     item::root()->reload();
     // Account for MPTT changes
     $private_album = test::random_album();
     access::deny(identity::everybody(), "view", $private_album);
     access::deny(identity::everybody(), "edit", $private_album);
     $private_photo = test::random_photo($private_album);
     // Make sure that we now have a public photo and private photo.
     $this->assert_true(access::group_can(identity::everybody(), "view", $public_photo));
     $this->assert_false(access::group_can(identity::everybody(), "view", $private_photo));
     // Swap the photos
     item::move($public_photo, $private_album);
     $private_album->reload();
     // Reload to get new MPTT pointers and cached perms.
     $public_album->reload();
     $private_photo->reload();
     $public_photo->reload();
     item::move($private_photo, $public_album);
     $private_album->reload();
     // Reload to get new MPTT pointers and cached perms.
     $public_album->reload();
     $private_photo->reload();
     $public_photo->reload();
     // Make sure that the public_photo is now private, and the private_photo is now public.
     $this->assert_false(access::group_can(identity::everybody(), "view", $public_photo));
     $this->assert_false(access::group_can(identity::everybody(), "edit", $public_photo));
     $this->assert_true(access::group_can(identity::everybody(), "view", $private_photo));
     $this->assert_true(access::group_can(identity::everybody(), "edit", $private_photo));
 }
Ejemplo n.º 18
0
 public function need_view_full_permission_to_view_original_test()
 {
     $album = test::random_album();
     $photo = test::random_photo($album);
     $album = $album->reload();
     // adding the photo changed the album in the db
     $_SERVER["REQUEST_URI"] = url::file("var/albums/{$album->name}/{$photo->name}");
     $controller = new File_Proxy_Controller();
     access::deny(identity::everybody(), "view_full", $album);
     identity::set_active_user(identity::guest());
     try {
         $controller->__call("", array());
         $this->assert_true(false);
     } catch (Kohana_404_Exception $e) {
         $this->assert_same(5, $e->test_fail_code);
     }
 }
Ejemplo n.º 19
0
 /**
  * Import a single group.
  */
 static function import_group(&$queue)
 {
     $g2_group_id = array_shift($queue);
     if (self::map($g2_group_id)) {
         return;
     }
     try {
         $g2_group = g2(GalleryCoreApi::loadEntitiesById($g2_group_id));
     } catch (Exception $e) {
         return t("Failed to import Gallery 2 group with id: %id\n%exception", array("id" => $g2_group_id, "exception" => $e->__toString()));
     }
     switch ($g2_group->getGroupType()) {
         case GROUP_NORMAL:
             try {
                 $group = identity::create_group($g2_group->getGroupName());
             } catch (Exception $e) {
                 // @todo For now we assume this is a "duplicate group" exception
                 $group = identity::lookup_user_by_name($g2_group->getGroupname());
             }
             $message = t("Group '%name' was imported", array("name" => $g2_group->getGroupname()));
             break;
         case GROUP_ALL_USERS:
             $group = identity::registered_users();
             $message = t("Group 'Registered' was converted to '%name'", array("name" => $group->name));
             break;
         case GROUP_SITE_ADMINS:
             $message = t("Group 'Admin' does not exist in Gallery 3, skipping");
             break;
             // This is not a group in G3
         // This is not a group in G3
         case GROUP_EVERYBODY:
             $group = identity::everybody();
             $message = t("Group 'Everybody' was converted to '%name'", array("name" => $group->name));
             break;
     }
     if (isset($group)) {
         self::set_map($g2_group->getId(), $group->id);
     }
     return $message;
 }
Ejemplo n.º 20
0
 public function as_restful_array_with_add_bit_test()
 {
     $response = item::root()->as_restful_array();
     $this->assert_true($response["can_add"]);
     access::deny(identity::everybody(), "add", item::root());
     identity::set_active_user(identity::guest());
     $response = item::root()->as_restful_array();
     $this->assert_false($response["can_add"]);
 }
Ejemplo n.º 21
0
 public function moved_items_inherit_new_permissions_test()
 {
     identity::set_active_user(identity::lookup_user_by_name("admin"));
     $root = ORM::factory("item", 1);
     $public_album = album::create($root, rand(), "public album");
     $public_photo = photo::create($public_album, MODPATH . "gallery/images/gallery.png", "", "");
     access::allow(identity::everybody(), "view", $public_album);
     $root->reload();
     // Account for MPTT changes
     $private_album = album::create($root, rand(), "private album");
     access::deny(identity::everybody(), "view", $private_album);
     $private_photo = photo::create($private_album, MODPATH . "gallery/images/gallery.png", "", "");
     // Make sure that we now have a public photo and private photo.
     $this->assert_true(access::group_can(identity::everybody(), "view", $public_photo));
     $this->assert_false(access::group_can(identity::everybody(), "view", $private_photo));
     // Swap the photos
     item::move($public_photo, $private_album);
     $private_album->reload();
     // Reload to get new MPTT pointers and cached perms.
     $public_album->reload();
     $private_photo->reload();
     $public_photo->reload();
     item::move($private_photo, $public_album);
     $private_album->reload();
     // Reload to get new MPTT pointers and cached perms.
     $public_album->reload();
     $private_photo->reload();
     $public_photo->reload();
     // Make sure that the public_photo is now private, and the private_photo is now public.
     $this->assert_false(access::group_can(identity::everybody(), "view", $public_photo));
     $this->assert_true(access::group_can(identity::everybody(), "view", $private_photo));
 }
Ejemplo n.º 22
0
 static function fix($task)
 {
     $start = microtime(true);
     $total = $task->get("total");
     if (empty($total)) {
         $item_count = db::build()->count_records("items");
         $total = 0;
         // mptt: 2 operations for every item
         $total += 2 * $item_count;
         // album audit (permissions and bogus album covers): 1 operation for every album
         $total += db::build()->where("type", "=", "album")->count_records("items");
         // one operation for each dupe slug, dupe name, dupe base name, and missing access cache
         foreach (array("find_dupe_slugs", "find_dupe_names", "find_dupe_base_names", "find_missing_access_caches") as $func) {
             foreach (self::$func() as $row) {
                 $total++;
             }
         }
         // one operation to rebuild path and url caches;
         $total += 1 * $item_count;
         $task->set("total", $total);
         $task->set("state", $state = self::FIX_STATE_START_MPTT);
         $task->set("ptr", 1);
         $task->set("completed", 0);
     }
     $completed = $task->get("completed");
     $state = $task->get("state");
     if (!module::get_var("gallery", "maintenance_mode")) {
         module::set_var("gallery", "maintenance_mode", 1);
     }
     // This is a state machine that checks each item in the database.  It verifies the following
     // attributes for an item.
     // 1. Left and right MPTT pointers are correct
     // 2. The .htaccess permission files for restricted items exist and are well formed.
     // 3. The relative_path_cache and relative_url_cache values are set to null.
     // 4. there are no album_cover_item_ids pointing to missing items
     //
     // We'll do a depth-first tree walk over our hierarchy using only the adjacency data because
     // we don't trust MPTT here (that might be what we're here to fix!).  Avoid avoid using ORM
     // calls as much as possible since they're expensive.
     //
     // NOTE: the MPTT check will only traverse items that have valid parents.  It's possible that
     // we have some tree corruption where there are items with parent ids to non-existent items.
     // We should probably do something about that.
     while ($state != self::FIX_STATE_DONE && microtime(true) - $start < 1.5) {
         switch ($state) {
             case self::FIX_STATE_START_MPTT:
                 $task->set("ptr", $ptr = 1);
                 $task->set("stack", item::root()->id . "L1");
                 $state = self::FIX_STATE_RUN_MPTT;
                 break;
             case self::FIX_STATE_RUN_MPTT:
                 $ptr = $task->get("ptr");
                 $stack = explode(" ", $task->get("stack"));
                 preg_match("/([0-9]+)([A-Z])([0-9]+)/", array_pop($stack), $matches);
                 // e.g. "12345L10"
                 list(, $id, $ptr_mode, $level) = $matches;
                 // Skip the 0th entry of matches.
                 switch ($ptr_mode) {
                     case "L":
                         // Albums could be parent nodes.
                         $stack[] = "{$id}R{$level}";
                         db::build()->update("items")->set("left_ptr", $ptr++)->where("id", "=", $id)->execute();
                         $level++;
                         foreach (db::build()->select(array("id", "type"))->from("items")->where("parent_id", "=", $id)->order_by("left_ptr", "DESC")->execute() as $child) {
                             $stack[] = $child->type == "album" ? "{$child->id}L{$level}" : "{$child->id}B{$level}";
                         }
                         $completed++;
                         break;
                     case "B":
                         // Non-albums must be leaf nodes.
                         db::build()->update("items")->set("left_ptr", $ptr++)->set("right_ptr", $ptr++)->set("level", $level)->set("relative_path_cache", null)->set("relative_url_cache", null)->where("id", "=", $id)->execute();
                         $completed += 2;
                         // we updated two pointers
                         break;
                     case "R":
                         db::build()->update("items")->set("right_ptr", $ptr++)->set("level", $level)->set("relative_path_cache", null)->set("relative_url_cache", null)->where("id", "=", $id)->execute();
                         $completed++;
                 }
                 $task->set("ptr", $ptr);
                 $task->set("stack", implode(" ", $stack));
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_DUPE_SLUGS;
                 }
                 break;
             case self::FIX_STATE_START_DUPE_SLUGS:
                 $stack = array();
                 foreach (self::find_dupe_slugs() as $row) {
                     list($parent_id, $slug) = explode(":", $row->parent_slug, 2);
                     $stack[] = join(":", array($parent_id, $slug));
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_DUPE_SLUGS;
                 } else {
                     $state = self::FIX_STATE_START_DUPE_NAMES;
                 }
                 break;
             case self::FIX_STATE_RUN_DUPE_SLUGS:
                 $stack = explode(" ", $task->get("stack"));
                 list($parent_id, $slug) = explode(":", array_pop($stack));
                 // We want to leave the first one alone and update all conflicts to be random values.
                 $fixed = 0;
                 $conflicts = ORM::factory("item")->where("parent_id", "=", $parent_id)->where("slug", "=", $slug)->find_all(1, 1);
                 if ($conflicts->count() && ($conflict = $conflicts->current())) {
                     $task->log("Fixing conflicting slug for item id {$conflict->id}");
                     db::build()->update("items")->set("slug", $slug . "-" . (string) rand(1000, 9999))->where("id", "=", $conflict->id)->execute();
                     // We fixed one conflict, but there might be more so put this parent back on the stack
                     // and try again.  We won't consider it completed when we don't fix a conflict.  This
                     // guarantees that we won't spend too long fixing one set of conflicts, and that we
                     // won't stop before all are fixed.
                     $stack[] = "{$parent_id}:{$slug}";
                     break;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_DUPE_NAMES;
                 }
                 break;
             case self::FIX_STATE_START_DUPE_NAMES:
                 $stack = array();
                 foreach (self::find_dupe_names() as $row) {
                     list($parent_id, $name) = explode(":", $row->parent_name, 2);
                     $stack[] = join(":", array($parent_id, $name));
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_DUPE_NAMES;
                 } else {
                     $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
                 }
                 break;
             case self::FIX_STATE_RUN_DUPE_NAMES:
                 // NOTE: This does *not* attempt to fix the file system!
                 $stack = explode(" ", $task->get("stack"));
                 list($parent_id, $name) = explode(":", array_pop($stack));
                 $fixed = 0;
                 // We want to leave the first one alone and update all conflicts to be random values.
                 $conflicts = ORM::factory("item")->where("parent_id", "=", $parent_id)->where("name", "=", $name)->find_all(1, 1);
                 if ($conflicts->count() && ($conflict = $conflicts->current())) {
                     $task->log("Fixing conflicting name for item id {$conflict->id}");
                     if (!$conflict->is_album() && preg_match("/^(.*)(\\.[^\\.\\/]*?)\$/", $conflict->name, $matches)) {
                         $item_base_name = $matches[1];
                         $item_extension = $matches[2];
                         // includes a leading dot
                     } else {
                         $item_base_name = $conflict->name;
                         $item_extension = "";
                     }
                     db::build()->update("items")->set("name", $item_base_name . "-" . (string) rand(1000, 9999) . $item_extension)->where("id", "=", $conflict->id)->execute();
                     // We fixed one conflict, but there might be more so put this parent back on the stack
                     // and try again.  We won't consider it completed when we don't fix a conflict.  This
                     // guarantees that we won't spend too long fixing one set of conflicts, and that we
                     // won't stop before all are fixed.
                     $stack[] = "{$parent_id}:{$name}";
                     break;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
                 }
                 break;
             case self::FIX_STATE_START_DUPE_BASE_NAMES:
                 $stack = array();
                 foreach (self::find_dupe_base_names() as $row) {
                     list($parent_id, $base_name) = explode(":", $row->parent_base_name, 2);
                     $stack[] = join(":", array($parent_id, $base_name));
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_DUPE_BASE_NAMES;
                 } else {
                     $state = self::FIX_STATE_START_ALBUMS;
                 }
                 break;
             case self::FIX_STATE_RUN_DUPE_BASE_NAMES:
                 // NOTE: This *does* attempt to fix the file system!  So, it must go *after* run_dupe_names.
                 $stack = explode(" ", $task->get("stack"));
                 list($parent_id, $base_name) = explode(":", array_pop($stack));
                 $base_name_escaped = Database::escape_for_like($base_name);
                 $fixed = 0;
                 // We want to leave the first one alone and update all conflicts to be random values.
                 $conflicts = ORM::factory("item")->where("parent_id", "=", $parent_id)->where("name", "LIKE", "{$base_name_escaped}.%")->where("type", "<>", "album")->find_all(1, 1);
                 if ($conflicts->count() && ($conflict = $conflicts->current())) {
                     $task->log("Fixing conflicting name for item id {$conflict->id}");
                     if (preg_match("/^(.*)(\\.[^\\.\\/]*?)\$/", $conflict->name, $matches)) {
                         $item_base_name = $matches[1];
                         // unlike $base_name, this always maintains capitalization
                         $item_extension = $matches[2];
                         // includes a leading dot
                     } else {
                         $item_base_name = $conflict->name;
                         $item_extension = "";
                     }
                     // Unlike conflicts found in run_dupe_names, these items are likely to have an intact
                     // file system.  Let's use the item save logic to rebuild the paths and rename the files
                     // if possible.
                     try {
                         $conflict->name = $item_base_name . "-" . (string) rand(1000, 9999) . $item_extension;
                         $conflict->validate();
                         // If we get here, we're safe to proceed with save
                         $conflict->save();
                     } catch (Exception $e) {
                         // Didn't work.  Edit database directly without fixing file system.
                         db::build()->update("items")->set("name", $item_base_name . "-" . (string) rand(1000, 9999) . $item_extension)->where("id", "=", $conflict->id)->execute();
                     }
                     // We fixed one conflict, but there might be more so put this parent back on the stack
                     // and try again.  We won't consider it completed when we don't fix a conflict.  This
                     // guarantees that we won't spend too long fixing one set of conflicts, and that we
                     // won't stop before all are fixed.
                     $stack[] = "{$parent_id}:{$base_name}";
                     break;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_ALBUMS;
                 }
                 break;
             case self::FIX_STATE_START_ALBUMS:
                 $stack = array();
                 foreach (db::build()->select("id")->from("items")->where("type", "=", "album")->execute() as $row) {
                     $stack[] = $row->id;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $state = self::FIX_STATE_RUN_ALBUMS;
                 break;
             case self::FIX_STATE_RUN_ALBUMS:
                 $stack = explode(" ", $task->get("stack"));
                 $id = array_pop($stack);
                 $item = ORM::factory("item", $id);
                 if ($item->album_cover_item_id) {
                     $album_cover_item = ORM::factory("item", $item->album_cover_item_id);
                     if (!$album_cover_item->loaded()) {
                         $item->album_cover_item_id = null;
                         $item->save();
                     }
                 }
                 $everybody = identity::everybody();
                 $view_col = "view_{$everybody->id}";
                 $view_full_col = "view_full_{$everybody->id}";
                 $intent = ORM::factory("access_intent")->where("item_id", "=", $id)->find();
                 if ($intent->{$view_col} === access::DENY) {
                     access::update_htaccess_files($item, $everybody, "view", access::DENY);
                 }
                 if ($intent->{$view_full_col} === access::DENY) {
                     access::update_htaccess_files($item, $everybody, "view_full", access::DENY);
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_REBUILD_ITEM_CACHES;
                 }
                 break;
             case self::FIX_STATE_START_REBUILD_ITEM_CACHES:
                 $stack = array();
                 foreach (self::find_empty_item_caches(500) as $row) {
                     $stack[] = $row->id;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $state = self::FIX_STATE_RUN_REBUILD_ITEM_CACHES;
                 break;
             case self::FIX_STATE_RUN_REBUILD_ITEM_CACHES:
                 $stack = explode(" ", $task->get("stack"));
                 if (!empty($stack)) {
                     $id = array_pop($stack);
                     $item = ORM::factory("item", $id);
                     $item->relative_path();
                     // this rebuilds the cache and saves the item as a side-effect
                     $task->set("stack", implode(" ", $stack));
                     $completed++;
                 }
                 if (empty($stack)) {
                     // Try refilling the stack
                     foreach (self::find_empty_item_caches(500) as $row) {
                         $stack[] = $row->id;
                     }
                     $task->set("stack", implode(" ", $stack));
                     if (empty($stack)) {
                         $state = self::FIX_STATE_START_MISSING_ACCESS_CACHES;
                     }
                 }
                 break;
             case self::FIX_STATE_START_MISSING_ACCESS_CACHES:
                 $stack = array();
                 foreach (self::find_missing_access_caches_limited(500) as $row) {
                     $stack[] = $row->id;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $state = self::FIX_STATE_RUN_MISSING_ACCESS_CACHES;
                 break;
             case self::FIX_STATE_RUN_MISSING_ACCESS_CACHES:
                 $stack = array_filter(explode(" ", $task->get("stack")));
                 // filter removes empty/zero ids
                 if (!empty($stack)) {
                     $id = array_pop($stack);
                     $access_cache = ORM::factory("access_cache");
                     $access_cache->item_id = $id;
                     $access_cache->save();
                     $task->set("stack", implode(" ", $stack));
                     $completed++;
                 }
                 if (empty($stack)) {
                     // Try refilling the stack
                     foreach (self::find_missing_access_caches_limited(500) as $row) {
                         $stack[] = $row->id;
                     }
                     $task->set("stack", implode(" ", $stack));
                     if (empty($stack)) {
                         // The new cache rows are there, but they're incorrectly populated so we have to fix
                         // them.  If this turns out to be too slow, we'll have to refactor
                         // access::recalculate_permissions to allow us to do it in slices.
                         access::recalculate_album_permissions(item::root());
                         $state = self::FIX_STATE_DONE;
                     }
                 }
                 break;
         }
     }
     $task->set("state", $state);
     $task->set("completed", $completed);
     if ($state == self::FIX_STATE_DONE) {
         $task->done = true;
         $task->state = "success";
         $task->percent_complete = 100;
         module::set_var("gallery", "maintenance_mode", 0);
     } else {
         $task->percent_complete = round(100 * $completed / $total);
     }
     $task->status = t2("One operation complete", "%count / %total operations complete", $completed, array("total" => $total));
 }
Ejemplo n.º 23
0
 public function delete_album_fails_without_permission_test()
 {
     $album1 = test::random_album();
     access::deny(identity::everybody(), "edit", $album1);
     identity::set_active_user(identity::guest());
     $request->url = rest::url("item", $album1);
     try {
         item_rest::delete($request);
     } catch (Exception $e) {
         $this->assert_equal("@todo FORBIDDEN", $e->getMessage());
         return;
     }
     $this->assert_true(false, "Shouldn't get here");
 }
Ejemplo n.º 24
0
 static function fix($task)
 {
     $start = microtime(true);
     $total = $task->get("total");
     if (empty($total)) {
         // mptt: 2 operations for every item
         $total = 2 * db::build()->count_records("items");
         // album audit (permissions and bogus album covers): 1 operation for every album
         $total += db::build()->where("type", "=", "album")->count_records("items");
         // one operation for each missing slug, name and access cache
         foreach (array("find_dupe_slugs", "find_dupe_names", "find_missing_access_caches") as $func) {
             foreach (self::$func() as $row) {
                 $total++;
             }
         }
         $task->set("total", $total);
         $task->set("state", $state = self::FIX_STATE_START_MPTT);
         $task->set("ptr", 1);
         $task->set("completed", 0);
     }
     $completed = $task->get("completed");
     $state = $task->get("state");
     if (!module::get_var("gallery", "maintenance_mode")) {
         module::set_var("gallery", "maintenance_mode", 1);
     }
     // This is a state machine that checks each item in the database.  It verifies the following
     // attributes for an item.
     // 1. Left and right MPTT pointers are correct
     // 2. The .htaccess permission files for restricted items exist and are well formed.
     // 3. The relative_path_cache and relative_url_cache values are set to null.
     // 4. there are no album_cover_item_ids pointing to missing items
     //
     // We'll do a depth-first tree walk over our hierarchy using only the adjacency data because
     // we don't trust MPTT here (that might be what we're here to fix!).  Avoid avoid using ORM
     // calls as much as possible since they're expensive.
     //
     // NOTE: the MPTT check will only traverse items that have valid parents.  It's possible that
     // we have some tree corruption where there are items with parent ids to non-existent items.
     // We should probably do something about that.
     while ($state != self::FIX_STATE_DONE && microtime(true) - $start < 1.5) {
         switch ($state) {
             case self::FIX_STATE_START_MPTT:
                 $task->set("ptr", $ptr = 1);
                 $task->set("stack", item::root()->id . ":L");
                 $state = self::FIX_STATE_RUN_MPTT;
                 break;
             case self::FIX_STATE_RUN_MPTT:
                 $ptr = $task->get("ptr");
                 $stack = explode(" ", $task->get("stack"));
                 list($id, $ptr_mode) = explode(":", array_pop($stack));
                 if ($ptr_mode == "L") {
                     $stack[] = "{$id}:R";
                     db::build()->update("items")->set("left_ptr", $ptr++)->where("id", "=", $id)->execute();
                     foreach (db::build()->select(array("id"))->from("items")->where("parent_id", "=", $id)->order_by("left_ptr", "ASC")->execute() as $child) {
                         array_push($stack, "{$child->id}:L");
                     }
                 } else {
                     if ($ptr_mode == "R") {
                         db::build()->update("items")->set("right_ptr", $ptr++)->set("relative_path_cache", null)->set("relative_url_cache", null)->where("id", "=", $id)->execute();
                     }
                 }
                 $task->set("ptr", $ptr);
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_DUPE_SLUGS;
                 }
                 break;
             case self::FIX_STATE_START_DUPE_SLUGS:
                 $stack = array();
                 foreach (self::find_dupe_slugs() as $row) {
                     list($parent_id, $slug) = explode(":", $row->parent_slug, 2);
                     $stack[] = join(":", array($parent_id, $slug));
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_DUPE_SLUGS;
                 } else {
                     $state = self::FIX_STATE_START_DUPE_NAMES;
                 }
                 break;
             case self::FIX_STATE_RUN_DUPE_SLUGS:
                 $stack = explode(" ", $task->get("stack"));
                 list($parent_id, $slug) = explode(":", array_pop($stack));
                 // We want to leave the first one alone and update all conflicts to be random values.
                 $fixed = 0;
                 $conflicts = ORM::factory("item")->where("parent_id", "=", $parent_id)->where("slug", "=", $slug)->find_all(1, 1);
                 if ($conflicts->count() && ($conflict = $conflicts->current())) {
                     $task->log("Fixing conflicting slug for item id {$conflict->id}");
                     db::build()->update("items")->set("slug", $slug . "-" . (string) rand(1000, 9999))->where("id", "=", $conflict->id)->execute();
                     // We fixed one conflict, but there might be more so put this parent back on the stack
                     // and try again.  We won't consider it completed when we don't fix a conflict.  This
                     // guarantees that we won't spend too long fixing one set of conflicts, and that we
                     // won't stop before all are fixed.
                     $stack[] = "{$parent_id}:{$slug}";
                     break;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_DUPE_NAMES;
                 }
                 break;
             case self::FIX_STATE_START_DUPE_NAMES:
                 $stack = array();
                 foreach (self::find_dupe_names() as $row) {
                     list($parent_id, $name) = explode(":", $row->parent_name, 2);
                     $stack[] = join(":", array($parent_id, $name));
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_DUPE_NAMES;
                 } else {
                     $state = self::FIX_STATE_START_ALBUMS;
                 }
                 break;
             case self::FIX_STATE_RUN_DUPE_NAMES:
                 $stack = explode(" ", $task->get("stack"));
                 list($parent_id, $name) = explode(":", array_pop($stack));
                 $fixed = 0;
                 // We want to leave the first one alone and update all conflicts to be random values.
                 $conflicts = ORM::factory("item")->where("parent_id", "=", $parent_id)->where("name", "=", $name)->find_all(1, 1);
                 if ($conflicts->count() && ($conflict = $conflicts->current())) {
                     $task->log("Fixing conflicting name for item id {$conflict->id}");
                     db::build()->update("items")->set("name", $name . "-" . (string) rand(1000, 9999))->where("id", "=", $conflict->id)->execute();
                     // We fixed one conflict, but there might be more so put this parent back on the stack
                     // and try again.  We won't consider it completed when we don't fix a conflict.  This
                     // guarantees that we won't spend too long fixing one set of conflicts, and that we
                     // won't stop before all are fixed.
                     $stack[] = "{$parent_id}:{$name}";
                     break;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_ALBUMS;
                 }
                 break;
             case self::FIX_STATE_START_ALBUMS:
                 $stack = array();
                 foreach (db::build()->select("id")->from("items")->where("type", "=", "album")->execute() as $row) {
                     $stack[] = $row->id;
                 }
                 $task->set("stack", implode(" ", $stack));
                 $state = self::FIX_STATE_RUN_ALBUMS;
                 break;
             case self::FIX_STATE_RUN_ALBUMS:
                 $stack = explode(" ", $task->get("stack"));
                 $id = array_pop($stack);
                 $item = ORM::factory("item", $id);
                 if ($item->album_cover_item_id) {
                     $album_cover_item = ORM::factory("item", $item->album_cover_item_id);
                     if (!$album_cover_item->loaded()) {
                         $item->album_cover_item_id = null;
                         $item->save();
                     }
                 }
                 $everybody = identity::everybody();
                 $view_col = "view_{$everybody->id}";
                 $view_full_col = "view_full_{$everybody->id}";
                 $intent = ORM::factory("access_intent")->where("item_id", "=", $id)->find();
                 if ($intent->{$view_col} === access::DENY) {
                     access::update_htaccess_files($item, $everybody, "view", access::DENY);
                 }
                 if ($intent->{$view_full_col} === access::DENY) {
                     access::update_htaccess_files($item, $everybody, "view_full", access::DENY);
                 }
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     $state = self::FIX_STATE_START_MISSING_ACCESS_CACHES;
                 }
                 break;
             case self::FIX_STATE_START_MISSING_ACCESS_CACHES:
                 $stack = array();
                 foreach (self::find_missing_access_caches() as $row) {
                     $stack[] = $row->id;
                 }
                 if ($stack) {
                     $task->set("stack", implode(" ", $stack));
                     $state = self::FIX_STATE_RUN_MISSING_ACCESS_CACHES;
                 } else {
                     $state = self::FIX_STATE_DONE;
                 }
                 break;
             case self::FIX_STATE_RUN_MISSING_ACCESS_CACHES:
                 $stack = explode(" ", $task->get("stack"));
                 $id = array_pop($stack);
                 $access_cache = ORM::factory("access_cache");
                 $access_cache->item_id = $id;
                 $access_cache->save();
                 $task->set("stack", implode(" ", $stack));
                 $completed++;
                 if (empty($stack)) {
                     // The new cache rows are there, but they're incorrectly populated so we have to fix
                     // them.  If this turns out to be too slow, we'll have to refactor
                     // access::recalculate_permissions to allow us to do it in slices.
                     access::recalculate_album_permissions(item::root());
                     $state = self::FIX_STATE_DONE;
                 }
                 break;
         }
     }
     $task->set("state", $state);
     $task->set("completed", $completed);
     if ($state == self::FIX_STATE_DONE) {
         $task->done = true;
         $task->state = "success";
         $task->percent_complete = 100;
         module::set_var("gallery", "maintenance_mode", 0);
     } else {
         $task->percent_complete = round(100 * $completed / $total);
     }
     $task->status = t2("One operation complete", "%count / %total operations complete", $completed, array("total" => $total));
 }
Ejemplo n.º 25
0
 /**
  * Rebuild the .htaccess files that prevent direct access to albums, resizes and thumbnails.  We
  * call this internally any time we change the view or view_full permissions for guest users.
  * This function is only public because we use it in maintenance tasks.
  *
  * @param  Item_Model   the album
  * @param  Group_Model  the group whose permission is changing
  * @param  string       the permission name
  * @param  string       the new permission value (eg access::DENY)
  */
 static function update_htaccess_files($album, $group, $perm_name, $value)
 {
     if ($group->id != identity::everybody()->id || !($perm_name == "view" || $perm_name == "view_full")) {
         return;
     }
     $dirs = array($album->file_path());
     if ($perm_name == "view") {
         $dirs[] = dirname($album->resize_path());
         $dirs[] = dirname($album->thumb_path());
     }
     $base_url = url::base(true);
     $sep = "?";
     if (strpos($base_url, "?") !== false) {
         $sep = "&";
     }
     $base_url .= $sep . "kohana_uri=/file_proxy";
     // Replace "/index.php/?kohana..." with "/index.php?koahan..."
     // Doesn't apply to "/?kohana..." or "/foo/?kohana..."
     // Can't check for "index.php" since the file might be renamed, and
     // there might be more Apache aliases / rewrites at work.
     $url_path = parse_url($base_url, PHP_URL_PATH);
     // Does the URL path have a file component?
     if (preg_match("#[^/]+\\.php#i", $url_path)) {
         $base_url = str_replace("/?", "?", $base_url);
     }
     foreach ($dirs as $dir) {
         if ($value === access::DENY) {
             $fp = fopen("{$dir}/.htaccess", "w+");
             fwrite($fp, "<IfModule mod_rewrite.c>\n");
             fwrite($fp, "  RewriteEngine On\n");
             fwrite($fp, "  RewriteRule (.*) {$base_url}/\$1 [L]\n");
             fwrite($fp, "</IfModule>\n");
             fwrite($fp, "<IfModule !mod_rewrite.c>\n");
             fwrite($fp, "  Order Deny,Allow\n");
             fwrite($fp, "  Deny from All\n");
             fwrite($fp, "</IfModule>\n");
             fclose($fp);
         } else {
             @unlink($dir . "/.htaccess");
         }
     }
 }
Ejemplo n.º 26
0
 static function hotfix_all()
 {
     $messages = array();
     $messages[] = t('Running Hotfix');
     /* ON THE LAST RUN WE NEED TO RE-FIX ALL DAMAGED ALBUM THUMBS! */
     $albumDir = self::$album_dir;
     if (substr($albumDir, -1) != DIRECTORY_SEPARATOR) {
         $albumDir .= DIRECTORY_SEPARATOR;
     }
     foreach (self::$albums_flat as $g1_album) {
         $album_id = self::map($g1_album, '', 'album');
         if (!$album_id) {
             $messages[] = t('Album %name not found', array('name' => $g1_album));
             continue;
         }
         $album = ORM::factory('item', $album_id);
         $importDir = $albumDir . $g1_album . DIRECTORY_SEPARATOR;
         try {
             require_once 'Gallery1DataParser.php';
             list($result, $items) = Gallery1DataParser::getPhotos($importDir);
             if ($result == null) {
                 foreach ($items as $object) {
                     if (isset($object->highlight) && $object->highlight == 1 && isset($object->highlightImage) && is_a($object->highlightImage, 'G1Img')) {
                         $g1_path = $importDir . $object->highlightImage->name . '.' . $object->highlightImage->type;
                         if (is_file($g1_path) && @copy($g1_path, $album->thumb_path())) {
                             $album->thumb_height = $object->highlightImage->height;
                             $album->thumb_width = $object->highlightImage->width;
                             $album->thumb_dirty = false;
                             $album->save();
                         }
                     }
                 }
             }
         } catch (Exception $e) {
             $messages[] = (string) new G1_Import_Exception(t('Failed to copy thumb for album %name.', array('name' => $g1_album)), $e);
         }
     }
     /* ON THE LAST RUN WE NEED TO RE-FIX ALL ALBUM PERMISSIONS */
     foreach (self::$albums_hidden as $g1_album => $dummy) {
         try {
             $album_id = self::map($g1_album, '', 'album');
             $album = ORM::factory('item', $album_id);
             access::deny(identity::everybody(), 'view', $album);
             $messages[] = t('Denying access to %album', array('album' => $g1_album));
         } catch (Exception $e) {
             $messages[] = (string) new G1_Import_Exception(t('Failed to set access permission for hidden album %name.', array('name' => $g1_album)), $e);
         }
     }
     return $messages;
 }