Skip to content

Commit e885cd3

Browse files
committed
SS14VerifiedEndpoint
1 parent 714e34b commit e885cd3

6 files changed

Lines changed: 184 additions & 67 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace VerifierServer\Endpoints;
4+
5+
use React\Http\Message\Response;
6+
use Psr\Http\Message\ServerRequestInterface;
7+
use VerifierServer\SS14PersistentState;
8+
9+
/**
10+
* Class SS14VerifiedEndpoint
11+
*
12+
* This class is responsible for handling the verification process for the VerifierServer.
13+
* It implements the EndpointInterface and provides methods to handle HTTP GET, POST, and DELETE requests.
14+
*
15+
* Key Responsibilities:
16+
* - Handles GET requests to retrieve the list of verified users in JSON format.
17+
* - Handles POST requests to add a new verification entry or DELETE requests to remove an existing entry.
18+
* - Validates authorization tokens to ensure secure access to the endpoint.
19+
* - Manages the persistent state of the verification list by reading from and writing to a JSON file.
20+
*
21+
* Methods:
22+
* - __construct: Initializes the VerifiedEndpoint with a reference to the PersistentState object.
23+
* - handle: Routes incoming HTTP requests to the appropriate handler based on the HTTP method.
24+
* - get: Handles GET requests to retrieve the verification list.
25+
* - post: Handles POST requests to modify the verification list.
26+
* - __post: Adds a new entry to the verification list if its fields/columns are unique.
27+
* - delete: Handles DELETE request to remove an existing entry from the verification list.
28+
*
29+
* Authorization:
30+
* - The class checks the provided token against the expected token stored in the PersistentState.
31+
* - If the token is invalid, the response is set to 401 Unauthorized.
32+
* - If the token is valid, the requested action is performed.
33+
*
34+
* Error Handling:
35+
* - Returns 401 Unauthorized if the provided token does not match the expected token.
36+
* - Returns 403 Forbidden if a duplicate entry is detected during a POST request.
37+
* - Returns 404 Not Found if an entry to be deleted does not exist.
38+
* - Returns 405 Method Not Allowed for unsupported HTTP methods.
39+
*
40+
* Response Structure:
41+
* - Sets appropriate HTTP status codes.
42+
* - Sets the Content-Type header based on the response type (e.g., application/json, text/plain).
43+
* - Encodes the response body as JSON for successful requests or as plain text for error responses.
44+
*
45+
* @property SS14PersistentState $state
46+
* @package VerifierServer\Endpoints
47+
*/
48+
class SS14VerifiedEndpoint extends VerifiedEndpoint
49+
{
50+
public function __construct(protected &$state)
51+
{}
52+
53+
/**
54+
* Handles POST requests by parsing the request data and performing actions based on the method type.
55+
*
56+
* @param ServerRequestInterface|string $request The raw HTTP request string.
57+
* @param string &$response The response string to be modified based on the request handling.
58+
* @param array &$headers The variable to store the headers of the response.
59+
* @param string &$body The variable to store the body of the response.
60+
*
61+
* The function performs the following steps:
62+
* 1. Extracts the raw data from the request.
63+
* 2. Parses the raw data into an associative array.
64+
* 3. Retrieves the method type, ss14, discord, and token from the parsed data.
65+
* 4. Checks if the provided token matches the expected token. If not, sets the response to 401 Unauthorized.
66+
* 5. Retrieves the verification list from the state.
67+
* 6. Based on the method type, either deletes an entry from the list or handles the default case.
68+
*/
69+
protected function post(ServerRequestInterface|string $request, int|string &$response, array &$headers, string &$body, bool $bypass_token = false): void
70+
{
71+
$formData = $request instanceof ServerRequestInterface
72+
? $request->getHeaders()
73+
: (is_string($request)
74+
? self::parseHeaders($request)
75+
: []);
76+
77+
$methodType = isset($formData['method'])
78+
? strtolower(trim(is_array($formData['method']) ? $formData['method'][0] : $formData['method']))
79+
: null;
80+
$discord = isset($formData['discord'])
81+
? trim(is_array($formData['discord']) ? $formData['discord'][0] : $formData['discord'])
82+
: '';
83+
$ss14 = isset($formData['ss14'])
84+
? trim(is_array($formData['ss14']) ? $formData['ss14'][0] : $formData['ss14'])
85+
: '';
86+
$token = isset($formData['token'])
87+
? trim(is_array($formData['token']) ? $formData['token'][0] : $formData['token'])
88+
: '';
89+
90+
if (!$bypass_token && ($this->state->getToken() === 'changeme' || $token !== $this->state->getToken())) {
91+
$response = Response::STATUS_UNAUTHORIZED;
92+
$headers = ['Content-Type' => 'text/plain'];
93+
$body = 'Unauthorized';
94+
return;
95+
}
96+
97+
$list = $this->state->getVerifyList();
98+
99+
switch ($methodType) {
100+
case 'delete':
101+
$existingIndex = array_search($ss14, array_column($list, 'ss14'));
102+
if ($existingIndex === false) $existingIndex = array_search($discord, array_column($list, 'discord'));
103+
$this->delete(
104+
$existingIndex,
105+
$list,
106+
$response,
107+
$headers,
108+
$body
109+
);
110+
break;
111+
default:
112+
$this->__post(
113+
$list,
114+
$ss14,
115+
$discord,
116+
$response,
117+
$headers,
118+
$body
119+
);
120+
break;
121+
}
122+
}
123+
124+
/**
125+
* Handles the default verification process.
126+
*
127+
* This method checks if the provided `ss14` or `discord` already exists in the list.
128+
* If either exists, it sets the response to a 403 Forbidden status.
129+
* If neither exists, it adds the new entry to the list, writes the updated list to a JSON file,
130+
* updates the state, and sets the response to a 200 OK status.
131+
*
132+
* @param array $list The list of existing entries.
133+
* @param string $ss14 The ss14 to be verified.
134+
* @param string $discord The discord identifier to be verified.
135+
* @param string &$response The response message to be set based on the verification result.
136+
* @param array &$headers The variable to store the headers of the response.
137+
* @param string &$body The variable to store the body of the response.
138+
*/
139+
protected function __post(array &$list, string $ss14, string $discord, int|string &$response, array &$headers, string &$body): void
140+
{
141+
$existingDiscordIndex = array_search($discord, array_column($list, 'discord'));
142+
$existingSS14Index = array_search($ss14, array_column($list, 'ss14'));
143+
if ($existingDiscordIndex !== false || $existingSS14Index !== false) {
144+
$response = Response::STATUS_FORBIDDEN;
145+
$headers = ['Content-Type' => 'text/plain'];
146+
$body = 'Forbidden';
147+
return;
148+
}
149+
150+
$list[] = [
151+
'discord' => $discord,
152+
'ss14' => $ss14,
153+
'create_time' => date('Y-m-d H:i:s')
154+
];
155+
$this->state::writeJson($this->state->getJsonPath(), $list);
156+
$this->state->setVerifyList($list);
157+
$headers = ['Content-Type' => 'application/json'];
158+
$headers['Content-Length'] = ($body = $this->__content())
159+
? strlen($body)
160+
: 0;
161+
}
162+
}

src/VerifierServer/Endpoints/VerifiedEndpoint.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@
4343
* - Sets the Content-Type header based on the response type (e.g., application/json, text/plain).
4444
* - Encodes the response body as JSON for successful requests or as plain text for error responses.
4545
*
46+
* @property PersistentState $state
4647
* @package VerifierServer\Endpoints
4748
*/
4849
class VerifiedEndpoint extends Endpoint
4950
{
50-
public function __construct(private PersistentState &$state)
51+
public function __construct(protected &$state)
5152
{}
5253

5354
/**
@@ -105,20 +106,19 @@ public function handle(
105106
protected function get(int|string &$response, array &$headers, string &$body): void
106107
{
107108
$response = Response::STATUS_OK;
108-
$headers = ['Content-Type' => 'application/json'];
109-
$headers['Content-Length'] = ($body = $this->__content())
110-
? strlen($body)
111-
: 0;
109+
$headers['Content-Type'] = 'application/json';
110+
$body = $this->__content();
111+
$headers['Content-Length'] = $body ? strlen($body) : 0;
112112
}
113113

114114
/**
115115
* Encodes the verification list retrieved from the state into a JSON string.
116116
*
117117
* @return string|false Returns the JSON-encoded string on success, or false on failure.
118118
*/
119-
protected function __content(): string|false
119+
protected function __content(): string
120120
{
121-
return json_encode($this->state->getVerifyList());
121+
return json_encode($this->state->getVerifyList()) ?: '';
122122
}
123123

124124
/**
@@ -211,13 +211,13 @@ protected function __post(array &$list, string $ckey, string $discord, int|strin
211211
{
212212
$existingCkeyIndex = array_search($ckey, array_column($list, 'ss13'));
213213
$existingDiscordIndex = array_search($discord, array_column($list, 'discord'));
214-
215214
if ($existingCkeyIndex !== false || $existingDiscordIndex !== false) {
216215
$response = Response::STATUS_FORBIDDEN;
217216
$headers = ['Content-Type' => 'text/plain'];
218217
$body = 'Forbidden';
219218
return;
220219
}
220+
221221
$list[] = [
222222
'ss13' => $ckey,
223223
'discord' => $discord,

src/VerifierServer/OAuth2Authenticator.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ public function login(
136136
$response = Response::STATUS_FOUND;
137137
$headers = ['Location' => "{$this->endpoint_name}/{$this->allowed_uri[0]}?login"];
138138
$body = '';
139-
var_dump($headers);
140139
return;
141140
}
142141

src/VerifierServer/PersistentState.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,11 @@ public function getVerifyList(bool $getLocalCache = false): array
116116
}
117117
$stmt = $this->pdo->query("SELECT * FROM {$this->table_name}");
118118
if ($stmt === false) {
119-
$errorInfo = $this->pdo->errorInfo();
120-
throw new PDOException("Failed to execute query: " . implode(", ", $errorInfo));
119+
throw new PDOException("Failed to execute query: " . implode(", ", $this->pdo->errorInfo()));
121120
}
122121
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
123122
if ($result === false) {
124-
$errorInfo = $this->pdo->errorInfo();
125-
throw new PDOException("Failed to fetch data: " . implode(", ", $errorInfo));
123+
throw new PDOException("Failed to fetch data: " . implode(", ", $this->pdo->errorInfo()));
126124
}
127125
return $this->verifyList = $result;
128126
}
@@ -249,4 +247,13 @@ public function __wakeup(): void
249247
$this->initializeDatabase();
250248
}
251249
}
250+
251+
public function __debugInfo()
252+
{
253+
return [
254+
'storageType' => $this->storageType,
255+
'json_path' => $this->json_path,
256+
'verifyList' => $this->verifyList ?? [],
257+
];
258+
}
252259
}

src/VerifierServer/SS14PersistentState.php

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -132,56 +132,4 @@ public function setVerifyList(array $list, bool $write = true): void
132132
}
133133
$this->verifyList = $list;
134134
}
135-
136-
/**
137-
* Loads environment configuration from a .env file.
138-
* If the .env file does not exist, it creates one with default values.
139-
*
140-
* @return array The environment configuration as an associative array.
141-
* @throws Exception If the TOKEN is 'changeme' and the HOST_ADDR is not '127.0.0.1'.
142-
*
143-
* After loading the .env file, it checks if the TOKEN is 'changeme' and the HOST_ADDR is not '127.0.0.1'.
144-
* If this condition is met, the script terminates with an error message.
145-
*/
146-
public static function loadEnvConfig(): array
147-
{
148-
if (! file_exists(".env")) {
149-
file_put_contents(".env",
150-
"HOST_ADDR=127.0.0.1" . PHP_EOL .
151-
"HOST_PORT=8080" . PHP_EOL .
152-
"TOKEN=changeme" . PHP_EOL .
153-
"STORAGE_TYPE=filesystem" . PHP_EOL .
154-
"JSON_PATH=json/ss14verify.json" . PHP_EOL .
155-
"# SQLite configuration" . PHP_EOL .
156-
"#DB_DSN=sqlite:verify.db" . PHP_EOL .
157-
"#DB_USERNAME=" . PHP_EOL .
158-
"#DB_PASSWORD=" . PHP_EOL .
159-
"#DB_OPTIONS=" . PHP_EOL .
160-
"# MySQL configuration" . PHP_EOL .
161-
"DB_DSN=mysql:host=127.0.0.1;port=3306;dbname=ss14_verify_list" . PHP_EOL .
162-
"DB_PORT=3306" . PHP_EOL .
163-
"DB_USERNAME=your_username" . PHP_EOL .
164-
"DB_PASSWORD=your_password" . PHP_EOL .
165-
"#DB_OPTIONS={\"option1\":\"value1\",\"option2\":\"value2\"}"
166-
);
167-
}
168-
169-
$dotenv = Dotenv::createImmutable(__DIR__ . '\\..\\..\\');
170-
$dotenv->load();
171-
172-
$env = $_ENV;
173-
if ($env['TOKEN'] === 'changeme' && $env['HOST_ADDR'] !== '127.0.0.1') {
174-
die("Cannot use default token with non-localhost address! ");
175-
}
176-
return [
177-
'HOST_ADDR' => $env['HOST_ADDR'],
178-
'HOST_PORT' => $env['HOST_PORT'],
179-
'TOKEN' => $env['TOKEN'],
180-
'DB_DSN' => $env['DB_DSN'],
181-
'DB_PORT' => $env['DB_PORT'],
182-
'DB_USERNAME' => $env['DB_USERNAME'],
183-
'DB_PASSWORD' => $env['DB_PASSWORD'],
184-
'DB_OPTIONS' => $env['DB_OPTIONS'] ?? ''
185-
];
186-
}
187135
}

src/VerifierServer/Server.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use VerifierServer\Endpoints\Interfaces\EndpointInterface;
2020
//use VerifierServer\Endpoints\USPSEndpoint;
2121
use VerifierServer\Endpoints\VerifiedEndpoint;
22+
use VerifierServer\Endpoints\SS14VerifiedEndpoint;
2223
use VerifierServer\Traits\HttpMethodsTrait;
2324

2425
use Exception;
@@ -346,7 +347,7 @@ private function handleReact(ServerRequestInterface $request): ResponseInterface
346347
private function handleResource($client): null
347348
{
348349
$request = fread($client, 1024);
349-
var_dump($request);
350+
//var_dump($request);
350351
if ($request === false) {
351352
throw new Exception("Failed to read from client");
352353
}
@@ -574,7 +575,7 @@ private function __setVerifiedEndpoint(PersistentState &$state): void
574575
}
575576
private function __setSS14VerifiedEndpoint(PersistentState &$state): void
576577
{
577-
//$this->endpoints['/ss14verified'] = new VerifiedEndpoint($state);
578+
$this->endpoints['/ss14verified'] = new SS14VerifiedEndpoint($state);
578579
}
579580

580581
public function setSS14OAuth2Endpoint(

0 commit comments

Comments
 (0)