// if a parent is specified, make sure it exists and belongs to the user; get its root (first-level) folder if it's a nested folder
$p = $this->db->prepare(
"WITH RECURSIVE folders(id) as (SELECT id from arsse_folders where owner is ? and id is ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id) ".
"SELECT id,(id not in (select id from folders)) as valid from arsse_folders where owner is ? and id is ?",
"SELECT id,(id not in (select id from folders)) as valid from arsse_folders where owner is ? and id is ?",
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[0])->thenReturn(1)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[1])->thenReturn(2)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[0])->thenReturn(1)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderAdd(Data::$user->id, $in[1])->thenReturn(2)->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 3, $this->anything())->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); // folder ID 3 does not exist
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
Phake::when(Data::$db)->folderPropertiesSet(Data::$user->id, 3, $this->anything())->thenThrow(new \JKingWeb\Arsse\Db\ExceptionInput("idMissing")); // folder ID 3 does not exist
function setUp(string $drv = Test\User\DriverInternalMock::class, string $db = null) {
$this->clearData();
$conf = new Conf();
$conf->userDriver = $drv;
$conf->userAuthPreferHTTP = true;
$conf->userComposeNames = true;
Data::$conf = $conf;
if($db !== null) {
Data::$db = new $db();
}
Data::$user = new User();
Data::$user->authorizationEnabled(false);
foreach(self::USERS as $user => $level) {
Data::$user->add($user, "");
Data::$user->rightsSet($user, $level);
}
Data::$user->authorizationEnabled(true);
}
$this->clearData();
$conf = new Conf();
$conf->userDriver = $drv;
$conf->userAuthPreferHTTP = true;
$conf->userComposeNames = true;
Data::$conf = $conf;
if($db !== null) {
Data::$db = new $db();
}
Data::$user = new User();
Data::$user->authorizationEnabled(false);
foreach(self::USERS as $user => $level) {
Data::$user->add($user, "");
Data::$user->rightsSet($user, $level);
}
Data::$user->authorizationEnabled(true);
}
function tearDown() {
$this->clearData();
}
function tearDown() {
$this->clearData();
}
function testSelfActionLogic() {
foreach(array_keys(self::USERS) as $user) {
Data::$user->auth($user, "");
// users should be able to do basic actions for themselves
$this->assertTrue(Data::$user->authorize($user, "userExists"), "User $user could not act for themselves.");
$this->assertTrue(Data::$user->authorize($user, "userRemove"), "User $user could not act for themselves.");
}
}
function testSelfActionLogic() {
foreach(array_keys(self::USERS) as $user) {
Data::$user->auth($user, "");
// users should be able to do basic actions for themselves
$this->assertTrue(Data::$user->authorize($user, "userExists"), "User $user could not act for themselves.");
$this->assertTrue(Data::$user->authorize($user, "userRemove"), "User $user could not act for themselves.");
}
}
function testRegularUserLogic() {
foreach(self::USERS as $actor => $rights) {
if($rights != User\Driver::RIGHTS_NONE) continue;
Data::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// regular users should only be able to act for themselves
if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
function testRegularUserLogic() {
foreach(self::USERS as $actor => $rights) {
if($rights != User\Driver::RIGHTS_NONE) continue;
Data::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// regular users should only be able to act for themselves
if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users
foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users
foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
foreach(self::USERS as $affected => $affectedRights) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
foreach(self::LEVELS as $level) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
}
}
foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
foreach(self::USERS as $affected => $affectedRights) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
foreach(self::LEVELS as $level) {
$this->assertTrue(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
}
}
foreach(self::DOMAINS as $domain) {
$this->assertTrue(Data::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
}
}
}
function testInvalidLevelLogic() {
foreach(self::USERS as $actor => $rights) {
if(in_array($rights, self::LEVELS)) continue;
Data::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves
if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
function testInvalidLevelLogic() {
foreach(self::USERS as $actor => $rights) {
if(in_array($rights, self::LEVELS)) continue;
Data::$user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves
if($actor==$affected) {
$this->assertTrue(Data::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue(Data::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse(Data::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse(Data::$user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse(Data::$user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse(Data::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
function testInternalExceptionLogic() {
$tests = [
// methods of User class to test, with parameters besides affected user