mirror of
https://github.com/appwrite/appwrite
synced 2026-05-24 09:28:40 +00:00
Merge pull request #9138 from appwrite/fix-installation-oauth-collision
Fix: VCS identity collision
This commit is contained in:
commit
f153e1bebf
2 changed files with 78 additions and 64 deletions
|
|
@ -5417,6 +5417,39 @@ $consoleCollections = array_merge([
|
||||||
'default' => false,
|
'default' => false,
|
||||||
'array' => false,
|
'array' => false,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('personalAccessToken'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 256,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => ['encrypt'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('personalAccessTokenExpiry'),
|
||||||
|
'type' => Database::VAR_DATETIME,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 0,
|
||||||
|
'signed' => false,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => ['datetime'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('personalRefreshToken'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 256,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => ['encrypt'],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'indexes' => [
|
'indexes' => [
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -355,53 +355,6 @@ App::get('/v1/vcs/github/callback')
|
||||||
throw new Exception(Exception::PROJECT_NOT_FOUND, $error);
|
throw new Exception(Exception::PROJECT_NOT_FOUND, $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
$personalSlug = '';
|
|
||||||
|
|
||||||
// OAuth Authroization
|
|
||||||
if (!empty($code)) {
|
|
||||||
$oauth2 = new OAuth2Github(System::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), System::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), "");
|
|
||||||
$accessToken = $oauth2->getAccessToken($code) ?? '';
|
|
||||||
$refreshToken = $oauth2->getRefreshToken($code) ?? '';
|
|
||||||
$accessTokenExpiry = $oauth2->getAccessTokenExpiry($code) ?? '';
|
|
||||||
$personalSlug = $oauth2->getUserSlug($accessToken) ?? '';
|
|
||||||
$email = $oauth2->getUserEmail($accessToken);
|
|
||||||
$oauth2ID = $oauth2->getUserID($accessToken);
|
|
||||||
|
|
||||||
// Makes sure this email is not already used in another identity
|
|
||||||
$identity = $dbForPlatform->findOne('identities', [
|
|
||||||
Query::equal('providerEmail', [$email]),
|
|
||||||
]);
|
|
||||||
if (!$identity->isEmpty()) {
|
|
||||||
if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) {
|
|
||||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
$identity = $identity
|
|
||||||
->setAttribute('providerAccessToken', $accessToken)
|
|
||||||
->setAttribute('providerRefreshToken', $refreshToken)
|
|
||||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry));
|
|
||||||
|
|
||||||
$dbForPlatform->updateDocument('identities', $identity->getId(), $identity);
|
|
||||||
} else {
|
|
||||||
$identity = $dbForPlatform->createDocument('identities', new Document([
|
|
||||||
'$id' => ID::unique(),
|
|
||||||
'$permissions' => [
|
|
||||||
Permission::read(Role::any()),
|
|
||||||
Permission::update(Role::user($user->getId())),
|
|
||||||
Permission::delete(Role::user($user->getId())),
|
|
||||||
],
|
|
||||||
'userInternalId' => $user->getInternalId(),
|
|
||||||
'userId' => $user->getId(),
|
|
||||||
'provider' => 'github',
|
|
||||||
'providerUid' => $oauth2ID,
|
|
||||||
'providerEmail' => $email,
|
|
||||||
'providerAccessToken' => $accessToken,
|
|
||||||
'providerRefreshToken' => $refreshToken,
|
|
||||||
'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create / Update installation
|
// Create / Update installation
|
||||||
if (!empty($providerInstallationId)) {
|
if (!empty($providerInstallationId)) {
|
||||||
$privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
$privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
||||||
|
|
@ -416,6 +369,22 @@ App::get('/v1/vcs/github/callback')
|
||||||
Query::equal('projectInternalId', [$projectInternalId])
|
Query::equal('projectInternalId', [$projectInternalId])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$personal = false;
|
||||||
|
$refreshToken = null;
|
||||||
|
$accessToken = null;
|
||||||
|
$accessTokenExpiry = null;
|
||||||
|
|
||||||
|
if (!empty($code)) {
|
||||||
|
$oauth2 = new OAuth2Github(System::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), System::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), "");
|
||||||
|
|
||||||
|
$accessToken = $oauth2->getAccessToken($code) ?? '';
|
||||||
|
$refreshToken = $oauth2->getRefreshToken($code) ?? '';
|
||||||
|
$accessTokenExpiry = DateTime::addSeconds(new \DateTime(), \intval($oauth2->getAccessTokenExpiry($code)));
|
||||||
|
|
||||||
|
$personalSlug = $oauth2->getUserSlug($accessToken) ?? '';
|
||||||
|
$personal = $personalSlug === $owner;
|
||||||
|
}
|
||||||
|
|
||||||
if ($installation->isEmpty()) {
|
if ($installation->isEmpty()) {
|
||||||
$teamId = $project->getAttribute('teamId', '');
|
$teamId = $project->getAttribute('teamId', '');
|
||||||
|
|
||||||
|
|
@ -433,14 +402,20 @@ App::get('/v1/vcs/github/callback')
|
||||||
'projectInternalId' => $projectInternalId,
|
'projectInternalId' => $projectInternalId,
|
||||||
'provider' => 'github',
|
'provider' => 'github',
|
||||||
'organization' => $owner,
|
'organization' => $owner,
|
||||||
'personal' => $personalSlug === $owner
|
'personal' => $personal,
|
||||||
|
'personalRefreshToken' => $refreshToken,
|
||||||
|
'personalAccessToken' => $accessToken,
|
||||||
|
'personalAccessTokenExpiry' => $accessTokenExpiry,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$installation = $dbForPlatform->createDocument('installations', $installation);
|
$installation = $dbForPlatform->createDocument('installations', $installation);
|
||||||
} else {
|
} else {
|
||||||
$installation = $installation
|
$installation = $installation
|
||||||
->setAttribute('organization', $owner)
|
->setAttribute('organization', $owner)
|
||||||
->setAttribute('personal', $personalSlug === $owner);
|
->setAttribute('personal', $personal)
|
||||||
|
->setAttribute('personalRefreshToken', $refreshToken)
|
||||||
|
->setAttribute('personalAccessToken', $accessToken)
|
||||||
|
->setAttribute('personalAccessTokenExpiry', $accessTokenExpiry);
|
||||||
$installation = $dbForPlatform->updateDocument('installations', $installation->getId(), $installation);
|
$installation = $dbForPlatform->updateDocument('installations', $installation->getId(), $installation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -720,17 +695,23 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||||
if ($installation->getAttribute('personal', false) === true) {
|
if ($installation->getAttribute('personal', false) === true) {
|
||||||
$oauth2 = new OAuth2Github(System::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), System::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), "");
|
$oauth2 = new OAuth2Github(System::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''), System::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''), "");
|
||||||
|
|
||||||
$identity = $dbForPlatform->findOne('identities', [
|
$accessToken = $installation->getAttribute('personalAccessToken');
|
||||||
Query::equal('provider', ['github']),
|
$refreshToken = $installation->getAttribute('personalRefreshToken');
|
||||||
Query::equal('userInternalId', [$user->getInternalId()]),
|
$accessTokenExpiry = $installation->getAttribute('personalAccessTokenExpiry');
|
||||||
]);
|
|
||||||
if ($identity->isEmpty()) {
|
|
||||||
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
$accessToken = $identity->getAttribute('providerAccessToken');
|
if (empty($accessToken) || empty($refreshToken) || empty($accessTokenExpiry)) {
|
||||||
$refreshToken = $identity->getAttribute('providerRefreshToken');
|
$identity = $dbForPlatform->findOne('identities', [
|
||||||
$accessTokenExpiry = $identity->getAttribute('providerAccessTokenExpiry');
|
Query::equal('provider', ['github']),
|
||||||
|
Query::equal('userInternalId', [$user->getInternalId()]),
|
||||||
|
]);
|
||||||
|
if ($identity->isEmpty()) {
|
||||||
|
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$accessToken = $accessToken ?? $identity->getAttribute('providerAccessToken');
|
||||||
|
$refreshToken = $refreshToken ?? $identity->getAttribute('providerRefreshToken');
|
||||||
|
$accessTokenExpiry = $accessTokenExpiry ?? $identity->getAttribute('providerAccessTokenExpiry');
|
||||||
|
}
|
||||||
|
|
||||||
$isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now');
|
$isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now');
|
||||||
if ($isExpired) {
|
if ($isExpired) {
|
||||||
|
|
@ -745,12 +726,12 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||||
throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, "Another request is currently refreshing OAuth token. Please try again.");
|
throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED, "Another request is currently refreshing OAuth token. Please try again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$identity = $identity
|
$installation = $installation
|
||||||
->setAttribute('providerAccessToken', $accessToken)
|
->setAttribute('personalAccessToken', $accessToken)
|
||||||
->setAttribute('providerRefreshToken', $refreshToken)
|
->setAttribute('personalRefreshToken', $refreshToken)
|
||||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry('')));
|
->setAttribute('personalAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry('')));
|
||||||
|
|
||||||
$dbForPlatform->updateDocument('identities', $identity->getId(), $identity);
|
$dbForPlatform->updateDocument('installations', $installation->getId(), $installation);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue