diff --git a/app/Application.php b/app/Application.php index eae5c83..5aa958a 100755 --- a/app/Application.php +++ b/app/Application.php @@ -33,6 +33,11 @@ class Application extends Model ]; + public function oneoffApplicant() + { + return $this->hasOne('App\OneoffApplicant', 'application_id', 'id'); + } + public function user() { return $this->belongsTo('App\User', 'applicantUserID', 'id'); @@ -64,4 +69,12 @@ class Application extends Model 'applicationStatus' => $status, ]); } + + + public function isOneoff() + { + return $this->user->id == 1; // ID 1 is always the ghost + } + + } diff --git a/app/OneoffApplicant.php b/app/OneoffApplicant.php new file mode 100644 index 0000000..9a25c9e --- /dev/null +++ b/app/OneoffApplicant.php @@ -0,0 +1,17 @@ +belongsTo('App\Application', 'id', 'application_id'); + } +} + diff --git a/composer.json b/composer.json index 17fbc61..ca5c589 100755 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "guzzlehttp/guzzle": "^7.0.1", "jeroennoten/laravel-adminlte": "^3.2", "laravel/framework": "^8.0", + "laravel/sanctum": "^2.8", "laravel/slack-notification-channel": "^2.0", "laravel/tinker": "^2.0", "laravel/ui": "^3.0", diff --git a/composer.lock b/composer.lock index 1b338b4..9d33ebf 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d11a4225e7b8dbcb7d676dd0a918d0b3", + "content-hash": "a0027d10b40da0082f6184838be3caa6", "packages": [ { "name": "almasaeed2010/adminlte", @@ -2040,6 +2040,70 @@ ], "time": "2020-10-06T14:22:36+00:00" }, + { + "name": "laravel/sanctum", + "version": "v2.8.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "331bd6572610b06ad6dd6b2a7c15a0465a3ca9c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/331bd6572610b06ad6dd6b2a7c15a0465a3ca9c9", + "reference": "331bd6572610b06ad6dd6b2a7c15a0465a3ca9c9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/contracts": "^6.9|^7.0|^8.0", + "illuminate/database": "^6.9|^7.0|^8.0", + "illuminate/support": "^6.9|^7.0|^8.0", + "php": "^7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.0|^5.0|^6.0", + "phpunit/phpunit": "^8.0|^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2020-11-24T17:31:19+00:00" + }, { "name": "laravel/slack-notification-channel", "version": "v2.2.0", @@ -9886,5 +9950,5 @@ "ext-json": "*" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.0.0" } diff --git a/config/sanctum.php b/config/sanctum.php new file mode 100644 index 0000000..835e880 --- /dev/null +++ b/config/sanctum.php @@ -0,0 +1,50 @@ + explode(',', env( + 'SANCTUM_STATEFUL_DOMAINS', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1' + )), + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. If this value is null, personal access tokens do + | not expire. This won't tweak the lifetime of first-party sessions. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, + 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, + ], + +]; diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php new file mode 100644 index 0000000..3ce0002 --- /dev/null +++ b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('personal_access_tokens'); + } +} diff --git a/database/migrations/2021_01_01_201604_oneoff_applicants.php b/database/migrations/2021_01_01_201604_oneoff_applicants.php new file mode 100644 index 0000000..192100d --- /dev/null +++ b/database/migrations/2021_01_01_201604_oneoff_applicants.php @@ -0,0 +1,43 @@ +id(); + $table->string('name'); + $table->string('email'); + $table->bigInteger('application_id')->unsigned(); + $table->timestamps(); + + $table->foreign('application_id') + ->references('id') + ->on('applications') + + ->onDelete('cascade') + ->onUpdate('cascade'); + + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('oneoff_applicants'); + } +} diff --git a/database/seeders/DefaultOptionsSeeder.php b/database/seeders/DefaultOptionsSeeder.php index 2cfb775..bffa641 100755 --- a/database/seeders/DefaultOptionsSeeder.php +++ b/database/seeders/DefaultOptionsSeeder.php @@ -42,5 +42,16 @@ class DefaultOptionsSeeder extends Seeder Options::setOption('enable_slack_notifications', true, 'Enable slack notifications'); Options::setOption('enable_email_notifications', true, 'Enable e-mail notifications'); + + // added in 0.6.2 + Options::setOption('pw_security_policy', 'low', 'Describes the current password security policy.'); + Options::setOption('graceperiod', 7, '2FA Grace Period'); + Options::setOption('password_expiry', 'disabled', 'Defines wether passwords must be reset after $value'); + Options::setOption('force2fa', false, 'Defines whether 2fa is forced upon users'); + Options::setOption('force2faRole', 'reviewer', 'Defines which role to force 2fa for'); + Options::setOption('requireGameLicense', true, 'Defines whether people need to validate their game license'); + + Options::setOption('currentGame', 'MINECRAFT', 'Defines what game we\'re working with'); + } } diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index af89e15..4c2ed3a 100755 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -35,129 +35,41 @@ class UserSeeder extends Seeder */ public function run() { - $staffUsers = [ + + /** + * Rationale: + * A ghost account is an account used by deleted users. + * Essentially, when users are deleted, their content is re-assigned to the + * ghost account. + * Also used by one-off apps. + * + * The ghost account was inspired by Github's ghost account. + */ + $ghostAccount = User::create([ + 'uuid' => '069a79f444e94726a5befca90e38aaf5', // Notch + 'name' => 'Ghost (deleted account)', + 'email' => 'blackhole@spacejewel-hosting.com', + 'username' => 'ghost', + 'originalIP' => '0.0.0.0', + 'password' => 'locked' + ])->assignRole('user'); // There can't be role-less users - [ - 'uuid' => 'd2b321b56ff1445db9d7794701983cad', - 'name' => 'Robot 1', - 'email' => 'tester1@example.com', - 'username' => 'tester1', - 'originalIP' => '99.18.146.235', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => 'ab22b5da02644953ace969fce85c0819', - 'name' => 'Robot 2', - 'email' => 'tester2@example.com', - 'username' => 'tester2', - 'originalIP' => '141.239.229.53', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => 'df38e6bf762944d3a600ded59a693ad1', - 'name' => 'Robot 3', - 'email' => 'tester3@example.com', - 'username' => 'tester3', - 'originalIP' => '25.63.20.97', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => '689e446484824f6bad5064e3df0aaa96', - 'name' => 'Robot 4', - 'email' => 'tester4@example.com', - 'username' => 'tester4', - 'originalIP' => '220.105.223.142', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => '172391f917bf418ab1c40ebc041ed5ba', - 'name' => 'Robot 5', - 'email' => 'tester5@example.com', - 'username' => 'tester5', - 'originalIP' => '224.66.76.60', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => '371f34dcce2a4457bf385ab9417a2345', - 'name' => 'Robot 6', - 'email' => 'tester6@example.com', - 'username' => 'tester6', - 'originalIP' => '97.113.131.0', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => '89aa5222855542bebe7a7780248ef5f9', - 'name' => 'Robot 7', - 'email' => 'tester7@example.com', - 'username' => 'tester7', - 'originalIP' => '15.160.137.222', - 'password' => Hash::make('password'), - ], - ]; - - $regularUsers = [ - - [ - 'uuid' => '20f69f47e72f463493b5b91d1c05452f', - 'name' => 'User 1', - 'email' => 'user1@example.com', - 'username' => 'user1', - 'originalIP' => '253.25.237.78', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => '5f900018241e4aaba7883f2d5c5c2357', - 'name' => 'User 2', - 'email' => 'user2@example.com', - 'username' => 'user2', - 'originalIP' => '82.92.156.176', - 'password' => Hash::make('password'), - ], - [ - 'uuid' => 'ba9780c3270745c6840eaabe1bf8aa14', - 'name' => 'User 3', - 'email' => 'user3@example.com', - 'username' => 'user3', - 'originalIP' => '224.123.129.17', - 'password' => Hash::make('password'), - ], - - ]; - - foreach ($regularUsers as $regularUser) { - $user = User::create($regularUser); - Profile::create([ - 'profileShortBio' => 'Random data '.rand(0, 1000), - 'profileAboutMe' => 'Random data '.rand(0, 1000), - 'socialLinks' => '[]', // empty json set, not an array - 'avatarPreference' => 'gravatar', - 'userID' => $user->id, - ]); - } - - foreach ($staffUsers as $staffUser) { - $user = User::create($staffUser); - Profile::create([ - 'profileShortBio' => 'Random data '.rand(0, 1000), - 'profileAboutMe' => 'Random data '.rand(0, 1000), - 'socialLinks' => '[]', - 'avatarPreference' => 'gravatar', - 'userID' => $user->id, - ]); - } - - User::create([ + $admin = User::create([ 'uuid' => '6102256abd284dd7b68e4c96ef313734', 'name' => 'Admin', 'email' => 'admin@example.com', 'username' => 'admin', - 'originalIP' => '192.168.1.2', + 'originalIP' => '217.1.189.34', 'password' => Hash::make('password'), + + ])->assignRole([ // all privileges + 'user', + 'reviewer', + 'admin', + 'hiringManager', + 'developer' ]); - foreach (User::all() as $user) { - $user->assignRole('reviewer', 'user'); - } } }