-
Notifications
You must be signed in to change notification settings - Fork 0
Cleanup to remove logic from the routes and to their own class. #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ylebre
wants to merge
27
commits into
main
Choose a base branch
from
cleanup/routes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 10 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
1598bda
remove content-type header, already set by php-solid-auth
ylebre b8833d7
Move logic away from idp/index.html
ylebre 2304531
restore cleanup deps
ylebre 5bb231a
rename accounts to account
ylebre a779436
get user from session, prevent double start session
ylebre 02eb72b
typofix
ylebre 9428099
rename Api/Solid to Api/SolidIdp
ylebre 6402e29
cleanup user profile route file
ylebre c413924
cleanup user storage route file
ylebre a73bf25
rename Api to Routes
ylebre df4c12a
add throw on error
ylebre 6ac73cc
get user from logged in session
ylebre aee5981
use ??
ylebre ab524f9
whitespace fixes
ylebre d7e0f96
use in_array
ylebre 69afc36
add fixme
ylebre 354bf81
use ??
ylebre fcf2c17
more explicit comparison
ylebre 60d37e2
remove unused cookielifetime
ylebre a68e468
remove unused var, directly create it
ylebre a745b74
add fixme
ylebre 037a0bc
centralize the use of $_SERVER to easier refactor later
ylebre 799607b
typofix
ylebre 096986a
remove unused functions, they are in SolidIdp
ylebre 6c3e22c
remove usage of md5
ylebre fe2dd7c
remove usage of md5
ylebre 8a6762e
return result in case something needs to use it
ylebre File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,286 @@ | ||
<?php | ||
namespace Pdsinterop\PhpSolid\Routes; | ||
|
||
use Pdsinterop\PhpSolid\Server; | ||
use Pdsinterop\PhpSolid\ClientRegistration; | ||
use Pdsinterop\PhpSolid\User; | ||
use Pdsinterop\PhpSolid\Session; | ||
use Pdsinterop\PhpSolid\Mailer; | ||
use Pdsinterop\PhpSolid\IpAttempts; | ||
|
||
class Account { | ||
public static function requireLoggedInUser() { | ||
$user = User::getUser(Session::getLoggedInUser()); | ||
if (!$user) { | ||
switch ($_SERVER['REQUEST_METHOD']) { | ||
case "GET": | ||
header("Location: /login/?redirect_uri=" . urlencode($_SERVER['REQUEST_URI'])); | ||
exit(); | ||
break; | ||
default: | ||
header("HTTP/1.0 400 Bad Request"); | ||
exit(); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
public static function respondToDashboard() { | ||
$user = User::getUser(Session::getLoggedInUser()); | ||
echo "Logged in as " . $user['webId']; | ||
} | ||
|
||
public static function respondToLogout() { | ||
$user = User::getUser(Session::getLoggedInUser()); | ||
if ($user) { | ||
session_destroy(); | ||
} | ||
header("Location: /login/"); | ||
exit(); | ||
} | ||
|
||
public static function respondToAccountVerify() { | ||
$verifyData = [ | ||
'email' => $_POST['email'] | ||
]; | ||
|
||
$verifyToken = User::saveVerifyToken('verify', $verifyData); | ||
Mailer::sendVerify($verifyToken); | ||
|
||
$responseData = "OK"; | ||
header("HTTP/1.1 201 Created"); | ||
header("Content-type: application/json"); | ||
echo json_encode($responseData, JSON_PRETTY_PRINT); | ||
ylebre marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
|
||
public static function respondToAccountNew() { | ||
$verifyToken = User::getVerifyToken($_POST['confirm']); | ||
if (!$verifyToken) { | ||
error_log("Could not read verify token"); | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
if ($verifyToken['email'] !== $_POST['email']) { | ||
error_log("Verify token does not match email"); | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
if (User::userEmailExists($_POST['email'])) { | ||
error_log("Account already exists"); | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
if (!$_POST['password'] === $_POST['repeat_password']) { | ||
error_log("Password repeat does not match"); | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
|
||
$newUser = [ | ||
"email" => $_POST['email'], | ||
"password" => $_POST['password'] | ||
]; | ||
|
||
$createdUser = User::createUser($newUser); | ||
if (!$createdUser) { | ||
error_log("Failed to create user"); | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
Mailer::sendAccountCreated($createdUser); | ||
|
||
$responseData = array( | ||
"webId" => $createdUser['webId'] | ||
); | ||
header("HTTP/1.1 201 Created"); | ||
header("Content-type: application/json"); | ||
Session::start($_POST['email']); | ||
echo json_encode($responseData, JSON_PRETTY_PRINT); | ||
} | ||
|
||
public static function respondToAccountResetPassword() { | ||
if (!User::userEmailExists($_POST['email'])) { | ||
header("HTTP/1.1 200 OK"); // Return OK even when user is not found; | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
exit(); | ||
} | ||
$verifyData = [ | ||
'email' => $_POST['email'] | ||
]; | ||
|
||
$verifyToken = User::saveVerifyToken('passwordReset', $verifyData); | ||
Mailer::sendResetPassword($verifyToken); | ||
header("HTTP/1.1 200 OK"); | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
} | ||
|
||
public static function respondToAccountChangePassword() { | ||
$verifyToken = User::getVerifyToken($_POST['token']); | ||
if (!$verifyToken) { | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
$result = User::setUserPassword($verifyToken['email'], $_POST['newPassword']); | ||
if (!$result) { | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
header("HTTP/1.1 200 OK"); | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
} | ||
|
||
public static function respondToAccountDelete() { | ||
if (!User::userEmailExists($_POST['email'])) { | ||
header("HTTP/1.1 200 OK"); // Return OK even when user is not found; | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
exit(); | ||
} | ||
$verifyData = [ | ||
'email' => $_POST['email'] | ||
]; | ||
|
||
$verifyToken = User::saveVerifyToken('deleteAccount', $verifyData); | ||
Mailer::sendDeleteAccount($verifyToken); | ||
header("HTTP/1.1 200 OK"); | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
} | ||
|
||
public static function respondToAccountDeleteConfirm() { | ||
$verifyToken = User::getVerifyToken($_POST['token']); | ||
if (!$verifyToken) { | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
User::deleteAccount($verifyToken['email']); | ||
header("HTTP/1.1 200 OK"); | ||
header("Content-type: application/json"); | ||
echo json_encode("OK"); | ||
} | ||
|
||
public static function respondToLogin() { | ||
$failureCount = IpAttempts::getAttemptsCount($_SERVER['REMOTE_ADDR'], "login"); | ||
if ($failureCount > 5) { | ||
header("HTTP/1.1 400 Bad Request"); | ||
exit(); | ||
} | ||
if (User::checkPassword($_POST['username'], $_POST['password'])) { | ||
Session::start($_POST['username']); | ||
if (!isset($_POST['redirect_uri']) || $_POST['redirect_uri'] === '') { | ||
header("Location: /dashboard/"); | ||
exit(); | ||
} | ||
header("Location: " . urldecode($_POST['redirect_uri'])); // FIXME: Do we need to harden this? | ||
} else { | ||
IpAttempts::logFailedAttempt($_SERVER['REMOTE_ADDR'], "login", time() + 3600); | ||
header("Location: /login/"); | ||
} | ||
} | ||
|
||
public static function respondToRegister() { | ||
$postData = file_get_contents("php://input"); | ||
$clientData = json_decode($postData, true); | ||
if (!isset($clientData)) { | ||
header("HTTP/1.1 400 Bad request"); | ||
return; | ||
} | ||
$parsedOrigin = parse_url($clientData['redirect_uris'][0]); | ||
$origin = $parsedOrigin['scheme'] . '://' . $parsedOrigin['host']; | ||
if (isset($parsedOrigin['port'])) { | ||
$origin .= ":" . $parsedOrigin['port']; | ||
} | ||
|
||
|
||
$generatedClientId = md5(random_bytes(32)); | ||
$generatedClientSecret = md5(random_bytes(32)); | ||
ylebre marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
$clientData['client_id_issued_at'] = time(); | ||
$clientData['client_id'] = $generatedClientId; | ||
$clientData['client_secret'] = $generatedClientSecret; | ||
$clientData['origin'] = $origin; | ||
ClientRegistration::saveClientRegistration($clientData); | ||
|
||
$client = ClientRegistration::getRegistration($generatedClientId); | ||
|
||
$responseData = array( | ||
'redirect_uris' => $client['redirect_uris'], | ||
'client_id' => $client['client_id'], | ||
'client_secret' => $client['client_secret'], | ||
'response_types' => array('code'), | ||
'grant_types' => array('authorization_code', 'refresh_token'), | ||
'application_type' => $client['application_type'] ?? 'web', | ||
'client_name' => $client['client_name'] ?? $client['client_id'], | ||
'id_token_signed_response_alg' => 'RS256', | ||
'token_endpoint_auth_method' => 'client_secret_basic', | ||
'client_id_issued_at' => $client['client_id_issued_at'], | ||
'client_secret_expires_at' => 0 | ||
); | ||
header("HTTP/1.1 201 Created"); | ||
header("Content-type: application/json"); | ||
echo json_encode($responseData, JSON_PRETTY_PRINT); | ||
} | ||
|
||
public static function respondToSharing() { | ||
$clientId = $_POST['client_id']; | ||
$userId = $user['userId']; | ||
ylebre marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
if ($_POST['consent'] === 'true') { | ||
User::allowClientForUser($clientId, $userId); | ||
} | ||
$returnUrl = urldecode($_POST['returnUrl']); | ||
header("Location: $returnUrl"); | ||
} | ||
|
||
public static function respondToToken() { | ||
$authServer = Server::getAuthServer(); | ||
$tokenGenerator = Server::getTokenGenerator(); | ||
|
||
$requestFactory = new \Laminas\Diactoros\ServerRequestFactory(); | ||
$request = $requestFactory->fromGlobals($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES); | ||
$requestBody = $request->getParsedBody(); | ||
|
||
$grantType = isset($requestBody['grant_type']) ? $requestBody['grant_type'] : null; | ||
$clientId = isset($requestBody['client_id']) ? $requestBody['client_id'] : null; | ||
ylebre marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
switch ($grantType) { | ||
case "authorization_code": | ||
$code = $requestBody['code']; | ||
$codeInfo = $tokenGenerator->getCodeInfo($code); | ||
$userId = $codeInfo['user_id']; | ||
if (!$clientId) { | ||
$clientId = $codeInfo['client_id']; | ||
} | ||
break; | ||
case "refresh_token": | ||
$refreshToken = $requestBody['refresh_token']; | ||
$tokenInfo = $tokenGenerator->getCodeInfo($refreshToken); // FIXME: getCodeInfo should be named 'decrypt' or 'getInfo'? | ||
$userId = $tokenInfo['user_id']; | ||
if (!$clientId) { | ||
$clientId = $tokenInfo['client_id']; | ||
} | ||
break; | ||
default: | ||
$userId = false; | ||
break; | ||
} | ||
|
||
$httpDpop = $request->getServerParams()['HTTP_DPOP']; | ||
|
||
$response = $authServer->respondToAccessTokenRequest($request); | ||
|
||
if (isset($userId)) { | ||
$response = $tokenGenerator->addIdTokenToResponse( | ||
$response, | ||
$clientId, | ||
$userId, | ||
($_SESSION['nonce'] ?? ''), | ||
Server::getKeys()['privateKey'], | ||
$httpDpop | ||
); | ||
} | ||
|
||
Server::respond($response); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.