mirror of
https://github.com/typemill/typemill.git
synced 2025-08-06 06:07:31 +02:00
Version 1.1.6 User Role, Fieldsets and Refactoring
This commit is contained in:
@@ -7,6 +7,7 @@ use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\User;
|
||||
use Typemill\Models\WriteYaml;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
@@ -34,9 +35,37 @@ class AuthController extends Controller
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$this->c->view->render($response, '/auth/login.twig');
|
||||
}
|
||||
$data = array();
|
||||
|
||||
/* check previous login attemps */
|
||||
$yaml = new WriteYaml();
|
||||
$logins = $yaml->getYaml('settings/users', '.logins');
|
||||
$userIP = $this->getUserIP();
|
||||
$userLogins = isset($logins[$userIP]) ? count($logins[$userIP]) : false;
|
||||
|
||||
if($userLogins)
|
||||
{
|
||||
/* get the latest */
|
||||
$lastLogin = intval($logins[$userIP][$userLogins-1]);
|
||||
|
||||
/* if last login is longer than 60 seconds ago, clear it. */
|
||||
if(time() - $lastLogin > 60)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
/* Did the user made three login attemps that failed? */
|
||||
elseif($userLogins >= 3)
|
||||
{
|
||||
$timeleft = 60 - (time() - $lastLogin);
|
||||
$data['messages'] = array('time' => $timeleft, 'error' => array( 'Too many bad logins. Please wait.'));
|
||||
}
|
||||
}
|
||||
|
||||
$this->c->view->render($response, '/auth/login.twig', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* signin an existing user
|
||||
*
|
||||
@@ -47,6 +76,36 @@ class AuthController extends Controller
|
||||
|
||||
public function login(Request $request, Response $response)
|
||||
{
|
||||
/* log user attemps to authenticate */
|
||||
$yaml = new WriteYaml();
|
||||
$logins = $yaml->getYaml('settings/users', '.logins');
|
||||
$userIP = $this->getUserIP();
|
||||
$userLogins = isset($logins[$userIP]) ? count($logins[$userIP]) : false;
|
||||
|
||||
/* if there have been user logins before. You have to do this again, because user does not always refresh the login page and old login attemps are stored. */
|
||||
if($userLogins)
|
||||
{
|
||||
/* get the latest */
|
||||
$lastLogin = intval($logins[$userIP][$userLogins-1]);
|
||||
|
||||
/* if last login is longer than 60 seconds ago, clear it and add this attempt */
|
||||
if(time() - $lastLogin > 60)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
/* Did the user made three login attemps that failed? */
|
||||
elseif($userLogins >= 2)
|
||||
{
|
||||
$logins[$userIP][] = time();
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
||||
|
||||
/* authentication */
|
||||
$params = $request->getParams();
|
||||
$validation = new Validation();
|
||||
|
||||
@@ -58,14 +117,26 @@ class AuthController extends Controller
|
||||
if($userdata && password_verify($params['password'], $userdata['password']))
|
||||
{
|
||||
$user->login($userdata['username']);
|
||||
|
||||
/* clear the user login attemps */
|
||||
if($userLogins)
|
||||
{
|
||||
unset($logins[$userIP]);
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
}
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('settings.show'));
|
||||
}
|
||||
}
|
||||
|
||||
/* if authentication failed, add attempt to log file */
|
||||
$logins[$userIP][] = time();
|
||||
$yaml->updateYaml('settings/users', '.logins', $logins);
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, credentials were wrong, please try again.');
|
||||
$this->c->flash->addMessage('error', 'Ups, wrong password or username, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* log out a user
|
||||
*
|
||||
@@ -82,5 +153,27 @@ class AuthController extends Controller
|
||||
}
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
}
|
||||
}
|
||||
|
||||
private function getUserIP()
|
||||
{
|
||||
$client = @$_SERVER['HTTP_CLIENT_IP'];
|
||||
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
$remote = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
if(filter_var($client, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $client;
|
||||
}
|
||||
elseif(filter_var($forward, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ip = $remote;
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
}
|
@@ -20,6 +20,11 @@ abstract class Controller
|
||||
$data = $this->c->dispatcher->dispatch('onPageReady', new OnPageReady($data))->getData();
|
||||
|
||||
unset($_SESSION['old']);
|
||||
|
||||
$response = $response->withAddedHeader('X-Content-Type-Options', 'nosniff');
|
||||
$response = $response->withAddedHeader('X-Frame-Options', 'SAMEORIGIN');
|
||||
$response = $response->withAddedHeader('X-XSS-Protection', '1;mode=block');
|
||||
|
||||
return $this->c->view->render($response, $route, $data);
|
||||
}
|
||||
|
||||
|
@@ -90,7 +90,7 @@ class SettingsController extends Controller
|
||||
if(isset($themeSettings['forms']['fields']))
|
||||
{
|
||||
$fields = $this->getFields($userSettings, 'themes', $themeName, $themeSettings);
|
||||
|
||||
|
||||
/* overwrite original theme form definitions with enhanced form objects */
|
||||
$themedata[$themeName]['forms']['fields'] = $fields;
|
||||
}
|
||||
@@ -177,57 +177,73 @@ class SettingsController extends Controller
|
||||
/* then iterate through the fields */
|
||||
foreach($objectSettings['forms']['fields'] as $fieldName => $fieldConfigs)
|
||||
{
|
||||
/* and create a new field object with the field name and the field configurations. */
|
||||
$field = new Field($fieldName, $fieldConfigs);
|
||||
|
||||
/* you have to prefil the value for the field with default settings, user settings or old user-input from form */
|
||||
$userValue = false;
|
||||
|
||||
/* first, add the default values from the original plugin or theme settings. Ignore checkboxes, otherwiese they might be always checked */
|
||||
if(isset($objectSettings['settings'][$fieldName]))
|
||||
if($fieldConfigs['type'] == 'fieldset')
|
||||
{
|
||||
$userValue = $objectSettings['settings'][$fieldName];
|
||||
}
|
||||
|
||||
/* now overwrite them with the local stored user settings */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $userSettings[$objectType][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* overwrite it with old input in form, if exists */
|
||||
if(isset($_SESSION['old'][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $_SESSION['old'][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* now we have set the uservalue for the field. Prepopulate the field object with it now */
|
||||
if($field->getType() == "textarea")
|
||||
{
|
||||
if($userValue)
|
||||
{
|
||||
$field->setContent($userValue);
|
||||
}
|
||||
}
|
||||
elseif($field->getType() == "checkbox")
|
||||
{
|
||||
/* needs special treatment, because field does not exist in settings if unchecked by user */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$field->setAttribute('checked', 'checked');
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->unsetAttribute('checked');
|
||||
}
|
||||
/* Create an array for the subsettings of the fieldset with the same structure and data as the original settings array */
|
||||
$subSettings = $objectSettings;
|
||||
$subSettings['forms'] = $fieldConfigs;
|
||||
|
||||
$fieldset = array();
|
||||
$fieldset['type'] = 'fieldset';
|
||||
$fieldset['legend'] = $fieldConfigs['legend'];
|
||||
$fieldset['fields'] = $this->getFields($userSettings, $objectType, $objectName, $subSettings);
|
||||
$fields[] = $fieldset;
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->setAttributeValue('value', $userValue);
|
||||
}
|
||||
/* and create a new field object with the field name and the field configurations. */
|
||||
$field = new Field($fieldName, $fieldConfigs);
|
||||
|
||||
/* you have to prefil the value for the field with default settings, user settings or old user-input from form */
|
||||
$userValue = false;
|
||||
|
||||
/* add the field to the field-List with the plugin-name as key */
|
||||
$fields[] = $field;
|
||||
/* first, add the default values from the original plugin or theme settings. Ignore checkboxes, otherwiese they might be always checked */
|
||||
if(isset($objectSettings['settings'][$fieldName]))
|
||||
{
|
||||
$userValue = $objectSettings['settings'][$fieldName];
|
||||
}
|
||||
|
||||
/* now overwrite them with the local stored user settings */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $userSettings[$objectType][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* overwrite it with old input in form, if exists */
|
||||
if(isset($_SESSION['old'][$objectName][$fieldName]))
|
||||
{
|
||||
$userValue = $_SESSION['old'][$objectName][$fieldName];
|
||||
}
|
||||
|
||||
/* now we have set the uservalue for the field. Prepopulate the field object with it now */
|
||||
if($field->getType() == "textarea")
|
||||
{
|
||||
if($userValue)
|
||||
{
|
||||
$field->setContent($userValue);
|
||||
}
|
||||
}
|
||||
elseif($field->getType() == "checkbox")
|
||||
{
|
||||
/* needs special treatment, because field does not exist in settings if unchecked by user */
|
||||
if(isset($userSettings[$objectType][$objectName][$fieldName]))
|
||||
{
|
||||
$field->setAttribute('checked', 'checked');
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->unsetAttribute('checked');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$field->setAttributeValue('value', $userValue);
|
||||
}
|
||||
|
||||
/* add the field to the field-List with the plugin-name as key */
|
||||
$fields[] = $field;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
@@ -331,13 +347,31 @@ class SettingsController extends Controller
|
||||
/* fetch the original settings from the folder (plugin or theme) to get the field definitions */
|
||||
$originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName);
|
||||
|
||||
if($originalSettings)
|
||||
if(isset($originalSettings['forms']['fields']))
|
||||
{
|
||||
/* flaten the multi-dimensional array with fieldsets to a one-dimensional array */
|
||||
$originalFields = array();
|
||||
foreach($originalSettings['forms']['fields'] as $fieldName => $fieldValue)
|
||||
{
|
||||
if(isset($fieldValue['fields']))
|
||||
{
|
||||
foreach($fieldValue['fields'] as $subFieldName => $subFieldValue)
|
||||
{
|
||||
$originalFields[$subFieldName] = $subFieldValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$originalFields[$fieldName] = $fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* take the user input data and iterate over all fields and values */
|
||||
foreach($userInput as $fieldName => $fieldValue)
|
||||
{
|
||||
/* get the corresponding field definition from original plugin settings */
|
||||
$fieldDefinition = isset($originalSettings['forms']['fields'][$fieldName]) ? $originalSettings['forms']['fields'][$fieldName] : false;
|
||||
$fieldDefinition = isset($originalFields[$fieldName]) ? $originalFields[$fieldName] : false;
|
||||
|
||||
if($fieldDefinition)
|
||||
{
|
||||
/* validate user input for this field */
|
||||
@@ -345,18 +379,23 @@ class SettingsController extends Controller
|
||||
}
|
||||
if(!$fieldDefinition && $fieldName != 'active')
|
||||
{
|
||||
$_SESSION['errors'][$objectName][$fieldName] = 'This field is not defined!';
|
||||
$_SESSION['errors'][$objectName][$fieldName] = array('This field is not defined!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** USER MANAGEMENT **
|
||||
***********************/
|
||||
|
||||
public function showUser($request, $response, $args)
|
||||
{
|
||||
if($_SESSION['role'] == 'editor' && $_SESSION['user'] !== $args['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
|
||||
$validate = new Validation();
|
||||
|
||||
if($validate->username($args['username']))
|
||||
@@ -428,12 +467,25 @@ class SettingsController extends Controller
|
||||
public function updateUser($request, $response, $args)
|
||||
{
|
||||
if($request->isPost())
|
||||
{
|
||||
{
|
||||
$params = $request->getParams();
|
||||
$user = new User();
|
||||
$userroles = $user->getUserroles();
|
||||
$validate = new Validation();
|
||||
|
||||
|
||||
/* non admins have different update rights */
|
||||
if($_SESSION['role'] !== 'administrator')
|
||||
{
|
||||
/* if an editor tries to update other userdata than its own */
|
||||
if($_SESSION['user'] !== $params['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
|
||||
/* non admins cannot change his userrole */
|
||||
$params['userrole'] = $_SESSION['role'];
|
||||
}
|
||||
|
||||
if($validate->existingUser($params, $userroles))
|
||||
{
|
||||
$userdata = array('username' => $params['username'], 'email' => $params['email'], 'userrole' => $params['userrole']);
|
||||
@@ -442,14 +494,14 @@ class SettingsController extends Controller
|
||||
{
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
elseif($validate->newPassword($params))
|
||||
{
|
||||
$userdata['password'] = $params['newpassword'];
|
||||
$user->updateUser($userdata);
|
||||
$this->c->flash->addMessage('info', 'Saved all changes');
|
||||
return $response->withRedirect($this->c->router->pathFor('user.list'));
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $params['username']]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +517,16 @@ class SettingsController extends Controller
|
||||
$params = $request->getParams();
|
||||
$validate = new Validation();
|
||||
$user = new User();
|
||||
|
||||
/* non admins have different update rights */
|
||||
if($_SESSION['role'] !== 'administrator')
|
||||
{
|
||||
/* if an editor tries to delete other user than its own */
|
||||
if($_SESSION['user'] !== $params['username'])
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('user.show', ['username' => $_SESSION['user']] ));
|
||||
}
|
||||
}
|
||||
|
||||
if($validate->username($params['username']))
|
||||
{
|
||||
|
Reference in New Issue
Block a user