Safety-related privileges; internals

This commit is contained in:
Marcin Kurczewski 2013-10-07 23:17:33 +02:00
parent bc01fd7dce
commit bb9ab81fed
12 changed files with 99 additions and 40 deletions

View file

@ -28,5 +28,12 @@ Kind regards,
[privileges] [privileges]
uploadPost=registered uploadPost=registered
viewPost=anonymous
viewPost.sketchy=registered
viewPost.unsafe=registered
listPosts=anonymous listPosts=anonymous
listPosts.sketchy=registered
listPosts.unsafe=registered
listUsers=registered listUsers=registered
listComments=registered
retrievePost=anonymous

View file

@ -34,7 +34,8 @@ class PostController
$params[':limit'] = 20; $params[':limit'] = 20;
$params[':offset'] = ($page - 1) * $params[':limit']; $params[':offset'] = ($page - 1) * $params[':limit'];
//todo safety //todo safety [user choice]
//todo safety [user privileges]
//todo construct WHERE based on filters //todo construct WHERE based on filters
$whereSql = ''; $whereSql = '';
@ -138,8 +139,8 @@ class PostController
if (!$post) if (!$post)
throw new SimpleException('Invalid post ID "' . $id . '"'); throw new SimpleException('Invalid post ID "' . $id . '"');
//todo: verify access rank...? PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
//todo: verify sketchy, nsfw, sfw PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
$this->context->subTitle = 'showing @' . $post->id; $this->context->subTitle = 'showing @' . $post->id;
$this->context->transport->post = $post; $this->context->transport->post = $post;
@ -147,9 +148,9 @@ class PostController
/** /**
* Action that renders the requested file itself and sends it to user. * Action that renders the requested file itself and sends it to user.
* @route /post/send/{name} * @route /post/retrieve/{name}
*/ */
public function sendAction($name) public function retrieveAction($name)
{ {
$this->context->layoutName = 'layout-file'; $this->context->layoutName = 'layout-file';
@ -157,10 +158,8 @@ class PostController
if (!$post) if (!$post)
throw new SimpleException('Invalid post name "' . $name . '"'); throw new SimpleException('Invalid post name "' . $name . '"');
//I guess access rank shouldn't be verified here. If someone arrives PrivilegesHelper::confirmWithException($this->context->user, Privilege::RetrievePost);
//here, they already know the full name of the post (not just the ID) PrivilegesHelper::confirmWithException($this->context->user, Privilege::RetrievePost, PostSafety::toString($post->safety));
//either by visiting the HTML container page or by having hotlink.
//Such users should be trusted.
$path = $this->config->main->filesPath . DIRECTORY_SEPARATOR . $post->name; $path = $this->config->main->filesPath . DIRECTORY_SEPARATOR . $post->name;
if (!file_exists($path)) if (!file_exists($path))

10
src/Enum.php Normal file
View file

@ -0,0 +1,10 @@
<?php
class Enum
{
public static function toString($constant)
{
$cls = new ReflectionClass(get_called_class());
$constants = $cls->getConstants();
return array_search($constant, $constants);
}
}

View file

@ -5,26 +5,45 @@ class PrivilegesHelper
public static function init() public static function init()
{ {
$privileges = \Chibi\Registry::getConfig()->privileges; self::$privileges = [];
foreach ($privileges as $privilegeName => $minAccessRankName) foreach (\Chibi\Registry::getConfig()->privileges as $key => $minAccessRankName)
{ {
$privilege = TextHelper::resolveConstant($privilegeName, 'Privilege'); if (strpos($key, '.') === false)
$key .= '.';
list ($privilegeName, $flag) = explode('.', $key);
$privilegeName = TextHelper::camelCaseToKebabCase($privilegeName);
$flag = TextHelper::camelCaseToKebabCase($flag);
$key = rtrim($privilegeName . '.' . $flag, '.');
$minAccessRank = TextHelper::resolveConstant($minAccessRankName, 'AccessRank'); $minAccessRank = TextHelper::resolveConstant($minAccessRankName, 'AccessRank');
self::$privileges[$privilege] = $minAccessRank; self::$privileges[$key] = $minAccessRank;
} }
} }
public static function confirm($user, $privilege) public static function confirm($user, $privilege, $flag = null)
{ {
$minAccessRank = isset(self::$privileges[$privilege]) $minAccessRank = AccessRank::Admin;
? self::$privileges[$privilege]
: AccessRank::Admin; $key = TextHelper::camelCaseToKebabCase(Privilege::toString($privilege));
if (isset(self::$privileges[$key]))
{
$minAccessRank = self::$privileges[$key];
}
if ($flag != null)
{
$key2 = $key . '.' . strtolower($flag);
if (isset(self::$privileges[$key2]))
{
$minAccessRank = self::$privileges[$key2];
}
}
return intval($user->access_rank) >= $minAccessRank; return intval($user->access_rank) >= $minAccessRank;
} }
public static function confirmWithException($user, $privilege) public static function confirmWithException($user, $privilege, $flag = null)
{ {
if (!self::confirm($user, $privilege)) if (!self::confirm($user, $privilege, $flag))
{ {
throw new SimpleException('Insufficient privileges'); throw new SimpleException('Insufficient privileges');
} }

View file

@ -17,13 +17,29 @@ class TextHelper
return $text; return $text;
} }
public static function kebabCaseToCamelCase($string)
{
$string = preg_split('/-/', $string);
$string = array_map('trim', $string);
$string = array_map('ucfirst', $string);
$string = join('', $string);
return $string;
}
public static function camelCaseToKebabCase($string)
{
$string = preg_replace_callback('/[A-Z]/', function($x)
{
return '-' . strtolower($x[0]);
}, $string);
$string = trim($string, '-');
return $string;
}
public static function resolveConstant($constantName, $className = null) public static function resolveConstant($constantName, $className = null)
{ {
$constantName = self::kebabCaseToCamelCase($constantName);
//convert from kebab-case to CamelCase //convert from kebab-case to CamelCase
$constantName = preg_split('/-/', $constantName);
$constantName = array_map('trim', $constantName);
$constantName = array_map('ucfirst', $constantName);
$constantName = join('', $constantName);
if ($className !== null) if ($className !== null)
{ {
$constantName = $className . '::' . $constantName; $constantName = $className . '::' . $constantName;

View file

@ -1,5 +1,5 @@
<?php <?php
class AccessRank class AccessRank extends Enum
{ {
const Anonymous = 0; const Anonymous = 0;
const Registered = 1; const Registered = 1;

View file

@ -1,5 +1,5 @@
<?php <?php
class PostSafety class PostSafety extends Enum
{ {
const Safe = 1; const Safe = 1;
const Sketchy = 2; const Sketchy = 2;

View file

@ -1,5 +1,5 @@
<?php <?php
class PostType class PostType extends Enum
{ {
const Image = 1; const Image = 1;
const Flash = 2; const Flash = 2;

View file

@ -1,7 +1,10 @@
<?php <?php
class Privilege class Privilege extends Enum
{ {
const UploadPost = 1; const ListPosts = 1;
const ListPosts = 2; const UploadPost = 2;
const ListUsers = 3; const ViewPost = 3;
const RetrievePost = 4;
const ListUsers = 5;
const ListComments = 6;
} }

View file

@ -27,13 +27,14 @@
$nav = []; $nav = [];
$nav []= ['Home', \Chibi\UrlHelper::route('index', 'index')]; $nav []= ['Home', \Chibi\UrlHelper::route('index', 'index')];
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts))
$nav []= ['Browse', \Chibi\UrlHelper::route('post', 'list')]; $nav []= ['Browse', \Chibi\UrlHelper::route('post', 'list')];
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts)) if (PrivilegesHelper::confirm($this->context->user, Privilege::ListComments))
{
$nav []= ['Comments', \Chibi\UrlHelper::route('comment', 'list')]; $nav []= ['Comments', \Chibi\UrlHelper::route('comment', 'list')];
if (PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts))
$nav []= ['Favorites', \Chibi\UrlHelper::route('post', 'favorites')]; $nav []= ['Favorites', \Chibi\UrlHelper::route('post', 'favorites')];
}
if (PrivilegesHelper::confirm($this->context->user, Privilege::UploadPost)) if (PrivilegesHelper::confirm($this->context->user, Privilege::UploadPost))
$nav []= ['Upload', \Chibi\UrlHelper::route('post', 'upload')]; $nav []= ['Upload', \Chibi\UrlHelper::route('post', 'upload')];

View file

@ -1,5 +1,9 @@
<?php if (!empty($this->context->transport->errorMessage)): ?>
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
<?php else: ?>
<?php foreach ($this->context->transport->posts as $post): ?> <?php foreach ($this->context->transport->posts as $post): ?>
<a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $post->id]) ?>"> <a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $post->id]) ?>">
Post&nbsp;<?php echo $post->id; ?> Post&nbsp;<?php echo $post->id; ?>
</a> </a>
<?php endforeach ?> <?php endforeach ?>
<?php endif ?>

View file

@ -1,5 +1,5 @@
<?php if (!empty($this->context->transport->errorMessage)): ?> <?php if (!empty($this->context->transport->errorMessage)): ?>
<p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p> <p class="alert alert-error"><?php echo $this->context->transport->errorMessage ?></p>
<?php else: ?> <?php else: ?>
<img src="<?php echo \Chibi\UrlHelper::route('post', 'send', ['name' => $this->context->transport->post->name]) ?>" alt="<?php echo $this->context->transport->post->name ?>"/> <img src="<?php echo \Chibi\UrlHelper::route('post', 'retrieve', ['name' => $this->context->transport->post->name]) ?>" alt="<?php echo $this->context->transport->post->name ?>"/>
<?php endif ?> <?php endif ?>