diff --git a/src/Tor/Api.php b/src/Tor/Api.php index 1188442..7139612 100644 --- a/src/Tor/Api.php +++ b/src/Tor/Api.php @@ -2,16 +2,24 @@ namespace Tor; +use Tor\Controller\ServiceApi; use Tor\Controller\GrantApi; use Tor\Controller\TicketApi; +use Tor\Controller\ApiAuth; + use Gac\Routing\Request; +use Gac\Routing\Routes; // Implements the dispatcher for Tor's API class Api { public function init() { global $routes; + $middlewareE = [ [ApiAuth::class, 'authExternal'] ]; + $middlewareI = [ [ApiAuth::class, 'authInternal'] ]; + $middlewareS = [ [ApiAuth::class, 'authSystem'] ]; + // Respond with supported legacy versions and current version of API $routes->add('/api', function (Request $request) { $request->status(200, 'OK') @@ -20,93 +28,109 @@ class Api { $routes->add('/api/v1', function (Request $request) { $request->status(200, 'OK') - ->send([ 'result' => 'unauthorized' ]); - }); - - // Internal: List all users - $routes->add('/api/v1/user/list', function (Request $request) { - $request->status(200, 'OK') ->send([ 'result' => 'ok' ]); }); - // Internal: Assign a given new public key id to username + // No Action specified + $routes->middleware($middlewareS)->add('/api/v1/user', [ UserApi::class, 'response' ]); + + // System: Assign a given new public key id and cert to username // Creates user if it doesn't exist - $routes->add('/api/v1/user/assign', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + $routes->middleware($middlewareS)->add('/api/v1/user/provision/{userName}', [ UserApi::class, 'provision' ]); - // Internal: Delete User and all Sessions + ExtraData - $routes->add('/api/v1/user/delete/{username}', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + // System: Delete User and all Sessions + ExtraData + $routes->middleware($middlewareS)->add('/api/v1/user/delete/{userName}', [ UserApi::class, 'delete' ]); - // Internal: Create a new permission group - $routes->add('/api/v1/group/create/{name}', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + // System: Fetch info about user + $routes->middleware($middlewareS)->add('/api/v1/user/info/{userName}', [ UserApi::class, 'info' ]); - // Internal: Delete a permission group - $routes->add('/api/v1/group/delete/{name}', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + // System: List all users + $routes->middleware($middlewareS)->add('/api/v1/user/list', [ UserApi::class, 'list' ]); - // Internal: Assign User to Group - $routes->add('/api/v1/group/assign/{name}', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + // No Action specified + $routes->middleware($middlewareS)->add('/api/v1/group', [ GroupApi::class, 'response' ]); - // Internal: Revoke User's Group Membership - $routes->add('/api/v1/group/revoke', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); + // System: Change properties of group, like default provisioning for ex. + // If not exists: Create a new permission group + $routes->middleware($middlewareS)->add('/api/v1/group/provision/{groupName}', [ GroupApi::class, 'provision' ]); + + // System: Delete a permission group + $routes->middleware($middlewareS)->add('/api/v1/group/delete/{groupName}', [ GroupApi::class, 'delete' ]); + + // System: Assign User to Group + $routes->middleware($middlewareS)->add('/api/v1/group/assign/{groupName}', [ GroupApi::class, 'assign' ]); + + // System: Revoke User's Group Membership + $routes->middleware($middlewareS)->add('/api/v1/group/revoke/{groupName}', [ GroupApi::class, 'revoke' ]); + + // Fetch info about group + $routes->middleware($middlewareS)->add('/api/v1/group/info/{groupName}', [ GroupApi::class, 'info' ]); + + // List all groups + $routes->middleware($middlewareS)->add('/api/v1/group/list', [ GroupApi::class, 'list' ]); + + // List all groups by service + $routes->middleware($middlewareS)->add('/api/v1/group/list/{serviceName}', [ GroupApi::class, 'listByService' ]); - // Internal: Delete User and all Sessions + ExtraData - $routes->add('/api/v1/group/delete', function (Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); - }); - // No action specified - $routes->add('/api/v1/grant', [ GrantApi::class, 'response' ]); + $routes->middleware($middlewareE)->add('/api/v1/service', [ ServiceApi::class, 'response' ]); + + // System: Provision a new token or api level for a given service + // Creates Service if it does not exist + $routes->middleware($middlewareS)->add('/api/v1/service/provision/{serviceName}', [ ServiceApi::class, 'provision' ]); + + // System: Delete a service and all grants, tickets depending on it + $routes->middleware($middlewareS)->add('/api/v1/service/delete/{serviceName}', [ ServiceApi::class, 'delete' ]); + + // System: List info about a service + $routes->middleware($middlewareS)->add('/api/v1/service/info/{serviceName}', [ ServiceApi::class, 'info' ]); + + // System: List all services + $routes->middleware($middlewareS)->add('/api/v1/service/list', [ ServiceApi::class, 'list' ]); + + // ---------------------------------------------------- // + + // No action specified + $routes->middleware($middlewareE)->add('/api/v1/grant', [ GrantApi::class, 'response' ]); // Create Ticket Granting Ticket - $routes->add('/api/v1/grant/create', [ GrantApi::class, 'create' ]); + $routes->middleware($middlewareE)->add('/api/v1/grant/create', [ GrantApi::class, 'create' ]); // Invalidate Ticket Granting Ticket - $routes->add('/api/v1/grant/destroy/{grantID}', [ GrantApi::class, 'destroy' ]); + $routes->middleware($middlewareE)->add('/api/v1/grant/destroy/{grantID}', [ GrantApi::class, 'destroy' ]); // Poll Authorization Status of Grant - $routes->add('/api/v1/grant/status/{grantID}', [ GrantApi::class, 'status' ]); + $routes->middleware($middlewareE)->add('/api/v1/grant/status/{grantID}', [ GrantApi::class, 'status' ]); - // Internal: List all active Grants - $routes->add('/api/v1/grant/list', [ GrantApi::class, 'list' ]); + // Internal: List all active Grants for current service + $routes->middleware($middlewareI)->add('/api/v1/grant/list', [ GrantApi::class, 'list' ]); - // Internal: Approve of Grant with specified subset of extradata - $routes->add('/api/v1/grant/approve/{grantID}', [ GrantApi::class, 'approve' ]); + // System: Approve of Grant with specified subset of extradata + $routes->middleware($middlewareS)->add('/api/v1/grant/approve/{grantID}', [ GrantApi::class, 'approve' ]); // Internal: Reject Grant - $routes->add('/api/v1/grant/reject/{grantID}', [ GrantApi::class, 'reject' ]); + $routes->middleware($middlewareI)->add('/api/v1/grant/reject/{grantID}', [ GrantApi::class, 'reject' ]); - // Fetch ID of Session Ticket by using authorized Grant ID + // TODO: Decision + + // No action specified + $routes->middleware($middlewareE)->add('/api/v1/ticket', [ TicketApi::class, 'response' ]); + + // Fetch ID of Session Ticket by using authorized Grant ID => NEW: Decision OTP // Useful when polling manually, not neccessary when using callback - $routes->add('/api/v1/ticket/fetch/{grantID}', [ TicketApi::class, 'fetch' ]); + $routes->middleware($middlewareE)->add('/api/v1/ticket/fetch/{grantID}', [ TicketApi::class, 'fetch' ]); // Destroy active Session - $routes->add('/api/v1/ticket/destroy/{ticketID}', [ TicketApi::class, 'destroy' ]); + $routes->middleware($middlewareE)->add('/api/v1/ticket/destroy/{ticketID}', [ TicketApi::class, 'destroy' ]); // Poll authorization status and start / end date for session ticket - $routes->add('/api/v1/ticket/status/{ticketID}', [ TicketApi::class, 'status' ]); + $routes->middleware($middlewareE)->add('/api/v1/ticket/status/{ticketID}', [ TicketApi::class, 'status' ]); // Session KeepAlive - $routes->add('/api/v1/ticket/heartbeat/{ticketID}', [ TicketApi::class, 'heartbeat' ]); + $routes->middleware($middlewareE)->add('/api/v1/ticket/heartbeat/{ticketID}', [ TicketApi::class, 'heartbeat' ]); // Internal: List all active Session Tickets - $routes->add('/api/v1/ticket/list', [ TicketApi::class, 'list' ]); + $routes->middleware($middlewareI)->add('/api/v1/ticket/list', [ TicketApi::class, 'list' ]); + } } diff --git a/src/Tor/Common/Utils.php b/src/Tor/Common/Utils.php index 9c87283..c63a993 100644 --- a/src/Tor/Common/Utils.php +++ b/src/Tor/Common/Utils.php @@ -12,6 +12,18 @@ class Utils { $path = ( $path !== '/' ) ? rtrim($path, '/') : $path; return ( $position === false ) ? $path : substr($path, 0, $position); } + + public static function FetchPostData(): array | bool + { + // POST + $post_data = file_get_contents('php://input'); + + // Check if post data exists and auth json node is present + if ($post_data != false) + return json_decode($post_data, true)['data'] ?? false; + + return false; + } /** * Determines if the browser provided a valid SSL client certificate @@ -37,5 +49,44 @@ class Utils { return true; } + + public static function OTPFactory(int $length = 6, bool $alpha = false): string + { + // Take a generator string which consist of + // all numeric digits + // or all alpha numeric chars + if (!$alpha) + $generator = "1357902468"; + else + $generator = "qwerASDFGHJKLtzuioQWERTZUIOPpasdfgh102938jklyxcYXCVBNMvbnm4756"; + + // Iterate $length times and pick a single character + // from generator and append it to $result + + // Login for generating a random character from generator + // ---generate a random number + // ---take modulus of same with length of generator (say i) + // ---append the character at place (i) from generator to result + + $result = ""; + + for ($i = 1; $i <= $length; $i++) { + $result .= substr($generator, (rand()%(strlen($generator))), 1); + } + + // Return result + return $result; + } + + public static function TokenFactory(int $blocks = 4): string + { + $token = ""; + + // Generate a token consisting out of $blocks many blocks + for ($i = 1; $i <= $blocks; $i++) + $token = self::OTPFactory(length: 4, alpha: true) . '-' . $token; + + return $token; + } } ?> diff --git a/src/Tor/Controller/ApiAuth.php b/src/Tor/Controller/ApiAuth.php new file mode 100644 index 0000000..2792c41 --- /dev/null +++ b/src/Tor/Controller/ApiAuth.php @@ -0,0 +1,109 @@ + $_GET["service"], "token" => $_GET["token"]); + + if ($post_data != false) + { + $srv_value = trim($post_data['service'] ?? ""); + $token_value = trim($post_data['token'] ?? ""); + + if (!empty($srv_value) && !empty($token_value)) + return array("service" => $srv_value, "token" => $token_value); + } + + return false; + } + + private static function ProcessAuth() + { + global $data, $api_service; + + // We already have acquired authorization + // INFO: This might not be instance safe + if (isset($api_service)) + return; + + $authData = self::fetchAuth(); + + // Check if service exists + if ($authData != false && $data->exists(Service::class, $authData['service'])) + { + $service = $data->load(Service::class, $authData['service']); + if ($service->token != null && !empty(trim($service->token))) + { + // Check if authorization token matches + if ($service->token == $authData['token']) + $api_service = $service; + } + } + } + + public function authExternal(\Gac\Routing\Request $request) + { + $this->auth($request, AuthLevel::External); + } + + public function authInternal(\Gac\Routing\Request $request) + { + $this->auth($request, AuthLevel::Internal); + } + + public function authSystem(\Gac\Routing\Request $request) + { + $this->auth($request, AuthLevel::System); + } + + // Middleware for api authentication checking + private function auth(\Gac\Routing\Request $request, AuthLevel $minLevel = AuthLevel::External) + { + if (!self::MatchesLevel($minLevel)) { + $request->status(401, 'Unauthorized')->send(["error" => ["message" => "unauthorized"]]); + die(); + } + } + + // Returns current service if authorization successful + public static function GetService(): Service | null + { + global $api_service; + + self::ProcessAuth(); + + return $api_service ?? null; + } + + public static function MatchesLevel(AuthLevel $level): bool + { + if (self::GetService() != null + && self::GetService()->level->value >= $level->value) + return true; + + return false; + } +} + +?> \ No newline at end of file diff --git a/src/Tor/Controller/GrantApi.php b/src/Tor/Controller/GrantApi.php index 2384502..94f7909 100644 --- a/src/Tor/Controller/GrantApi.php +++ b/src/Tor/Controller/GrantApi.php @@ -7,6 +7,8 @@ use Tor\Data\Ticket; use Tor\Data\User; use Tor\Data\Service; +use Tor\Controller\ApiAuth; + use Gac\Routing\Request; class GrantApi extends BaseApi { @@ -21,20 +23,21 @@ class GrantApi extends BaseApi { while ($data->exists(Grant::class , $uniqid)) $uniqid = uniqid(); - // TODO: Services - $service = new Service(); - $service->id = uniqid(); - $grant = new Grant(); $grant->id = $uniqid; - $grant->service = $service; + $grant->service = ApiAuth::GetService(); $grant->create = time(); $data->save($grant); - $data->save($service); - $request->status(201, 'Created') - ->send([ 'grant' => $grant->id, 'service' => $grant->service->flatIdentifier(), 'result' => 'created' ]); + $response = [ + 'grant' => $grant->id, + 'service' => $grant->service->flatIdentifier(), + 'create' => $grant->create, + 'result' => 'created' + ]; + + $request->status(201, 'Created')->send($response); } // Destroy a grant and all dependencies @@ -59,7 +62,7 @@ class GrantApi extends BaseApi { } } - // Internal: Approve Grant (Only works if not authorized yet) + // System: Approve Grant (Only works if not authorized yet) function approve(\Gac\Routing\Request $request, string $grantID) { global $data; @@ -147,13 +150,18 @@ class GrantApi extends BaseApi { function list(\Gac\Routing\Request $request) { global $data; - // TODO: - $serviceName = '638bcc3500810'; + // Get name of authenticated service + $serviceName = ApiAuth::GetService()->flatIdentifier(); $grants = $data->fromIndex(Service::class, $serviceName, findClass: Grant::class); + $result = [ + 'grants' => $grants, + 'result' => 'ok' + ]; + $request->status(200, 'OK') - ->send([ 'grants' => $grants, 'result' => 'ok' ]); + ->send($result); } // Default response if no action is defined diff --git a/src/Tor/Controller/ServiceApi.php b/src/Tor/Controller/ServiceApi.php new file mode 100644 index 0000000..0f61e20 --- /dev/null +++ b/src/Tor/Controller/ServiceApi.php @@ -0,0 +1,137 @@ +exists(Service::class, $serviceName); + + $post_data = Utils::FetchPostData(); + + if ($post_data != false) { + $new_token = trim($post_data['token'] ?? ""); + $new_level = trim($post_data['level'] ?? ""); + } + + if (!$exists) { + $service = new Service(); + $service->id = $serviceName; + $service->level = AuthLevel::External; + $service->token = Utils::TokenFactory(); + } else { + $service = $data->load(Service::class, $serviceName); + } + + if (!empty($new_token)) + $service->token = $new_token; + + if (!empty($new_level)) + $service->level = AuthLevel::from($new_level); + + $data->save($service); + + $result = [ + 'service' => $service->flatIdentifier(), + 'token' => $service->token, + 'level' => $service->level->value, + ]; + + if (!$exists) { + $result['result'] = 'created'; + $request->status(201, 'Created') + ->send($result); + } else { + $result['result'] = 'provisioned'; + $request->status(200, 'OK') + ->send($result); + } + } + + // System: Delete a service and all dependencies + function delete(\Gac\Routing\Request $request, string $serviceName) { + global $data; + + $exists = $data->exists(Service::class, $serviceName); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $grants = $data->fromIndex(Service::class, $serviceName, findClass: Grant::class); + + if (!empty($grants)) + { + foreach ($grants as $grant) + { + $tickets = $data->fromIndex(Grant::class, $grant->flatIdentifier(), findClass: Ticket::class); + + $data->delete(Grant::class, $grant->flatIdentifier()); + + foreach ($tickets as $ticket) + $data->delete(Ticket::class, $ticket->flatIdentifier()); + } + } + + $data->delete(Service::class, $serviceName); + $request->status(200, 'OK')->send([ 'result' => 'destroyed' ]); + } + } + + // System: Fetch info about a Service + function info(\Gac\Routing\Request $request, string $serviceName) { + global $data; + + $exists = $data->exists(Service::class, $serviceName); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $service = $data->load(Service::class, $serviceName); + + $result = [ + 'service' => $service->flatIdentifier(), + 'token' => $service->token, + 'level' => $service->level->value, + 'result' => 'ok' + ]; + + $request->status(200, 'OK')->send($result); + } + } + + // System: List all Services + function list(\Gac\Routing\Request $request) { + global $data; + + $services = $data->listAll(Service::class); + + $result = [ + 'services' => $services, + 'result' => 'ok' + ]; + + $request->status(200, 'OK') + ->send($result); + } + + // Default response if no action is defined + function response(\Gac\Routing\Request $request) { + $request->status(200, 'OK')->send([ 'result' => 'ok' ]); + } + +} \ No newline at end of file diff --git a/src/Tor/Controller/TicketApi.php b/src/Tor/Controller/TicketApi.php index 0745144..2132b66 100644 --- a/src/Tor/Controller/TicketApi.php +++ b/src/Tor/Controller/TicketApi.php @@ -10,54 +10,94 @@ use Gac\Routing\Request; class TicketApi extends BaseApi { // Fetch ID of Session Ticket by using authorized Grant ID - function fetch(\Gac\Routing\Request $request) { + function fetch(\Gac\Routing\Request $request, string $grantId) { global $data; - // TODO: Identifier - $identifier = 'cats'; - $exists = $data->exists(Grant::class, $identifier); + $ticket = $data->fromIndex(Grant::class, $id, Ticket::class)[0] ?? null; - if (!$exists) + if ($ticket == null) + $request->status(200, 'OK')->send([ 'ticket' => $ticket->id, 'result' => 'found' ]); + else $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); - else { - // TODO: Create Ticket on Approval instead and ... load by index - $ticket = new Ticket(); - $ticket->grant = $data->load(Grant::class, $identifier); - $ticket->user = new User(); - $ticket->start = time(); - $ticket->end = time() + 86400; - - $data->save($ticket); - - $request->status(201, 'Created') - ->send([ 'ticket' => $ticket->id, 'result' => 'created' ]); - } } // Destroy active session - function destroy(\Gac\Routing\Request $request) { + function destroy(\Gac\Routing\Request $request, string $ticketId) { global $data; - // TODO: Identifier - $identifier = 'cats'; - $exists = $data->exists(Grant::class, $identifier); + $exists = $data->exists(Ticket::class, $ticketId); - if (!$exists) + if (!$exists) { $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); - else - $data->delete(Grant::class, $identifier); + } else { + $ticket = $data->load(Ticket::class, $ticketId); + $data->delete(Ticket::class, $ticketId); + + // Also delete grant + $data->delete(Grant::class, $ticket->grant->flatIdentifier()); + + $request->status(200, 'OK')->send([ 'result' => 'destroyed' ]); + } } // Poll authorization status and start / end date for session ticket - function status(\Gac\Routing\Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); + function status(\Gac\Routing\Request $request, string $ticketId) { + global $data; + + $exists = $data->exists(Ticket::class, $ticketId); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $ticket = $data->load(Ticket::class, $ticketId); + + $result = [ + 'user' => $ticket->user->flatIdentifier(), + 'grant' => $ticket->grant->flatIdentifier(), + 'start' => $ticket->start, + 'end' = $ticket->end, + 'status' => 'valid', + 'result' => 'ok' + ]; + + if ($ticket->end < time()) + $result["status"] = "expired"; + + $request->status(200, 'OK')->send($result); + } } // Session KeepAlive function heartbeat(\Gac\Routing\Request $request) { - $request->status(200, 'OK') - ->send([ 'result' => 'ok' ]); + global $data; + + $exists = $data->exists(Ticket::class, $ticketId); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $ticket = $data->load(Ticket::class, $ticketId); + + $result = [ + 'start' => $ticket->start, + 'end' = $ticket->end, + 'result' => 'expired' + ]; + + if ($ticket->end >= time()) + { + $ticket->end = time() + 86400; + $data->save($ticket); + + $result['end'] = $ticket->end; + $result['result'] = 'ok'; + + } + + $request->status(200, 'OK')->send($result); + } } // Internal: List all tickets diff --git a/src/Tor/Controller/UserApi.php b/src/Tor/Controller/UserApi.php new file mode 100644 index 0000000..272b461 --- /dev/null +++ b/src/Tor/Controller/UserApi.php @@ -0,0 +1,144 @@ +exists(Service::class, $serviceName); + + $post_data = Utils::FetchPostData(); + + if ($post_data != false) { + $new_token = trim($post_data['token'] ?? ""); + $new_level = trim($post_data['level'] ?? ""); + } + + if (!$exists) { + $service = new Service(); + $service->id = $serviceName; + $service->level = AuthLevel::External; + $service->token = Utils::TokenFactory(); + } else { + $service = $data->load(Service::class, $serviceName); + } + + if (!empty($new_token)) + $service->token = $new_token; + + if (!empty($new_level)) + $service->level = AuthLevel::from($new_level); + + $data->save($service); + + $result = [ + 'service' => $service->flatIdentifier(), + 'token' => $service->token, + 'level' => $service->level->value, + ]; + + if (!$exists) { + $result['result'] = 'created'; + $request->status(201, 'Created') + ->send($result); + } else { + $result['result'] = 'provisioned'; + $request->status(200, 'OK') + ->send($result); + } + } + + // System: Delete an User and all dependencies + function delete(\Gac\Routing\Request $request, string $userName) { + global $data; + + $exists = $data->exists(User::class, $userName); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $tickets = $data->fromIndex(User::class, $userName, findClass: Tickets::class); + + if (!empty($tickets)) + { + foreach ($tickets as $ticket) + { + $grants = $data->fromIndex(Ticket::class, $ticket->flatIdentifier(), findClass: Grant::class); + + $data->delete(Ticket::class, $ticket->flatIdentifier()); + + foreach ($grants as $grant) + $data->delete(Grant::class, $grant->flatIdentifier()); + } + } + + $data->delete(User::class, $userName); + $request->status(200, 'OK')->send([ 'result' => 'destroyed' ]); + } + } + + // System: Fetch info about an User + function info(\Gac\Routing\Request $request, string $userName) { + global $data; + + $exists = $data->exists(User::class, $userName); + + if (!$exists) { + $request->status(404, 'Not Found')->send(["error" => ["message" => "not found"]]); + } + else { + $user = $data->load(User::class, $userName); + + $groups = []; + + if (isset($user->groups) && $user->groups != null) + { + foreach ($user->groups as $group) + $groups[] = $group->flatIdentifier(); + } + + $result = [ + 'user' => $user->flatIdentifier(), + 'cert' => $user->cert, + 'serial' => $user->serial, + 'create' => $user->create, + 'expire' => $user->expire, + 'groups' => $groups, + 'result' => 'ok' + ]; + + $request->status(200, 'OK')->send($result); + } + } + + // System: List all Users + function list(\Gac\Routing\Request $request) { + global $data; + + $users = $data->listAll(User::class); + + $result = [ + 'users' => $users, + 'result' => 'ok' + ]; + + $request->status(200, 'OK') + ->send($result); + } + + // Default response if no action is defined + function response(\Gac\Routing\Request $request) { + $request->status(200, 'OK')->send([ 'result' => 'ok' ]); + } + +} \ No newline at end of file diff --git a/src/Tor/Data/AuthLevel.php b/src/Tor/Data/AuthLevel.php new file mode 100644 index 0000000..f1d4a9c --- /dev/null +++ b/src/Tor/Data/AuthLevel.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/Tor/Data/Decision.php b/src/Tor/Data/Decision.php new file mode 100644 index 0000000..807a839 --- /dev/null +++ b/src/Tor/Data/Decision.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/Tor/Data/Ticket.php b/src/Tor/Data/Ticket.php index 1e10a93..337d646 100644 --- a/src/Tor/Data/Ticket.php +++ b/src/Tor/Data/Ticket.php @@ -2,6 +2,9 @@ namespace Tor\Data; +use Tor\Data\Grant; +use Tor\Data\User; + class Ticket extends BaseEntity { public Grant $grant; public User $user; diff --git a/src/Tor/Data/User.php b/src/Tor/Data/User.php index c9e6aa4..ffaf580 100644 --- a/src/Tor/Data/User.php +++ b/src/Tor/Data/User.php @@ -5,4 +5,10 @@ namespace Tor\Data; class User extends BaseEntity { public string $serial; public string $cert; + public int $create; + public int $expire; + /** + * @type Tor\Data\Group + */ + public array $groups = []; } diff --git a/templates/base.html.twig b/templates/base.html.twig index 3b07e30..160bdb3 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -46,4 +46,4 @@ - \ No newline at end of file + diff --git a/templates/consent.html.twig b/templates/consent.html.twig index ba3ddcf..08769ce 100644 --- a/templates/consent.html.twig +++ b/templates/consent.html.twig @@ -4,14 +4,8 @@
A service has requested access to your Identity




+ +
Please verify before continuing.