Compare commits

...

30 Commits

Author SHA1 Message Date
85c719c24d Fix bad key name 2020-12-19 01:33:59 +00:00
5df3f965ef Merged in revert-pr-6 (pull request #7)
Revert "Apply fixes from StyleCI (pull request #6)"
2020-10-21 00:31:11 +00:00
4eb115d165 Revert "Apply fixes from StyleCI (pull request #6)"
This reverts pull request #6.

> This pull request applies code style fixes from an analysis carried out by [StyleCI](https://bitbucket.styleci.io).
> 
> For more information, click [here](https://bitbucket.styleci.io/analyses/a2Jl7D).
2020-10-21 00:29:50 +00:00
0433ce7693 Merged in analysis-a2Jl7D (pull request #6)
Apply fixes from StyleCI
2020-10-21 00:24:54 +00:00
773ec570d9 Apply fixes from StyleCI 2020-10-21 00:01:41 +00:00
53c23f3698 Changed branding for the repo 2020-10-21 00:01:32 +00:00
f1db159eee
Update SECURITY.md 2020-09-08 17:44:56 +01:00
0d14a65ee5
Create SECURITY.md 2020-09-08 17:32:56 +01:00
2942157603
Update README.md 2020-09-08 06:16:27 +01:00
11f3fb90d0
Update README.md 2020-09-08 06:16:14 +01:00
937a0206a5 Added existing account check to logs 2020-09-08 01:38:56 +01:00
3598a32ecf Added existing account check to logs 2020-09-08 01:37:33 +01:00
ac8b303e2c Update to logauthfailure 2020-09-08 01:34:47 +01:00
e93abd2ab7 Added logging for successful authentication attempts 2020-09-08 01:31:09 +01:00
20ab381076 Added logging for failed authentication attempts 2020-09-08 01:26:27 +01:00
e566e40404 Update target user in logs 2020-09-08 00:07:50 +01:00
b0a935b8b3 Add acceptable "permanent" ban time 2020-09-08 00:06:27 +01:00
0dfb68dba2 Add acceptable "permanent" ban time 2020-09-08 00:05:37 +01:00
24303052ad Ban validation update 2020-09-07 23:57:50 +01:00
178bc31a6e Ban datetime format 2020-09-07 23:44:14 +01:00
98e557a840 Update ban dates 2020-09-07 23:42:09 +01:00
95bf7c239e Update ban time logic 2020-09-07 23:38:25 +01:00
4d2595dd39 Update ban logic 2020-09-07 23:33:35 +01:00
4e81a41210 Updated installation process 2020-09-07 23:22:25 +01:00
1319ce6b86 Added more debug logging 2020-09-07 22:56:54 +01:00
bea83b650c Added more debug logging 2020-09-07 22:54:20 +01:00
675cc3c329 Import missing facade 2020-09-07 22:35:42 +01:00
e8119b763c Register Application observers 2020-09-07 21:43:48 +01:00
04838048ce
Merge pull request #10 from spacejewel-hosting/translate
Force new users to verify email
2020-09-03 20:22:11 +01:00
87f8e63b24 Force new users to verify email 2020-09-03 20:06:29 +01:00
16 changed files with 172 additions and 23 deletions

View File

@ -21,9 +21,6 @@ RECAPTCHA_PRIVATE_KEY=
RECAPTCHA_VERIFY_URL="https://www.google.com/recaptcha/api/siteverify" RECAPTCHA_VERIFY_URL="https://www.google.com/recaptcha/api/siteverify"
# WARNING: Your contact form will be useless if you change this value. Only change this URL if Google updates it. # WARNING: Your contact form will be useless if you change this value. Only change this URL if Google updates it.
IPGEO_API_KEY=""
IPGEO_API_URL=""
MOJANG_STATUS_URL="https://status.mojang.com/check" MOJANG_STATUS_URL="https://status.mojang.com/check"
MOJANG_API_URL="https://api.mojang.com" MOJANG_API_URL="https://api.mojang.com"
@ -32,7 +29,7 @@ IPGEO_API_URL="https://api.ipgeolocation.io/ipgeo"
ARCANEDEV_LOGVIEWER_MIDDLEWARE=web,auth,can:admin.maintenance.logs.view ARCANEDEV_LOGVIEWER_MIDDLEWARE=web,auth,can:admin.maintenance.logs.view
RELEASE=staffmanagement@0.2.0 RELEASE=staffmanagement@0.6.1
SLACK_INTEGRATION_WEBHOOK= SLACK_INTEGRATION_WEBHOOK=
@ -68,4 +65,8 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Mostly for developers, but with Papertrail, you can easily see what the app's users are doing without relying on
# the internal log viewer.
SENTRY_LARAVEL_DSN= SENTRY_LARAVEL_DSN=
PAPERTRAIL_URL=
PAPERTRAIL_PORT

View File

@ -1,6 +1,6 @@
# Raspberry Teams - The Simple Staff Application Manager v 0.5.2 [![Crowdin](https://badges.crowdin.net/raspberry-staff-manager/localized.svg)](https://crowdin.com/project/raspberry-staff-manager) # RB Recruiter v 0.6.2 [![Crowdin](https://badges.crowdin.net/raspberry-staff-manager/localized.svg)](https://crowdin.com/project/raspberry-staff-manager)
## The quick and pain-free staff application manager ## The quick and pain-free form management solution for communities
Have you ever gotten tired of managing your Minecraft server/network's applications through Discord (or anything else) and having to scroll through hundreds of new messages just to find that one applicant's username? Have you ever gotten tired of managing your Minecraft server/network's applications through Discord (or anything else) and having to scroll through hundreds of new messages just to find that one applicant's username?
@ -48,6 +48,14 @@ Tech stack:
- jQuery / Plain Javascript - jQuery / Plain Javascript
- vueJS (in the future) - vueJS (in the future)
# Stability
Currently, the ``master`` branch is highly unstable, since it's under active development. Expect it to break with each commit. Even though I make an effort to make sure each commit is good to go before pushing, things might still break unexpectedly, and you may find a lot of bugs (which you should report).
Every released version is currently pre-release. If you really want to run this before version ``1.0.0`` comes out, always stay on the latest version, as those will always be tested before release, ensuring less chaos.
*Note: This application is NOT production ready! It won't be until the first stable release comes out, which might take a bit longer.
# Operating System Requirements # Operating System Requirements
Currently, this application is only supported on Linux environments (Ubuntu 20.04 or derivatives are recommended). Currently, this application is only supported on Linux environments (Ubuntu 20.04 or derivatives are recommended).

19
SECURITY.md Normal file
View File

@ -0,0 +1,19 @@
# Security Policy
## Supported Versions
The following versions are currently supported:
| Version | Supported |
| ------- | ------------------ |
| 0.1.x | :x: |
| 0.5.x | :x: |
| 0.6.x | :white_check_mark: |
## Reporting a Vulnerability
To securely report a vulnerability, you may send me an email directly containing the details of said vulnerability: ``me@nogueira.codes``.
You may optionally encrypt your message with my [public PGP key](http://pool.sks-keyservers.net/pks/lookup?op=get&search=0x48DF709E7405702B).
Use this free [online encryption tool](https://www.igolder.com/pgp/encryption/) if you don't know how to use PGP on your desktop.

View File

@ -17,6 +17,10 @@ class Ban extends Model
]; ];
public $dates = [
'bannedUntil'
];
public function user() public function user()
{ {
return $this->belongsTo('App\User', 'userID', 'id'); return $this->belongsTo('App\User', 'userID', 'id');

View File

@ -99,12 +99,16 @@ class Install extends Command
$settings['MAIL_PASSWORD'] = $this->secret('SMTP Password (Input won\'t be seen)'); $settings['MAIL_PASSWORD'] = $this->secret('SMTP Password (Input won\'t be seen)');
$settings['MAIL_PORT'] = $this->ask('SMTP Server Port'); $settings['MAIL_PORT'] = $this->ask('SMTP Server Port');
$settings['MAIL_HOST'] = $this->ask('SMTP Server Hostname'); $settings['MAIL_HOST'] = $this->ask('SMTP Server Hostname');
$settings['MAIL_FROM_ADDRESS'] = $this->ask('E-mail address to send from');
$this->info('== Notification Settings (5/6) (Slack) =='); $this->info('== Notification Settings (5/6) (Slack) ==');
$settings['SLACK_INTEGRATION_WEBHOOK'] = $this->ask('Integration webhook URL'); $settings['SLACK_INTEGRATION_WEBHOOK'] = $this->ask('Integration webhook URL');
$this->info('== Web Settings (6/6) =='); $this->info('== Web Settings (6/6) ==');
$settings['APP_URL'] = $this->ask('Application\'s URL'); $settings['APP_URL'] = $this->ask('Application\'s URL (ex. https://where.you.installed.theapp.com): ');
$settings['APP_LOGO'] = $this->ask('App logo (Link to an image): ');
$settings['APP_SITEHOMEPAGE'] = $this->ask('Site homepage (appears in the main header): ');
} while(!$this->confirm('Are you sure you want to save these settings? You can always go back and try again.')); } while(!$this->confirm('Are you sure you want to save these settings? You can always go back and try again.'));

View File

@ -15,7 +15,7 @@ class BanController extends Controller
public function insert(BanUserRequest $request, User $user) public function insert(BanUserRequest $request, User $user)
{ {
$this->authorize('create', Ban::class); $this->authorize('create', [Ban::class, $user]);
if (is_null($user->bans)) if (is_null($user->bans))
{ {
@ -50,13 +50,13 @@ class BanController extends Controller
else else
{ {
// Essentially permanent // Essentially permanent
$expiryDate->addYears(100); $expiryDate->addYears(5);
} }
$ban = Ban::create([ $ban = Ban::create([
'userID' => $user->id, 'userID' => $user->id,
'reason' => $reason, 'reason' => $reason,
'bannedUntil' => $expiryDate->toDateTimeString() ?? null, 'bannedUntil' => $expiryDate->format('Y-m-d H:i:s'),
'userAgent' => "Unknown", 'userAgent' => "Unknown",
'authorUserID' => Auth::user()->id 'authorUserID' => Auth::user()->id
]); ]);

View File

@ -7,6 +7,7 @@ use App\Options as Option;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class OptionsController extends Controller class OptionsController extends Controller
{ {
@ -29,17 +30,33 @@ class OptionsController extends Controller
{ {
if (Auth::user()->can('admin.settings.edit')) if (Auth::user()->can('admin.settings.edit'))
{ {
Log::debug('Updating application options', [
'ip' => $request->ip(),
'ua' => $request->userAgent(),
'username' => Auth::user()->username
]);
foreach($request->all() as $optionName => $option) foreach($request->all() as $optionName => $option)
{ {
try try
{ {
if (Options::optionExists($option)) Log::debug('Going through option ' . $optionName);
if (Options::optionExists($optionName))
{ {
Log::debug('Option exists, updating to new values', [
'opt' => $optionName,
'new_value' => $option
]);
Options::changeOption($optionName, $option); Options::changeOption($optionName, $option);
} }
} }
catch(\Exception $ex) catch(\Exception $ex)
{ {
Log::error('Unable to update options!', [
'msg' => $ex->getMessage(),
'trace' => $ex->getTraceAsString()
]);
report($ex);
$errorCond = true; $errorCond = true;
$request->session()->flash('error', 'An error occurred while trying to save settings: ' . $ex->getMessage()); $request->session()->flash('error', 'An error occurred while trying to save settings: ' . $ex->getMessage());
} }

View File

@ -27,7 +27,7 @@ class BanUserRequest extends FormRequest
{ {
return [ return [
'reason' => 'required|string', 'reason' => 'required|string',
'durationOperand' => 'nullable|integer', 'durationOperand' => 'nullable|string',
'durationOperator' => 'nullable|string' 'durationOperator' => 'nullable|string'
]; ];
} }

View File

@ -0,0 +1,45 @@
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
class LogAuthenticationFailure
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
$targetAccountID = 0;
$originalIP = "0.0.0.0";
if (isset($event->user->id))
{
$targetAccountID = $event->user->id;
}
Log::alert('SECURITY (login): Detected failed authentication attempt!', [
'targetAccountID' => $targetAccountID,
'existingAccount' => ($targetAccountID == 0) ? false : true,
'sourceIP' => request()->ip(),
'matchesAccountLastIP' => request()->ip() == $originalIP,
'sourceUserAgent' => request()->userAgent(),
]);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
class LogAuthenticationSuccess
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
Log::info('SECURITY (postauth-pre2fa): Detected successful login attempt', [
'accountID' => $event->user->id,
'sourceIP' => request()->ip(),
'matchesAccountLastIP' => request()->ip() == $event->user->originalIP,
'sourceUserAgent' => request()->userAgent(),
]);
}
}

View File

@ -3,6 +3,7 @@
namespace App\Observers; namespace App\Observers;
use App\Application; use App\Application;
use Illuminate\Support\Facades\Log;
class ApplicationObserver class ApplicationObserver
{ {

View File

@ -39,17 +39,18 @@ class BanPolicy
* Determine whether the user can create models. * Determine whether the user can create models.
* *
* @param \App\User $user * @param \App\User $user
* @param User $targetUser
* @return mixed * @return mixed
*/ */
public function create(User $user) public function create(User $user, User $targetUser)
{ {
Log::debug("Authorization check started", [ Log::debug("Authorization check started", [
'requiredRoles' => 'admin', 'requiredRoles' => 'admin',
'currentRoles' => $user->roles(),
'hasRequiredRole' => $user->hasRole('admin'), 'hasRequiredRole' => $user->hasRole('admin'),
'targetUser' => $targetUser->username,
'isCurrentUser' => Auth::user()->is($user) 'isCurrentUser' => Auth::user()->is($user)
]); ]);
return $user->hasRole('admin') && Auth::user()->isNot($user); return $user->hasRole('admin') && $user->isNot($targetUser);
} }
/** /**

View File

@ -2,6 +2,8 @@
namespace App\Providers; namespace App\Providers;
use App\Application;
use App\Observers\ApplicationObserver;
use App\Observers\UserObserver; use App\Observers\UserObserver;
use App\User; use App\User;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
@ -32,7 +34,9 @@ class AppServiceProvider extends ServiceProvider
]); ]);
Schema::defaultStringLength(191); Schema::defaultStringLength(191);
User::observe(UserObserver::class); User::observe(UserObserver::class);
Application::observe(ApplicationObserver::class);
$this->app['request']->server->set('HTTPS', $this->app->environment() != 'local'); $this->app['request']->server->set('HTTPS', $this->app->environment() != 'local');
} }

View File

@ -2,7 +2,11 @@
namespace App\Providers; namespace App\Providers;
use App\Listeners\LogAuthenticationFailure;
use App\Listeners\LogAuthenticationSuccess;
use App\Listeners\OnUserRegistration; use App\Listeners\OnUserRegistration;
use Illuminate\Auth\Events\Failed;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification; use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@ -20,6 +24,12 @@ class EventServiceProvider extends ServiceProvider
SendEmailVerificationNotification::class, SendEmailVerificationNotification::class,
OnUserRegistration::class OnUserRegistration::class
], ],
Failed::class => [
LogAuthenticationFailure::class
],
Login::class => [
LogAuthenticationSuccess::class
],
'App\Events\ApplicationApprovedEvent' => [ 'App\Events\ApplicationApprovedEvent' => [
'App\Listeners\PromoteUser' 'App\Listeners\PromoteUser'
], ],

View File

@ -7,11 +7,10 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles; use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable class User extends Authenticatable implements MustVerifyEmail
{ {
use Notifiable; use Notifiable;
use HasRoles; use HasRoles;
//use MustVerifyEmail;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@ -17,7 +17,7 @@ Route::group(['prefix' => LaravelLocalization::setLocale(), 'middleware' => [ 'l
Route::group(['prefix' => 'auth', 'middleware' => ['usernameUUID']], function (){ Route::group(['prefix' => 'auth', 'middleware' => ['usernameUUID']], function (){
Auth::routes(); Auth::routes(['verify' => true]);
Route::post('/twofa/authenticate', 'Auth\TwofaController@verify2FA') Route::post('/twofa/authenticate', 'Auth\TwofaController@verify2FA')
->name('verify2FA'); ->name('verify2FA');
@ -31,7 +31,7 @@ Route::group(['prefix' => LaravelLocalization::setLocale(), 'middleware' => [ 'l
->name('sendSubmission'); ->name('sendSubmission');
Route::group(['middleware' => ['auth', 'forcelogout', '2fa']], function(){ Route::group(['middleware' => ['auth', 'forcelogout', '2fa', 'verified']], function(){
Route::get('/dashboard', 'DashboardController@index') Route::get('/dashboard', 'DashboardController@index')
->name('dashboard') ->name('dashboard')