-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #129 from wri/release/desert-date
[RELEASE] Dessert Date
- Loading branch information
Showing
41 changed files
with
745 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
namespace App\Auth; | ||
|
||
use App\Models\User; | ||
use Illuminate\Auth\GuardHelpers; | ||
use Illuminate\Contracts\Auth\Authenticatable; | ||
use Illuminate\Contracts\Auth\Guard; | ||
use Illuminate\Http\Request; | ||
use Tymon\JWTAuth\Exceptions\TokenInvalidException; | ||
use Tymon\JWTAuth\Validators\TokenValidator; | ||
|
||
class ServiceAccountGuard implements Guard | ||
{ | ||
use GuardHelpers; | ||
|
||
const HEADER = 'authorization'; | ||
CONST PREFIX = 'bearer'; | ||
const API_KEY_LENGTH = 64; | ||
|
||
protected Request $request; | ||
|
||
public function __construct(Request $request) | ||
{ | ||
$this->request = $request; | ||
} | ||
|
||
public function user(): ?Authenticatable | ||
{ | ||
if ($this->user !== null) { | ||
return $this->user; | ||
} | ||
|
||
$apiKey = $this->getApiKey(); | ||
if ($apiKey == null) { | ||
return null; | ||
} | ||
|
||
return $this->user = User::where('api_key', $apiKey)->first(); | ||
} | ||
|
||
public function validate(array $credentials = []): bool | ||
{ | ||
// There's no logging in or validating for this guard. | ||
return false; | ||
} | ||
|
||
protected function getApiKey(): ?string | ||
{ | ||
$header = $this->request->headers->get(self::HEADER); | ||
if ($header == null) { | ||
return null; | ||
} | ||
|
||
$position = strripos($header, self::PREFIX); | ||
if ($position === false) { | ||
return null; | ||
} | ||
|
||
$bearerValue = trim(substr($header, $position + strlen(self::PREFIX))); | ||
if (strlen($bearerValue) !== self::API_KEY_LENGTH || $this->isJwt($bearerValue)) { | ||
return null; | ||
} | ||
|
||
return $bearerValue; | ||
} | ||
|
||
protected function isJwt($value): bool | ||
{ | ||
try { | ||
return (new TokenValidator())->check($value) != null; | ||
} catch (TokenInvalidException $exception) { | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
namespace App\Console\Commands; | ||
|
||
use App\Models\V2\User; | ||
use App\Validators\ServiceAccountValidator; | ||
use DateTime; | ||
use DateTimeZone; | ||
use Exception; | ||
use Illuminate\Console\Command; | ||
use Spatie\Permission\Models\Role; | ||
|
||
class CreateServiceAccount extends Command | ||
{ | ||
/** | ||
* The name and signature of the console command. | ||
* | ||
* @var string | ||
*/ | ||
protected $signature = 'create-service-account {email}'; | ||
|
||
/** | ||
* The console command description. | ||
* | ||
* @var string | ||
*/ | ||
protected $description = 'Creates a service account with the given email address.'; | ||
|
||
/** | ||
* Execute the console command. | ||
*/ | ||
public function handle() | ||
{ | ||
try { | ||
$email = $this->argument('email'); | ||
|
||
$apiKey = base64_encode(random_bytes(48)); | ||
|
||
$data = [ | ||
'email_address' => $email, | ||
'api_key' => $apiKey, | ||
]; | ||
ServiceAccountValidator::validate('CREATE', $data); | ||
|
||
$data['role'] = 'service'; | ||
$data['email_address_verified_at'] = new DateTime('now', new DateTimeZone('UTC')); | ||
|
||
$user = new User($data); | ||
$user->saveOrFail(); | ||
// TODO Allow other types of service account, when/if necessary. | ||
$user->assignRole('greenhouse-service-account'); | ||
|
||
$this->info("Created service account $email with API Key: $apiKey"); | ||
return 0; | ||
|
||
} catch (Exception $exception) { | ||
$this->error($exception->getMessage()); | ||
$this->error('Creation failed'); | ||
return -1; | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
app/Console/Commands/OneOff/CreateGreenhouseServiceAccountRole.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
namespace App\Console\Commands\OneOff; | ||
|
||
use Illuminate\Console\Command; | ||
use Spatie\Permission\Models\Permission; | ||
use Spatie\Permission\Models\Role; | ||
|
||
class CreateGreenhouseServiceAccountRole extends Command | ||
{ | ||
/** | ||
* The name and signature of the console command. | ||
* | ||
* @var string | ||
*/ | ||
protected $signature = 'one-off:create-greenhouse-service-account-role'; | ||
|
||
/** | ||
* The console command description. | ||
* | ||
* @var string | ||
*/ | ||
protected $description = 'Creates the Greenhouse service account role'; | ||
|
||
/** | ||
* Execute the console command. | ||
*/ | ||
public function handle() | ||
{ | ||
// Keep this command idempotent | ||
$role = Role::where('name', 'greenhouse-service-account')->first(); | ||
if ($role == null) { | ||
$role = Role::create(['name' => 'greenhouse-service-account']); | ||
} | ||
|
||
// Make sure all permissions in config/permissions have been created. | ||
$permissionKeys = array_keys(config('wri.permissions')); | ||
foreach ($permissionKeys as $key) { | ||
if (Permission::where('name', $key)->count() === 0) { | ||
Permission::create(['name' => $key]); | ||
} | ||
} | ||
|
||
$role->syncPermissions(['projects-read', 'polygons-manage', 'media-manage']); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace App\Jobs\V2; | ||
|
||
use App\Mail\EntityStatusChange as EntityStatusChangeMail; | ||
use App\Models\V2\EntityModel; | ||
use App\StateMachines\EntityStatusStateMachine; | ||
use Illuminate\Bus\Queueable; | ||
use Illuminate\Contracts\Queue\ShouldQueue; | ||
use Illuminate\Foundation\Bus\Dispatchable; | ||
use Illuminate\Queue\InteractsWithQueue; | ||
use Illuminate\Queue\SerializesModels; | ||
use Illuminate\Support\Facades\Mail; | ||
|
||
class SendEntityStatusChangeEmailsJob implements ShouldQueue | ||
{ | ||
use Dispatchable; | ||
use InteractsWithQueue; | ||
use Queueable; | ||
use SerializesModels; | ||
|
||
private EntityModel $entity; | ||
|
||
public function __construct(EntityModel $entity) | ||
{ | ||
$this->entity = $entity; | ||
} | ||
|
||
public function handle(): void | ||
{ | ||
if ($this->entity->status != EntityStatusStateMachine::APPROVED && | ||
$this->entity->status != EntityStatusStateMachine::NEEDS_MORE_INFORMATION && | ||
$this->entity->update_request_status != EntityStatusStateMachine::NEEDS_MORE_INFORMATION) { | ||
return; | ||
} | ||
|
||
$emailAddresses = $this->entity->project->users()->pluck('email_address'); | ||
if (empty($emailAddresses)) { | ||
return; | ||
} | ||
|
||
// TODO: This is a temporary hack to avoid spamming folks that have a funky role right now. In the future, | ||
// they will have a different role, and we can simply skip sending this email to anybody with that role. | ||
$skipRecipients = collect(explode(',', getenv('ENTITY_UPDATE_DO_NOT_EMAIL'))); | ||
foreach ($emailAddresses as $emailAddress) { | ||
if ($skipRecipients->contains($emailAddress)) { | ||
continue; | ||
} | ||
|
||
Mail::to($emailAddress)->send(new EntityStatusChangeMail($this->entity)); | ||
} | ||
} | ||
} |
Oops, something went wrong.