mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Store OAuth tokens and more OAuth account info.
Summary: Test Plan: Reviewers: CC:
This commit is contained in:
parent
21286a723e
commit
063269a00a
7 changed files with 164 additions and 32 deletions
6
resources/sql/patches/003.more_oauth.sql
Normal file
6
resources/sql/patches/003.more_oauth.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
alter table phabricator_user.user_oauthinfo add accountURI varchar(255);
|
||||
alter table phabricator_user.user_oauthinfo add accountName varchar(255);
|
||||
alter table phabricator_user.user_oauthinfo add token varchar(255);
|
||||
alter table phabricator_user.user_oauthinfo add tokenExpires int unsigned;
|
||||
alter table phabricator_user.user_oauthinfo add tokenScope varchar(255);
|
||||
alter table phabricator_user.user_oauthinfo add tokenStatus varchar(255);
|
|
@ -21,6 +21,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
private $provider;
|
||||
private $userID;
|
||||
private $accessToken;
|
||||
private $tokenExpires;
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return false;
|
||||
|
@ -91,6 +92,13 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
if (!$token) {
|
||||
return $this->buildErrorResponse(new PhabricatorOAuthFailureView());
|
||||
}
|
||||
|
||||
if (idx($data, 'expires')) {
|
||||
$this->tokenExpires = time() + $data['expires'];
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->tokenExpires = $request->getInt('expires');
|
||||
}
|
||||
|
||||
$userinfo_uri = new PhutilURI($provider->getUserInfoURI());
|
||||
|
@ -148,6 +156,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
'<p>Link your '.$provider_name.' account to your Phabricator '.
|
||||
'account?</p>');
|
||||
$dialog->addHiddenInput('token', $token);
|
||||
$dialog->addHiddenInput('expires', $this->tokenExpires);
|
||||
$dialog->addSubmitButton('Link Accounts');
|
||||
$dialog->addCancelButton('/settings/page/'.$provider_key.'/');
|
||||
|
||||
|
@ -156,8 +165,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
|
||||
$oauth_info = new PhabricatorUserOAuthInfo();
|
||||
$oauth_info->setUserID($current_user->getID());
|
||||
$oauth_info->setOAuthProvider($provider_key);
|
||||
$oauth_info->setOAuthUID($user_id);
|
||||
$this->configureOAuthInfo($oauth_info);
|
||||
$oauth_info->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
|
@ -170,6 +178,10 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
if ($known_oauth) {
|
||||
$known_user = id(new PhabricatorUser())->load($known_oauth->getUserID());
|
||||
$session_key = $known_user->establishSession('web');
|
||||
|
||||
$this->configureOAuthInfo($known_oauth);
|
||||
$known_oauth->save();
|
||||
|
||||
$request->setCookie('phusr', $known_user->getUsername());
|
||||
$request->setCookie('phsid', $session_key);
|
||||
return id(new AphrontRedirectResponse())
|
||||
|
@ -184,31 +196,17 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
$known_email = id(new PhabricatorUser())
|
||||
->loadOneWhere('email = %s', $oauth_email);
|
||||
if ($known_email) {
|
||||
$known_oauth = id(new PhabricatorUserOAuthInfo())->loadOneWhere(
|
||||
'userID = %d AND oauthProvider = %s',
|
||||
$known_email->getID(),
|
||||
$provider->getProviderKey());
|
||||
if ($known_oauth) {
|
||||
$provider_name = $provider->getName();
|
||||
throw new Exception(
|
||||
"The email associated with the ".$provider_name." account you ".
|
||||
"just logged in with is already associated with another ".
|
||||
"Phabricator account which is, in turn, associated with a ".
|
||||
$provider_name." account different from the one you just logged ".
|
||||
"in with.");
|
||||
}
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog->setUser($current_user);
|
||||
$dialog->setTitle('Already Linked to Another Account');
|
||||
$dialog->appendChild(
|
||||
'<p>The '.$provider_name.' account you just authorized has an '.
|
||||
'email address which is already in use by another Phabricator '.
|
||||
'account. To link the accounts, log in to your Phabricator '.
|
||||
'account and then go to Settings.</p>');
|
||||
$dialog->addCancelButton('/login/');
|
||||
|
||||
$oauth_info = new PhabricatorUserOAuthInfo();
|
||||
$oauth_info->setUserID($known_email->getID());
|
||||
$oauth_info->setOAuthProvider($provider->getProviderKey());
|
||||
$oauth_info->setOAuthUID($user_id);
|
||||
$oauth_info->save();
|
||||
|
||||
$session_key = $known_email->establishSession('web');
|
||||
$request->setCookie('phusr', $known_email->getUsername());
|
||||
$request->setCookie('phsid', $session_key);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/');
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,8 +277,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
|
||||
$oauth_info = new PhabricatorUserOAuthInfo();
|
||||
$oauth_info->setUserID($user->getID());
|
||||
$oauth_info->setOAuthProvider($provider->getProviderKey());
|
||||
$oauth_info->setOAuthUID($user_id);
|
||||
$this->configureOAuthInfo($oauth_info);
|
||||
$oauth_info->save();
|
||||
|
||||
$session_key = $user->establishSession('web');
|
||||
|
@ -312,6 +309,7 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
$form = new AphrontFormView();
|
||||
$form
|
||||
->addHiddenInput('token', $token)
|
||||
->addHiddenInput('expires', $this->tokenExpires)
|
||||
->setUser($request->getUser())
|
||||
->setAction($provider->getRedirectURI())
|
||||
->appendChild(
|
||||
|
@ -410,8 +408,45 @@ class PhabricatorOAuthLoginController extends PhabricatorAuthController {
|
|||
return null;
|
||||
}
|
||||
|
||||
private function retrieveAccountURI() {
|
||||
switch ($this->provider->getProviderKey()) {
|
||||
case PhabricatorOAuthProvider::PROVIDER_FACEBOOK:
|
||||
return $this->userData['link'];
|
||||
case PhabricatorOAuthProvider::PROVIDER_GITHUB:
|
||||
$username = $this->retrieveUsernameSuggestion();
|
||||
if ($username) {
|
||||
return 'https://github.com/'.$username;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function retreiveRealNameSuggestion() {
|
||||
return $this->userData['name'];
|
||||
}
|
||||
|
||||
private function configureOAuthInfo(PhabricatorUserOAuthInfo $oauth_info) {
|
||||
$provider = $this->provider;
|
||||
|
||||
$oauth_info->setOAuthProvider($provider->getProviderKey());
|
||||
$oauth_info->setOAuthUID($this->retrieveUserID());
|
||||
$oauth_info->setAccountURI($this->retrieveAccountURI());
|
||||
$oauth_info->setAccountName($this->retrieveUserNameSuggestion());
|
||||
|
||||
$oauth_info->setToken($this->accessToken);
|
||||
$oauth_info->setTokenStatus(PhabricatorUserOAuthInfo::TOKEN_STATUS_GOOD);
|
||||
|
||||
// If we have out-of-date expiration info, just clear it out. Then replace
|
||||
// it with good info if the provider gave it to us.
|
||||
$expires = $oauth_info->getTokenExpires();
|
||||
if ($expires <= time()) {
|
||||
$expires = null;
|
||||
}
|
||||
if ($this->tokenExpires) {
|
||||
$expires = $this->tokenExpires;
|
||||
}
|
||||
$oauth_info->setTokenExpires($expires);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -348,8 +348,15 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
|
|||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel($provider_name.' ID')
|
||||
->setValue($oauth_info->getOAuthUID()));
|
||||
|
||||
->setValue($oauth_info->getOAuthUID()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel($provider_name.' Name')
|
||||
->setValue($oauth_info->getAccountName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel($provider_name.' URI')
|
||||
->setValue($oauth_info->getAccountURI()));
|
||||
|
||||
$unlink = 'Unlink '.$provider_name.' Account';
|
||||
$unlink_form = new AphrontFormView();
|
||||
|
@ -363,6 +370,45 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
|
|||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink));
|
||||
$forms['Unlink Account'] = $unlink_form;
|
||||
|
||||
$expires = $oauth_info->getTokenExpires();
|
||||
if ($expires) {
|
||||
if ($expires <= time()) {
|
||||
$expires = "Expired";
|
||||
} else {
|
||||
$expires = phabricator_format_timestamp($expires);
|
||||
}
|
||||
} else {
|
||||
$expires = 'No Information Available';
|
||||
}
|
||||
|
||||
$scope = $oauth_info->getTokenScope();
|
||||
if (!$scope) {
|
||||
$scope = 'No Information Available';
|
||||
}
|
||||
|
||||
$status = $oauth_info->getTokenStatus();
|
||||
$status = PhabricatorUserOAuthInfo::getReadableTokenStatus($status);
|
||||
|
||||
$token_form = new AphrontFormView();
|
||||
$token_form
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
'<p class="aphront-from-instructions">insert rap about tokens</p>')
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Token Status')
|
||||
->setValue($status))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Expires')
|
||||
->setValue($expires))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Scope')
|
||||
->setValue($scope));
|
||||
|
||||
$forms['Account Token Information'] = $token_form;
|
||||
}
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
|
|
|
@ -25,6 +25,7 @@ phutil_require_module('phabricator', 'view/form/control/textarea');
|
|||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenav');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
|
|
@ -18,8 +18,43 @@
|
|||
|
||||
class PhabricatorUserOAuthInfo extends PhabricatorUserDAO {
|
||||
|
||||
const TOKEN_STATUS_NONE = 'none';
|
||||
const TOKEN_STATUS_GOOD = 'good';
|
||||
const TOKEN_STATUS_FAIL = 'fail';
|
||||
const TOKEN_STATUS_EXPIRED = 'xpyr';
|
||||
|
||||
protected $userID;
|
||||
protected $oauthProvider;
|
||||
protected $oauthUID;
|
||||
|
||||
protected $accountURI;
|
||||
protected $accountName;
|
||||
|
||||
protected $token;
|
||||
protected $tokenExpires;
|
||||
protected $tokenScope;
|
||||
protected $tokenStatus;
|
||||
|
||||
public function getTokenStatus() {
|
||||
if (!$this->token) {
|
||||
return self::TOKEN_STATUS_NONE;
|
||||
}
|
||||
|
||||
if ($this->tokenExpires && $this->tokenExpires <= time()) {
|
||||
return self::TOKEN_STATUS_EXPIRED;
|
||||
}
|
||||
|
||||
return $this->tokenStatus;
|
||||
}
|
||||
|
||||
public static function getReadableTokenStatus($status) {
|
||||
static $map = array(
|
||||
self::TOKEN_STATUS_NONE => 'No Token',
|
||||
self::TOKEN_STATUS_GOOD => 'Token Good',
|
||||
self::TOKEN_STATUS_FAIL => 'Token Failed',
|
||||
self::TOKEN_STATUS_EXPIRED => 'Token Expired',
|
||||
);
|
||||
return idx($map, $status, 'Unknown');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,5 +8,7 @@
|
|||
|
||||
phutil_require_module('phabricator', 'applications/people/storage/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorUserOAuthInfo.php');
|
||||
|
|
|
@ -27,8 +27,15 @@ function phabricator_format_relative_time($duration) {
|
|||
function phabricator_format_timestamp($epoch) {
|
||||
$difference = (time() - $epoch);
|
||||
|
||||
if ($difference < 0) {
|
||||
$difference = -$difference;
|
||||
$relative = 'from now';
|
||||
} else {
|
||||
$relative = 'ago';
|
||||
}
|
||||
|
||||
if ($difference < 60 * 60 * 24) {
|
||||
return phabricator_format_relative_time($difference).' ago';
|
||||
return phabricator_format_relative_time($difference).' '.$relative;
|
||||
} else if (date('Y') == date('Y', $epoch)) {
|
||||
return date('M j, g:i A', $epoch);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue