Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into production
Browse files Browse the repository at this point in the history
  • Loading branch information
rjmackay committed Jul 10, 2018
2 parents 978aeb6 + b77080c commit f3379cd
Show file tree
Hide file tree
Showing 20 changed files with 389 additions and 76 deletions.
19 changes: 17 additions & 2 deletions application/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@


/**
* Add response message for HTTP 422
* Add response message for HTTP 422 and 429
*/
Kohana_Response::$messages[422] = 'Unprocessable Entity';
Kohana_Response::$messages[429] = 'Too Many Requests';

/**
* Set Kohana::$environment if a 'KOHANA_ENV' environment variable has been supplied.
Expand Down Expand Up @@ -127,7 +128,21 @@
$client = (
new Raven_Client(getenv("RAVEN_URL"), [
'exclude' => ['HTTP_Exception_404'],
'error_types' => (E_ALL & ~E_NOTICE & ~E_USER_NOTICE)
'error_types' => (E_ALL & ~E_NOTICE & ~E_USER_NOTICE),
'processors' => [
'Raven_Processor_SanitizeHttpHeadersProcessor',
'Raven_Processor_SanitizeDataProcessor'
],
'processorOptions' => [
'Raven_Processor_SanitizeDataProcessor' => [
'fields_re' => '/(authorization|password|passwd|secret|password_confirmation|card_number|auth_pw|authToken|api_key|client_secret)/i',
],
'Raven_Processor_SanitizeHttpHeadersProcessor' => [
'sanitize_http_headers' => [
'Authorization', 'Proxy-Authorization', 'X-Csrf-Token', 'X-CSRFToken', 'X-XSRF-TOKEN', 'X-Ushahidi-Signature',
]
]
]
])
)->install();

Expand Down
10 changes: 10 additions & 0 deletions application/classes/HTTP/Exception/429.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');

class HTTP_Exception_429 extends HTTP_Exception {

/**
* @var integer HTTP 429 Too Many Requests
*/
protected $_code = 429;

}
7 changes: 6 additions & 1 deletion application/classes/Ushahidi/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ public static function init()
$di->params['Ushahidi\Factory\ValidatorFactory']['map']['users'] = [
'create' => $di->lazyNew('Ushahidi_Validator_User_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_User_Update'),
'register' => $di->lazyNew('Ushahidi_Validator_User_Register')
'register' => $di->lazyNew('Ushahidi_Validator_User_Register'),
'passwordreset' => $di->lazyNew(Ushahidi\App\Validator\User\Reset::class)
];
$di->params['Ushahidi\Factory\ValidatorFactory']['map']['messages'] = [
'create' => $di->lazyNew('Ushahidi_Validator_Message_Create'),
Expand Down Expand Up @@ -729,6 +730,9 @@ public static function init()
$di->params['Ushahidi_Validator_User_Register'] = [
'repo' => $di->lazyGet('repository.user')
];
$di->params[Ushahidi\App\Validator\User\Reset::class] = [
'repo' => $di->lazyGet('repository.user')
];
$di->params['Ushahidi_Validator_CSV_Create'] = [
'form_repo' => $di->lazyGet('repository.form'),
];
Expand All @@ -737,6 +741,7 @@ public static function init()
];
$di->params['Ushahidi_Validator_Role_Update'] = [
'permission_repo' => $di->lazyGet('repository.permission'),
'feature_enabled' => $di->lazyGet('roles.enabled'),
];

// Validator Setters
Expand Down
2 changes: 2 additions & 0 deletions application/classes/Ushahidi/Repository/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ public function isValidResetToken($token) {
->where('created', '>', time() - 1800) // Expire tokens after less than 30 mins
->execute($this->db);



$count = $result->get('total') ?: 0;

return $count !== 0;
Expand Down
4 changes: 4 additions & 0 deletions application/classes/Ushahidi/Rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,10 @@ protected function _execute_usecase()
$e
);
}
catch (Ushahidi\Core\Exception\ThrottlingException $e)
{
throw new HTTP_Exception_429('Too Many Requests');
}
catch (\InvalidArgumentException $e)
{
throw new HTTP_Exception_400(
Expand Down
17 changes: 16 additions & 1 deletion application/classes/Ushahidi/Validator/Role/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
class Ushahidi_Validator_Role_Update extends Validator
{
protected $permission_repo;
protected $feature_enabled;
protected $default_error_source = 'role';

public function __construct(PermissionRepository $permission_repo)
public function __construct(PermissionRepository $permission_repo, $feature_enabled)
{
$this->permission_repo = $permission_repo;
$this->feature_enabled = (bool) $feature_enabled;
}

protected function getRules()
Expand All @@ -30,10 +32,23 @@ protected function getRules()
],
'permissions' => [
[[$this, 'checkPermissions'], [':validation', ':value']],

],
'name' => [
[[$this, 'checkRolesEnabled'], [':validation']],
],
];
}

public function checkRolesEnabled(Validation $validation)
{
if (!$this->feature_enabled) {
$validation->error('name', 'rolesNotEnabled');
return;
}
return;
}

public function checkPermissions(Validation $validation, $permissions)
{
if (!$permissions) {
Expand Down
5 changes: 5 additions & 0 deletions application/messages/role.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

return array(
'rolesNotEnabled' => 'The roles feature is not enabled for your deployment.'
);
3 changes: 2 additions & 1 deletion application/messages/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
'isUniqueEmail' => ':field is already in use',
'isUniqueUsername' => ':field is already in use',
'isUserSelf' => 'You cannot change your own role',
'adminUserLimitReached' => 'limit::admin'
'adminUserLimitReached' => 'limit::admin',
'invalidResetToken' => 'Invalid or expired reset token'
);
74 changes: 54 additions & 20 deletions src/App/Init.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,66 @@
return $memcached;
}));

// Set up login rate limiter
$di->set('ratelimiter.login.flap', $di->lazyNew('BehEh\Flaps\Flap'));
// Set up register rate limiter
$di->set('ratelimiter.register.flap', $di->lazyNew(
'BehEh\Flaps\Flap',
[
'storage' => $di->lazyNew(
'BehEh\Flaps\Storage\DoctrineCacheAdapter',
[
'cache' => $di->lazyGet('ratelimiter.cache')
]
),
'name' => 'register'
]
));

$di->params['BehEh\Flaps\Flap'] = [
'storage' => $di->lazyNew('BehEh\Flaps\Storage\DoctrineCacheAdapter'),
'name' => 'login'
];
$di->set('ratelimiter.register.strategy', $di->lazyNew(
'BehEh\Flaps\Throttling\LeakyBucketStrategy',
[
'requests' => 3,
'timeSpan' => '1m'
]
));

$di->set('ratelimiter.login.strategy', $di->lazyNew('BehEh\Flaps\Throttling\LeakyBucketStrategy'));
$di->set('ratelimiter.register', $di->lazyNew(
Ushahidi\App\RateLimiter::class,
[
'flap' => $di->lazyGet('ratelimiter.register.flap'),
'throttlingStrategy' => $di->lazyGet('ratelimiter.register.strategy'),
]
));

// 3 requests every 1 minute by default
$di->params['BehEh\Flaps\Throttling\LeakyBucketStrategy'] = [
'requests' => 3,
'timeSpan' => '1m'
];
// Set up login rate limiter
$di->set('ratelimiter.login.flap', $di->lazyNew(
'BehEh\Flaps\Flap',
[
'storage' => $di->lazyNew(
'BehEh\Flaps\Storage\DoctrineCacheAdapter',
[
'cache' => $di->lazyGet('ratelimiter.cache')
]
),
'name' => 'login'
]
));

$di->set('ratelimiter.login', $di->lazyNew('Ushahidi\App\RateLimiter'));

$di->params['Ushahidi\App\RateLimiter'] = [
'flap' => $di->lazyGet('ratelimiter.login.flap'),
'throttlingStrategy' => $di->lazyGet('ratelimiter.login.strategy'),
];
$di->set('ratelimiter.login.strategy', $di->lazyNew(
'BehEh\Flaps\Throttling\LeakyBucketStrategy',
[
'requests' => 3,
'timeSpan' => '1m'
]
));

$di->params['BehEh\Flaps\Storage\DoctrineCacheAdapter'] = [
'cache' => $di->lazyGet('ratelimiter.cache')
];
$di->set('ratelimiter.login', $di->lazyNew(
Ushahidi\App\RateLimiter::class,
[
'flap' => $di->lazyGet('ratelimiter.login.flap'),
'throttlingStrategy' => $di->lazyGet('ratelimiter.login.strategy'),
]
));

// Rate limit storage cache
$di->set('ratelimiter.cache', function () use ($di) {
Expand Down
48 changes: 48 additions & 0 deletions src/App/Validator/User/Reset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/**
* Ushahidi User Update Validator
*
* @author Ushahidi Team <[email protected]>
* @package Ushahidi\Application
* @copyright 2014 Ushahidi
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3)
*/

namespace Ushahidi\App\Validator\User;

use Ushahidi\Core\Entity;
use Ushahidi\Core\Tool\Validator;
use Ushahidi\Core\Entity\UserRepository;

class Reset extends Validator
{

protected $default_error_source = 'user';
protected $repo;

public function __construct(UserRepository $repo)
{
$this->repo = $repo;
}

protected function getRules()
{
return [
'token' => [
[[$this, 'checkResetToken'], [':validation', ':value']]
],
'password' => [
['min_length', [':value', 7]],
['max_length', [':value', 72]],
],
];
}

public function checkResetToken(\Validation $validation, $token)
{
if (!$this->repo->isValidResetToken($token)) {
$validation->error('token', 'invalidResetToken');
}
}
}
2 changes: 1 addition & 1 deletion src/Core/Exception/ValidatorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ValidatorException extends \InvalidArgumentException
{
private $errors;

public function __construct($message, array $errors, Exception $previous = null)
public function __construct($message, array $errors, \Exception $previous = null)
{
$flatErrors = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($errors)), false);

Expand Down
28 changes: 22 additions & 6 deletions src/Core/Tool/Uploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ public function upload(UploadData $file, $filename = null)
$filename = uniqid() . '-' . $file->name;
}

// Avoid any possible issues with case sensitivity by forcing all files
// to be made lowercase.
$filename = strtolower($filename);
// Avoid possible issues with case sensitivity by forcing all files
// to be made lowercase. Also replace possibly invalid characters in filename
$filename = strtolower(preg_replace('/[^\pL\pN\-\_\s\.]+/u', '', $filename));


// Add the first and second letters of filename to the directory path
// to help segment the files, producing a more reasonable amount of
Expand All @@ -66,9 +67,24 @@ public function upload(UploadData $file, $filename = null)
$extension = pathinfo($filepath, PATHINFO_EXTENSION);
$mimeType = MimeType::detectByFileExtension($extension) ?: 'text/plain';
$config = ['mimetype' => $mimeType];
$this->fs->putStream($filepath, $stream, $config);
if (is_resource($stream)) {
fclose($stream);

try {
$this->fs->putStream($filepath, $stream, $config);
} catch (\Guzzle\Http\Exception\ClientErrorResponseException $e) {
// Flysystem and FlysystemRackspace are very leaky abstractions
// so we have to manually catch guzzle errors here
$response = $e->getResponse();

throw new \InvalidArgumentException('Could not upload file: '. $response->getBody(true));
} catch (\Guzzle\Http\Exception\BadResponseException $e) {
// Flysystem and FlysystemRackspace are very leaky abstractions
// so we have to manually catch guzzle errors here

throw new \InvalidArgumentException('Could not upload file');
} finally {
if (is_resource($stream)) {
fclose($stream);
}
}

// Get meta information about the file.
Expand Down
16 changes: 11 additions & 5 deletions src/Core/Usecase/Media/CreateMedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Ushahidi\Core\Tool\Uploader;
use Ushahidi\Core\Tool\UploadData;
use Ushahidi\Core\Usecase\CreateUsecase;
use Ushahidi\Exception\ValidatorException;
use Ushahidi\Core\Exception\ValidatorException;

class CreateMedia extends CreateUsecase
{
Expand Down Expand Up @@ -62,7 +62,7 @@ public function interact()
} catch (ValidatorException $e) {
// If a file was uploaded, it must be purged after a failed upload.
// Otherwise storage will be filled with junk files.
if ($this->fs->has($this->upload->file)) {
if ($this->upload && $this->fs->has($this->upload->file)) {
$this->fs->delete($this->upload->file);
}

Expand All @@ -79,9 +79,15 @@ public function interact()
protected function getEntity()
{
// Upload the file and get the file reference
$this->upload = $this->uploader->upload(
new UploadData($this->getPayload('file'))
);
try {
$this->upload = $this->uploader->upload(
new UploadData($this->getPayload('file'))
);
} catch (\InvalidArgumentException $e) {
throw new ValidatorException($e->getMessage(), [
'file' => $e->getMessage()
], $e);
}

$payload = [
'caption' => $this->getPayload('caption', false) ?: null,
Expand Down
Loading

0 comments on commit f3379cd

Please sign in to comment.