init
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\AccessKey;
|
||||
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Lucent\LucentException;
|
||||
use Lucent\Member\Role;
|
||||
|
||||
class AccessKey
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
public readonly string $_id,
|
||||
public readonly string $name,
|
||||
public readonly Role $role,
|
||||
public readonly string $token,
|
||||
private readonly ?string $showOnceToken = null,
|
||||
) {
|
||||
$validator = Validator::make($this->toArray(), [
|
||||
'name' => 'min:3,max:120',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
throw new LucentException($validator->errors()->first());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function fromArray(array $data): AccessKey
|
||||
{
|
||||
|
||||
return new AccessKey(
|
||||
_id: data_get($data, "_id"),
|
||||
name: data_get($data, "name"),
|
||||
role: Role::from(data_get($data, "role")),
|
||||
token: data_get($data, "token"),
|
||||
);
|
||||
}
|
||||
|
||||
public function getShowOnceToken(): ?string
|
||||
{
|
||||
return $this->showOnceToken;
|
||||
}
|
||||
|
||||
public function isValid(string $token): bool
|
||||
{
|
||||
return Hash::check($token, $this->token);
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return \json_decode(\json_encode($this), true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\AccessKey;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Lucent\Channel\ChannelContext;
|
||||
use Lucent\DB\Monger;
|
||||
|
||||
class AccessKeyRepo
|
||||
{
|
||||
|
||||
public static function findByToken(string $token): ?AccessKey
|
||||
{
|
||||
$channel = ChannelContext::get()->channel;
|
||||
return $channel->accessKeys->firstWhere("token",$token);
|
||||
}
|
||||
|
||||
public static function add(AccessKey $accessKey): void
|
||||
{
|
||||
$channel = ChannelContext::get()->channel;
|
||||
Monger::central()->updateOne("channels", ["_id" => $channel->_id], [
|
||||
'$push' => [
|
||||
"accessKeys" => $accessKey->toArray()
|
||||
],
|
||||
'$set' => [
|
||||
"updatedAt" => Carbon::now()->toJson(),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public static function remove(string $id): void
|
||||
{
|
||||
$channel = ChannelContext::get()->channel;
|
||||
Monger::central()->updateOne("channels", ["_id" => $channel->_id], [
|
||||
'$pull' => [
|
||||
"accessKeys" => ["_id" => $id]
|
||||
],
|
||||
'$set' => [
|
||||
"updatedAt" => Carbon::now()->toJson(),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\AccessKey;
|
||||
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Lucent\Id\Id;
|
||||
use Lucent\LucentException;
|
||||
use Lucent\Member\Role;
|
||||
|
||||
class AccessKeyService
|
||||
{
|
||||
|
||||
public static function create(string $name, string $role): AccessKey
|
||||
{
|
||||
$showOnceToken = Str::random(48);
|
||||
$accessKey = new AccessKey(
|
||||
_id: Id::new(),
|
||||
name: $name,
|
||||
token: hash("sha256", $showOnceToken),
|
||||
role: Role::from($role),
|
||||
showOnceToken: $showOnceToken,
|
||||
);
|
||||
|
||||
AccessKeyRepo::add($accessKey);
|
||||
return $accessKey;
|
||||
}
|
||||
|
||||
public static function findByToken(string $token): ?AccessKey
|
||||
{
|
||||
$hashedToken = hash("sha256", $token);
|
||||
return AccessKeyRepo::findByToken($hashedToken);
|
||||
}
|
||||
|
||||
public static function remove(string $id): void
|
||||
{
|
||||
|
||||
AccessKeyRepo::remove($id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\AccessKey;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Support\Collection<int|string, AccessKey>
|
||||
*/
|
||||
final class AccessKeysCollection extends Collection
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
AccessKey ...$array
|
||||
) {
|
||||
parent::__construct($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccessKey[]
|
||||
**/
|
||||
public function toArray(): array
|
||||
{
|
||||
return collect($this)->values()->toArray();
|
||||
}
|
||||
|
||||
|
||||
public function toDB(): array
|
||||
{
|
||||
return \json_decode(\json_encode($this), true);
|
||||
}
|
||||
|
||||
|
||||
public static function fromArray(array $data): AccessKeysCollection
|
||||
{
|
||||
$item = array_map([AccessKey::class, 'fromArray'], $data);
|
||||
return new AccessKeysCollection(...$item);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\AccessKey;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Lucent\Account\Role;
|
||||
|
||||
class ApiMiddleware
|
||||
{
|
||||
|
||||
public function handle(Request $request, Closure $next, string $accessLevel): Response
|
||||
{
|
||||
|
||||
$bearerToken = $request->header('Authorization');
|
||||
$token = str_replace('Bearer ', '', $bearerToken);
|
||||
|
||||
$role = match ($token) {
|
||||
config("lucent.read_key") => Role::READER,
|
||||
config("lucent.write_key") => Role::EDITOR,
|
||||
config("lucent.developer_key") => Role::DEVELOPER,
|
||||
default => ""
|
||||
};
|
||||
|
||||
if (empty($role)) {
|
||||
abort(401);
|
||||
}
|
||||
|
||||
|
||||
if (!$role->hasAccess($accessLevel)) {
|
||||
abort(401);
|
||||
}
|
||||
|
||||
$request->mergeIfMissing(['userId' => "system"]);
|
||||
$request->mergeIfMissing(['userRole' => $role->value]);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user