69 lines
2.4 KiB
PHP
69 lines
2.4 KiB
PHP
<?php
|
|
require __DIR__ . '/_bootstrap.php';
|
|
|
|
/**
|
|
* @OA\Post(
|
|
* path="/login.php",
|
|
* tags={"Auth"},
|
|
* summary="Log in, issue bearer token",
|
|
* security={},
|
|
* @OA\RequestBody(required=true, @OA\JsonContent(
|
|
* required={"login","password","device_name"},
|
|
* @OA\Property(property="login", type="string", description="e-mail or username"),
|
|
* @OA\Property(property="password", type="string", format="password"),
|
|
* @OA\Property(property="device_name", type="string", example="iPhone 15")
|
|
* )),
|
|
* @OA\Response(response=200, description="Success", @OA\JsonContent(
|
|
* @OA\Property(property="data", type="object",
|
|
* @OA\Property(property="token", type="string"),
|
|
* @OA\Property(property="user", ref="#/components/schemas/User")
|
|
* )
|
|
* )),
|
|
* @OA\Response(response=401, ref="#/components/responses/Unauthorized"),
|
|
* @OA\Response(response=403, description="E-mail not verified (code email_not_verified)",
|
|
* @OA\JsonContent(ref="#/components/schemas/Error")),
|
|
* @OA\Response(response=422, ref="#/components/responses/ValidationError")
|
|
* )
|
|
*/
|
|
require_method('POST');
|
|
|
|
$in = body();
|
|
$login = trim((string) ($in['login'] ?? ''));
|
|
$pass = (string) ($in['password'] ?? '');
|
|
$device = trim((string) ($in['device_name'] ?? ''));
|
|
|
|
$fields = [];
|
|
if ($login === '') { $fields['login'] = ['Required']; }
|
|
if ($pass === '') { $fields['password'] = ['Required']; }
|
|
if ($device === '') { $fields['device_name'] = ['Required']; }
|
|
if ($fields) {
|
|
json_error(422, 'Validation failed', $fields);
|
|
}
|
|
|
|
$stmt = $pdo->prepare('SELECT * FROM auth_users WHERE email = ? OR username = ? LIMIT 1');
|
|
$stmt->execute([$login, $login]);
|
|
$user = $stmt->fetch();
|
|
|
|
if (!$user || !password_verify($pass, (string) $user['password'])) {
|
|
json_error(401, 'Invalid credentials');
|
|
}
|
|
|
|
// Distinct code so the app opens the verification screen instead of blaming the password.
|
|
if (empty($user['email_verified_at'])) {
|
|
json_error(403, 'E-mail is not verified', null, 'email_not_verified');
|
|
}
|
|
|
|
$plain = bin2hex(random_bytes(32));
|
|
$config = require __DIR__ . '/config.php';
|
|
$expires = (new DateTimeImmutable("+{$config['token_ttl_days']} days"))->format('Y-m-d H:i:s');
|
|
|
|
$pdo->prepare(
|
|
'INSERT INTO api_tokens (user_id, name, token, expires_at, created_at)
|
|
VALUES (?, ?, ?, ?, NOW())'
|
|
)->execute([$user['id'], $device, hash('sha256', $plain), $expires]);
|
|
|
|
json_data([
|
|
'token' => $plain,
|
|
'user' => present_user($user),
|
|
]);
|