Archived
1
0
Fork 0

Compare commits

..

No commits in common. "dev" and "v1.1" have entirely different histories.
dev ... v1.1

53 changed files with 193 additions and 398 deletions

View file

@ -30,7 +30,7 @@ session:
statsKey: _httpcb_sess_idx
prefix: _httpcb_sess_
#sendgrid:
#sendgrid
#key: value
# OAuth

View file

@ -4,61 +4,58 @@ router:
routes:
home-route:
pattern: '/'
path: Index::index
path:
controller: index
action: index
about-route:
pattern: '/about'
path: Index::about
# Callbacks
cb-list:
pattern: '/callback/list'
path: Callback::list
cb-new:
pattern: '/callback/new'
path: Callback::new
path:
controller: index
action: about
cb-created:
pattern: '/callback/created/{id}'
path: Callback::created
cb-show:
pattern: '/callback/show/{id}'
path: Callback::show
path:
controller: callback
action: created
cb-endpoint:
pattern: '/cb/{id}/:params'
path: Api::endpoint
# login
path:
controller: api
action: endpoint
login:
pattern: '/login'
path: Auth::index
path:
controller: auth
action: index
logout:
pattern: '/logout'
path: Auth::logout
path:
controller: auth
action: logout
oauth:
pattern: '/login/{strategy:([a-z]+)}/:params'
path: Auth::oauth
path:
controller: auth
action: oauth
oauth-disconnect:
pattern: '/oauth/{provider:([a-z]+)}/disconnect'
path: 'User::oauthdisconnect'
oauth-disconnect-confirm:
pattern: '/oauth/{provider:([a-z]+)}/disconnect/{confirm}'
path: 'User::oauthdisconnect'
# User
user-register:
pattern: '/register'
path: Auth::register
user-settings:
pattern: '/settings'
path: User::settings
user-activity-log:
pattern: '/user/activity'
path: User::activity
path:
controller: user
action: settings
activation-link:
pattern: '/activate/{link}'
path: Api::activationlink
path:
controller: api
action: activationlink
# Backend
backend-home:
@ -73,15 +70,12 @@ router:
backend-user-edit:
pattern: '/admin/user/{id:([0-9]+)}'
path: backend::user::edit
backend-user-impersonate:
pattern: '/admin/impersonate/{id:([0-9]+)}'
path: backend::user::impersonate
backend-user-activation-email:
pattern: '/admin/user/{id:([0-9]+)}/activation'
path: backend::user::activation-email
backend-user-status:
pattern: '/admin/user/{id:([0-9]+)}/status/{type}'
path: backend::user::status
pattern: '/admin/user/{id:([0-9]+)}/{type}'
path:
module: backend
controller: user
action: status
backend-log:
pattern: '/admin/log{page:/?([0-9]+)?}'
path: backend::log::index

View file

@ -6,7 +6,6 @@ use App\Controller\ControllerBase,
App\Model\Data\Callback as CallbackModel,
App\Model\Data\Request as RequestModel,
App\Model\Data\RequestMeta as RequestMetaModel,
App\Model\Data\User,
App\Model\Data\UserActivation;
class ApiController extends ControllerBase

View file

@ -118,11 +118,8 @@ class AuthController extends ControllerBase
}
$user = new User();
$user->assign(
$data->toArray(),
null,
['email', 'username', 'firstname', 'lastname']
);
$user->assign($data->toArray(), null,
[ 'email', 'username', 'firstname', 'lastname' ]);
$form = new RegistrationForm($user);

View file

@ -55,8 +55,7 @@ class CallbackController extends ControllerBase
return $this->response->redirect(array(
'for' => 'cb-created',
'id' => $callback->getPublicId()
));
'id' => $callback->getPublicId()));
} else {
foreach($callback->getMessages() as $msg) {
$this->flash->error($msg);
@ -72,6 +71,8 @@ class CallbackController extends ControllerBase
$msg .= '</ul>';
$this->flash->message('error', $msg);
}
}
$this->view->form = $form;
@ -84,6 +85,7 @@ class CallbackController extends ControllerBase
{
$row = CallbackModel::get($id);
if (!$row) {
}
$this->view->id = $id;
}

View file

@ -18,7 +18,6 @@ class ControllerBase extends Controller
protected function _forward404()
{
$this->dispatcher->forward(array(
'namespace' => 'App\\Controller',
'controller' => 'error',
'action' => 'show404'
));

View file

@ -15,3 +15,4 @@ class IndexController extends ControllerBase
{
}
}

View file

@ -44,11 +44,8 @@ class UserController extends ControllerBase
]);
// Send the email.
$this->di->getMail()->send(
'Httpcb password activation',
$user->getEmail(),
$content
);
$this->di->getMail()->send('Httpcb password activation',
$user->getEmail(), $content);
$msg = "For security reasons. Before a password can be created "
. "a email has been sent to <strong>{$user->getEmail()}</strong> with "

View file

@ -97,33 +97,4 @@ class UserController extends \Phalcon\Mvc\Controller
$this->flash->success('The account was: ' . $status);
$this->response->redirect('/admin');
}
public function activationEmailAction($id)
{
$user = User::findFirstById($id);
if ($user) {
if ($user->isSuspended()) {
$this->eventsManager->fire('auth:onSentActivation', $user);
$this->flash->success('Activation email sent to: ' . $user->email);
} else {
$this->flash->error('Only suspended users can be sent activation emails.');
}
} else {
$this->flash->error('Invalid user: ' . $id);
}
$this->response->redirect('/admin');
}
public function impersonateAction($id)
{
$user = User::findFirstById($id);
try {
$this->auth->impersonate($user);
$this->response->redirect('/');
} catch (\Exception $ex) {
$this->flash->error($ex->getMessage());
$this->response->redirect('/admin');
}
}
}

View file

@ -7,14 +7,12 @@ use Phalcon\Forms\Form;
/**
* Element types
*/
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Submit;
/**
* Validators
*/
use Phalcon\Validation\Validator\StringLength;
class CallbackCreate extends Form

View file

@ -7,7 +7,6 @@ use Phalcon\Forms\Form;
/**
* Element types
*/
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Password;
use Phalcon\Forms\Element\Submit;
@ -15,7 +14,6 @@ use Phalcon\Forms\Element\Submit;
/**
* Validators
*/
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\Email as EmailValidator;
use Phalcon\Validation\Validator\StringLength;

View file

@ -5,19 +5,16 @@ namespace App\Form;
/**
* Models
*/
use App\Model\Data\User;
/**
* Phalcon Form
*/
use Httpcb\Form as FormBase;
/**
* Element types
*/
use Phalcon\Forms\Element\Text,
Phalcon\Forms\Element\Password,
Phalcon\Forms\Element\Submit;
@ -25,7 +22,6 @@ use Phalcon\Forms\Element\Text,
/**
* Validators
*/
use Phalcon\Validation,
Phalcon\Validation\Validator\Callback as CallbackValidator,
Phalcon\Validation\Validator\Alnum as AlnumValidator,
@ -58,9 +54,7 @@ class Registration extends FormBase
'messageMinimum' => 'Username must be at least :min characters long.',
]),
new CallbackValidator([
'callback' => function ($data) {
return User::findFirstByUsername($data['username']) === false;
},
'callback' => function($data) { return User::findFirstByUsername($data['username']) === false; },
'message' => 'The username already exists.',
'attribute' => 'username',
])
@ -93,9 +87,7 @@ class Registration extends FormBase
$email->addValidators([
new CallbackValidator([
'callback' => function ($data) {
return User::findFirstByEmail($data['email']) === false;
},
'callback' => function($data) { return User::findFirstByEmail($data['email']) === false; },
'message' => 'This email already exist.',
])
]);

View file

@ -5,19 +5,16 @@ namespace App\Form;
/**
* Models
*/
use App\Model\Data\User as UserModel;
/**
* Form
*/
use Httpcb\Form as FormBase;
/**
* Element types
*/
use Phalcon\Forms\Element\Text,
Phalcon\Forms\Element\Password,
Phalcon\Forms\Element\Submit;
@ -25,7 +22,6 @@ use Phalcon\Forms\Element\Text,
/**
* Validators
*/
use Phalcon\Validation\Validator\Callback as CallbackValidator,
Phalcon\Validation\Validator\Uniqueness as UniquenessValidator,
Phalcon\Validation\Validator\Alnum as AlnumValidator,

View file

@ -70,6 +70,7 @@ class Acl
if ($def instanceof Config) {
$inherits = $def->get('inherits');
$description = $def->get('description');
}
$role = new Role($name, $description);

View file

@ -10,7 +10,6 @@ use App\Model\Data\User,
class Auth extends Injectable
{
const SESSION_KEY = 'auth';
const IMPERSONATOR_ID = 'auth.impersonator';
/**
* Login using email/user + password combination.
@ -64,11 +63,8 @@ class Auth extends Injectable
$this->setIdentity($user->getId());
$this->eventsManager->fire(
'auth:onLogin',
$this,
"OAuth {$data->getProvider()}"
);
$this->eventsManager->fire('auth:onLogin', $this,
"OAuth {$data->getProvider()}");
return new Result(Result::SUCCESS);
@ -87,40 +83,6 @@ class Auth extends Injectable
$this->eventsManager->fire('auth:onLogin', $this, 'System');
}
public function getImpersonator()
{
$id = $this->session->get(self::IMPERSONATOR_ID);
return $id !== null ? User::findFirst($id) : null;
}
/**
* Impersonate a user
*
* @param User $user
*/
public function impersonate(User $user)
{
$current = $this->getIdentity();
if ($current === null) {
throw new \InvalidArgumentException("Need to be authenticated to be able to impersonate someone");
}
if ($current->getId() === $user->getId()) {
// Same user
throw new \DomainException("Can't impersonate yourself");
}
$this->session->set(self::IMPERSONATOR_ID, $current->getId());
$this->setIdentity($user->getId());
$this->eventsManager->fire('auth:onImpersonate', $this, $current);
}
public function impersonateClear($imp_id)
{
$this->session->remove(self::IMPERSONATOR_ID);
$this->session->set(self::SESSION_KEY, $imp_id);
}
/**
* @param $identity
* @return Auth
@ -170,12 +132,7 @@ class Auth extends Injectable
*/
public function clearIdentity()
{
$imp_id = $this->session->get(self::IMPERSONATOR_ID);
if ($imp_id !== null) {
$this->impersonateClear($imp_id);
} else {
$this->session->remove(self::SESSION_KEY);
}
return $this;
}
}

View file

@ -2,8 +2,7 @@
namespace Httpcb;
class Debug
{
class Debug {
public static function dump($var, $label = null, $echo = true)
{

View file

@ -53,10 +53,7 @@ class Form extends FormBase
$xhtml .= sprintf(
'<label class="%s" for="%s">%s</label>',
$opt['label-class'],
$ele->getName(),
$ele->getLabel()
);
$opt['label-class'], $ele->getName(), $ele->getLabel());
}
$xhtml .= '<div class="' . implode(' ', $opt['class']) . '">'

View file

@ -126,22 +126,15 @@ class Menu extends Tag
return $xhtml;
}
$xhtml = self::tagHtml(
'li',
$node->isActive()
$xhtml = self::tagHtml('li', $node->isActive()
? array('class' => $this->_activeClass) : null,
false,
false,
true
);
false, false, true);
// Generate the link.
$xhtml .= self::linkTo($node->getHref(), $node->getCaption());
if (
$node->isActive() && $node->hasChildren()
&& ($max_depth === null || $depth < $max_depth)
) {
if ($node->isActive() && $node->hasChildren()
&& ($max_depth === null || $depth < $max_depth)) {
$xhtml .= $this->_renderMenu($node->getChildren(), $depth + 1, $max_depth);
}

View file

@ -81,3 +81,4 @@ class Container
return $this;
}
}

View file

@ -16,8 +16,6 @@ use Phalcon\Di\FactoryDefault as DiDefault,
Phalcon\Cache\Frontend\Data as FrontendDataCache,
Phalcon\Cache\Backend\Apc as BackendApcCache,
Phalcon\Translate\Adapter\NativeArray as TranslateAdapter,
Phalcon\Storage\AdapterFactory as StorageAdapterFactory,
Phalcon\Cache\AdapterFactory as CacheAdapterFactory,
Phalcon\Logger,
Phalcon\Mvc\Router;
@ -32,8 +30,7 @@ use Httpcb\Auth,
use App\Listener\AccessListener,
App\Listener\DispatchListener,
App\Listener\ActivityLog,
App\Listener\AuthEmailListener;
App\Listener\ActivityLog;
class Services extends DiDefault
{
@ -49,7 +46,8 @@ class Services extends DiDefault
if (substr($method->getName(),0, 11) == '_initShared') {
$service = lcfirst(substr($method->getName(), 11));
$this->setShared($service, $method->getClosure($this));
} else if (substr($method->getName(), 0, 5) == '_init') {
}
else if (substr($method->getName(),0, 5) == '_init') {
$service = lcfirst(substr($method->getName(), 5));
$this->set($service, $method->getClosure($this));
}
@ -179,11 +177,8 @@ class Services extends DiDefault
$options = $mdConfig['options'];
$adapter = $mdConfig['adapter'];
$serializerFactory = new \Phalcon\Storage\SerializerFactory();
$factory = new CacheAdapterFactory($serializerFactory);
$class = 'Phalcon\Mvc\Model\MetaData\\' . $adapter;
return new $class($factory, $options);
return new $class($options);
}
// Otherwise, default to Memory.
@ -200,11 +195,8 @@ class Services extends DiDefault
$adapter_name = isset($data['adapter']) ? $data['adapter'] : 'Stream';
$options = $data['options'];
$serializerFactory = new \Phalcon\Storage\SerializerFactory();
$factory = new StorageAdapterFactory($serializerFactory);
$class = 'Phalcon\Session\Adapter\\' . $adapter_name;
$adapter = new $class($factory, $options);
$adapter = new $class($options);
}
// Default to Stream
else {
@ -318,7 +310,7 @@ class Services extends DiDefault
$config = $this->get('config')->router;
// Create the router
$router = new Router(false);
$router = new Router();
$router->removeExtraSlashes($config->get('removeExtraSlashes', false));
foreach($config->routes as $name => $def) {
@ -335,9 +327,6 @@ class Services extends DiDefault
$router->add($def->get('pattern'), $path)
->setName($name);
}
$router->notFound(['controller' => 'error', 'action' => 'show404']);
return $router;
}
@ -348,7 +337,6 @@ class Services extends DiDefault
$eventsManager = new \Phalcon\Events\Manager();
$eventsManager->attach('user', $activityLog);
$eventsManager->attach('auth', $activityLog);
$eventsManager->attach('auth', new AuthEmailListener);
return $eventsManager;
}

View file

@ -33,8 +33,7 @@ class ServerUrl extends AbstractHelper
// remove port if it's the default port.
if (($scheme == 'http' && $port == 80)
|| ($scheme == 'https' && $port == 443)
) {
|| ($scheme == 'https' && $port == 443)) {
$port = null;
}

View file

@ -23,19 +23,6 @@ class ActivityLog extends Injectable
$this->_log($auth->getUser(), sprintf("Logged in (%s)", $type));
}
/**
* On Impersonate event.
*
* @param Event $event
* @param Auth $auth
* @param User $user The user Impersonating the user in $auth
*/
public function onImpersonate(Event $event, Auth $auth, User $user)
{
$imp = $auth->getUser();
$this->_log($user, sprintf("Impersonated user (%s:%s)", $imp->getId(), $imp->getUsername()));
}
/**
* @param Event $event
* @param User $auth
@ -78,21 +65,9 @@ class ActivityLog extends Injectable
$this->_log($user, sprintf("OAuth disconnected (%s)", $providerName));
}
/**
* Fired when a activation email is sent.
*
* @param Event $event
* @param User $user
* @param string $providerName
*/
public function onSentActivation(Event $event, User $user)
{
$this->_log($user, sprintf("Activation email sent"));
}
protected function _log(User $user, $message)
{
$ip = (new \Phalcon\Http\Request())->getClientAddress(true);
$ip = (new \Phalcon\Http\Request())->getClientAddress();
return (new ActivityLogger())->assign([
'user_id' => $user->getId(),

View file

@ -1,25 +0,0 @@
<?php
namespace App\Listener;
use App\Model\Data\User,
App\Model\Data\UserActivation;
use Phalcon\Di\Injectable,
Phalcon\Events\Event;
class AuthEmailListener extends Injectable
{
public function onSentActivation(Event $event, User $user)
{
$activation = new UserActivation();
$activation->setUserId($user->getId())
->save();
$content = $this->di->getShared('template')->render('mail/account_activation', [
'link' => $activation->getActivationKey()
]);
$this->di->getMail()->send('Httpcb account activation', $user->getEmail(), $content);
}
}

View file

@ -10,12 +10,8 @@ class CreateRequestMetaTable extends AbstractMigration
$table = $this->table('request_meta');
$table->addColumn('callbackid', 'integer');
$table->addForeignKey(
'callbackid',
'callback',
['id'],
['constraint' => 'FK_callback']
);
$table->addForeignKey('callbackid', 'callback', [ 'id' ],
[ 'constraint' => 'FK_callback' ]);
$table->addColumn('source_ip', 'string', [
'limit' => 50,

View file

@ -9,12 +9,8 @@ class CreateRequestObjectTable extends AbstractMigration
{
$table = $this->table('request_object');
$table->addForeignKey(
'id',
'request_meta',
['id'],
['constraint' => 'FK_request_meta']
);
$table->addForeignKey('id', 'request_meta', ['id'],
[ 'constraint' => 'FK_request_meta' ]);
$table->addColumn('headers', 'blob', [
'null' => true,

View file

@ -265,16 +265,6 @@ class User extends Base
return $this->status == self::STATUS_ACTIVE;
}
/**
* Returns true if this user is suspended.
*
* @return bool
*/
public function isSuspended()
{
return $this->status == self::STATUS_SUSPENDED;
}
/**
* @return mixed
*/

View file

@ -44,3 +44,4 @@ abstract class Base implements ModuleDefinitionInterface
));
}
}

View file

@ -12,8 +12,6 @@
data-bs-toggle="dropdown" role="button" aria-expanded="false">
{{ icon('solid/user') }} <strong>{{ auth.getUser().username }}</strong>
{% set imp = auth.getImpersonator() %}
{% if imp %}( {{ icon('solid/user-secret') }} {{ imp.username }} ){% endif %}
</a>
<ul class="dropdown-menu navigation-user-menu-dropdown-list">

View file

@ -56,13 +56,6 @@
{% if (user.getId()) %}
{% set actions = [ 'Activate': 'Active', 'Suspend': 'Suspended', 'Delete': 'Deleted' ] %}
<div class="float-end">
{% if user.isSuspended() %}
<a class="button button-info" href="{{ url(['for': 'backend-user-activation-email', 'id': user.getId() ]) }}">
Send activation email
</a>
{% endif %}
{% for label, status in actions %}
{% if (user.status != status) %}

View file

@ -20,7 +20,6 @@
<th>Email</th>
<th>Type</th>
<th>Status</th>
<th>&nbsp;</th>
</tr>
</thead>
@ -37,12 +36,7 @@
<td>{{ item.name }}</td>
<td>{{ item.email }}</td>
<td>{{ item.type | capitalize }}</td>
<td><span class="badge {{ item.isActive() ? 'badge-success' : 'badge-danger' }}">{{ item.status }}</span></td>
<td>
<a title="Impersonate" href="{{ url(['for': 'backend-user-impersonate', 'id': item.id ]) }}">
{{ icon('solid/user-secret') }}
</a>
</td>
<td>{{ item.status }}</td>
</tr>
{% endfor %}
</tbody>

View file

@ -7,7 +7,6 @@
"ext-psr": ">=1.2",
"ext-redis": "*",
"ext-yaml": "*",
"ext-mbstring": "*",
"robmorgan/phinx": "^0.10.6",
"league/oauth2-client": "^2.3",
"league/oauth2-github": "^2.0",

5
package-lock.json generated
View file

@ -1,12 +1,11 @@
{
"name": "httpcb",
"version": "1.1.0",
"version": "1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "httpcb",
"version": "1.1.0",
"version": "1.1",
"license": "ISC",
"devDependencies": {
"@popperjs/core": "^2.11.5",

View file

@ -1,6 +1,6 @@
{
"name": "httpcb",
"version": "1.1.0",
"version": "1.1",
"description": "HTTP Callback Tool",
"devDependencies": {
"@popperjs/core": "^2.11.5",