2021-05-11 06:30:20 +00:00
< ? php
/**
* @ copyright Copyright ( C ) 2010 - 2021 , the Friendica project
*
* @ license GNU AGPL version 3 or any later version
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*
*/
namespace Friendica\Module\OAuth ;
use Friendica\Core\Logger ;
use Friendica\DI ;
use Friendica\Module\BaseApi ;
2021-06-08 06:32:24 +00:00
use Friendica\Security\OAuth ;
2021-05-11 06:30:20 +00:00
/**
2021-05-12 12:00:24 +00:00
* @ see https :// docs . joinmastodon . org / spec / oauth /
2021-05-13 11:26:56 +00:00
* @ see https :// aaronparecki . com / oauth - 2 - simplified /
2021-05-11 06:30:20 +00:00
*/
class Authorize extends BaseApi
{
2021-06-10 07:02:06 +00:00
private static $oauth_code = '' ;
2021-05-11 06:30:20 +00:00
/**
* @ param array $parameters
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function rawContent ( array $parameters = [])
{
2021-05-19 06:18:42 +00:00
$request = self :: getRequest ([
2021-06-16 19:24:44 +00:00
'force_login' => '' , // Forces the user to re-login, which is necessary for authorizing with multiple accounts from the same instance.
'response_type' => '' , // Should be set equal to "code".
'client_id' => '' , // Client ID, obtained during app registration.
2021-05-19 06:18:42 +00:00
'client_secret' => '' , // Isn't normally provided. We will use it if present.
2021-06-16 19:24:44 +00:00
'redirect_uri' => '' , // Set a URI to redirect the user to. If this parameter is set to "urn:ietf:wg:oauth:2.0:oob" then the authorization code will be shown instead. Must match one of the redirect URIs declared during app registration.
'scope' => 'read' , // List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). Must be a subset of scopes declared during app registration. If not provided, defaults to "read".
2021-05-19 06:18:42 +00:00
'state' => '' ,
]);
2021-05-13 11:26:56 +00:00
2021-05-19 06:18:42 +00:00
if ( $request [ 'response_type' ] != 'code' ) {
2021-05-13 11:26:56 +00:00
Logger :: warning ( 'Unsupported or missing response type' , [ 'request' => $_REQUEST ]);
DI :: mstdnError () -> UnprocessableEntity ( DI :: l10n () -> t ( 'Unsupported or missing response type' ));
2021-05-11 06:30:20 +00:00
}
2021-05-19 06:18:42 +00:00
if ( empty ( $request [ 'client_id' ]) || empty ( $request [ 'redirect_uri' ])) {
2021-05-13 11:26:56 +00:00
Logger :: warning ( 'Incomplete request data' , [ 'request' => $_REQUEST ]);
DI :: mstdnError () -> UnprocessableEntity ( DI :: l10n () -> t ( 'Incomplete request data' ));
}
2021-06-08 06:32:24 +00:00
$application = OAuth :: getApplication ( $request [ 'client_id' ], $request [ 'client_secret' ], $request [ 'redirect_uri' ]);
2021-05-11 06:30:20 +00:00
if ( empty ( $application )) {
2021-05-12 14:00:15 +00:00
DI :: mstdnError () -> UnprocessableEntity ();
2021-05-11 06:30:20 +00:00
}
2021-05-13 11:26:56 +00:00
// @todo Compare the application scope and requested scope
2021-05-22 15:41:25 +00:00
$redirect_request = $_REQUEST ;
unset ( $redirect_request [ 'pagename' ]);
$redirect = 'oauth/authorize?' . http_build_query ( $redirect_request );
2021-05-12 06:50:27 +00:00
2021-05-11 06:30:20 +00:00
$uid = local_user ();
if ( empty ( $uid )) {
Logger :: info ( 'Redirect to login' );
2021-05-12 12:19:15 +00:00
DI :: app () -> redirect ( 'login?return_path=' . urlencode ( $redirect ));
2021-05-11 06:30:20 +00:00
} else {
Logger :: info ( 'Already logged in user' , [ 'uid' => $uid ]);
}
2021-06-08 06:32:24 +00:00
if ( ! OAuth :: existsTokenForUser ( $application , $uid ) && ! DI :: session () -> get ( 'oauth_acknowledge' )) {
2021-05-12 06:50:27 +00:00
Logger :: info ( 'Redirect to acknowledge' );
2021-05-12 12:19:15 +00:00
DI :: app () -> redirect ( 'oauth/acknowledge?' . http_build_query ([ 'return_path' => $redirect , 'application' => $application [ 'name' ]]));
2021-05-12 06:50:27 +00:00
}
2021-05-12 06:51:59 +00:00
DI :: session () -> remove ( 'oauth_acknowledge' );
2021-06-08 06:32:24 +00:00
$token = OAuth :: createTokenForUser ( $application , $uid , $request [ 'scope' ]);
2021-05-11 06:30:20 +00:00
if ( ! $token ) {
2021-05-12 14:00:15 +00:00
DI :: mstdnError () -> UnprocessableEntity ();
2021-05-11 06:30:20 +00:00
}
2021-06-10 06:26:34 +00:00
if ( $application [ 'redirect_uri' ] != 'urn:ietf:wg:oauth:2.0:oob' ) {
DI :: app () -> redirect ( $application [ 'redirect_uri' ] . ( strpos ( $application [ 'redirect_uri' ], '?' ) ? '&' : '?' ) . http_build_query ([ 'code' => $token [ 'code' ], 'state' => $request [ 'state' ]]));
}
2021-06-10 07:02:06 +00:00
self :: $oauth_code = $token [ 'code' ];
2021-06-10 06:26:34 +00:00
}
public static function content ( array $parameters = [])
{
2021-06-10 07:02:06 +00:00
if ( empty ( self :: $oauth_code )) {
2021-06-10 06:26:34 +00:00
return '' ;
}
2021-06-10 07:02:06 +00:00
return DI :: l10n () -> t ( 'Please copy the following authentication code into your application and close this window: %s' , self :: $oauth_code );
2021-05-11 06:30:20 +00:00
}
}