using System;
using System.Reactive.Linq;
using Octokit.Reactive;
namespace Octokit
{
public static class AuthorizationExtensions
{
///
/// This method will create a new authorization for the specified OAuth application, only if an authorization
/// for that application doesn’t already exist for the user. It returns the user’s token for the application
/// if one exists. Otherwise, it creates a new one.
///
///
///
/// This method allows the caller to provide a callback which is used to retrieve the two-factor code from
/// the user. Typically the callback is used to show some user interface to the user.
///
///
/// See API documentation
/// for more details.
///
///
/// The this method extends
/// Client ID for the OAuth application that is requesting the token
/// The client secret
/// Defines the scopes and metadata for the token
/// Callback used to retrieve the two-factor authentication code
/// from the user
///
public static IObservable GetOrCreateApplicationAuthentication(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
Func> twoFactorChallengeHandler)
{
Ensure.ArgumentNotNull(authorizationsClient, "authorizationsClient");
Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
Ensure.ArgumentNotNull(newAuthorization, "newAuthorization");
return authorizationsClient.GetOrCreateApplicationAuthentication(clientId, clientSecret, newAuthorization)
.Catch(exception => twoFactorChallengeHandler(exception)
.SelectMany(result =>
result.ResendCodeRequested
? authorizationsClient.GetOrCreateApplicationAuthentication(
clientId,
clientSecret,
newAuthorization,
twoFactorChallengeHandler)
: authorizationsClient.GetOrCreateApplicationAuthentication(clientId,
clientSecret,
newAuthorization,
result.AuthenticationCode)));
}
///
/// This method will create a new authorization for the specified OAuth application. If an authorization
/// for that application already exists for the user and fingerprint, it'll delete the existing one and
/// recreate it.
///
///
///
/// This method is typically used to initiate an application authentication flow.
/// This method allows the caller to provide a callback which is used to retrieve the two-factor code from
/// the user. Typically the callback is used to show some user interface to the user.
///
///
/// See API documentation
/// for more details.
///
///
/// The this method extends
/// Client ID for the OAuth application that is requesting the token
/// The client secret
/// Defines the scopes and metadata for the token
/// Callback used to retrieve the two-factor authentication code
/// from the user
/// If true, instead of completing when the two factor code supplied
/// is invalid, we go through the whole cycle again and prompt the two factor dialog.
///
public static IObservable CreateAndDeleteExistingApplicationAuthorization(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
Func> twoFactorChallengeHandler,
bool retryInvalidTwoFactorCode)
{
return authorizationsClient.CreateAndDeleteExistingApplicationAuthorization(
clientId,
clientSecret,
newAuthorization,
twoFactorChallengeHandler,
null,
retryInvalidTwoFactorCode);
}
public static IObservable CreateAndDeleteExistingApplicationAuthorization(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
Func> twoFactorChallengeHandler,
string twoFactorAuthenticationCode,
bool retryInvalidTwoFactorCode)
{
Ensure.ArgumentNotNull(authorizationsClient, "authorizationsClient");
Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
Ensure.ArgumentNotNull(newAuthorization, "newAuthorization");
// If retryInvalidTwoFactorCode is false, then we only show the TwoFactorDialog when we catch
// a TwoFactorRequiredException. If it's true, we show it for TwoFactorRequiredException and
// TwoFactorChallengeFailedException
Func> twoFactorHandler = ex =>
retryInvalidTwoFactorCode || ex is TwoFactorRequiredException
? twoFactorChallengeHandler(ex)
: Observable.Throw(ex);
return authorizationsClient.CreateAuthorizationAndDeleteExisting(
clientId,
clientSecret,
newAuthorization,
twoFactorAuthenticationCode)
.Catch(
exception => twoFactorHandler(exception)
.SelectMany(result =>
result.ResendCodeRequested
? authorizationsClient.CreateAndDeleteExistingApplicationAuthorization(
clientId,
clientSecret,
newAuthorization,
twoFactorHandler,
null, // twoFactorAuthenticationCode
retryInvalidTwoFactorCode)
: authorizationsClient.CreateAndDeleteExistingApplicationAuthorization(
clientId,
clientSecret,
newAuthorization,
twoFactorHandler,
result.AuthenticationCode,
retryInvalidTwoFactorCode)));
}
// If the Application Authorization already exists, the result might have an empty string as the token. This is
// because GitHub.com no longer stores the token, but stores a hashed version of it. It is assumed that clients
// will store the token locally.
// The only reason to be calling GetOrCreateApplicationAuthentication is pretty much the case when you are
// logging in and thus don't have the token already. So if the token returned is an empty string, we'll go
// ahead and delete it for you and then recreate it.
static IObservable CreateAuthorizationAndDeleteExisting(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
string twoFactorAuthenticationCode = null)
{
return authorizationsClient.GetOrCreateAuthorizationUnified(
clientId,
clientSecret,
newAuthorization,
twoFactorAuthenticationCode)
.SelectMany(authorization => string.IsNullOrEmpty(authorization.Token)
? authorizationsClient.Delete(authorization.Id, twoFactorAuthenticationCode)
.SelectMany(_ =>
authorizationsClient.CreateNewAuthorization(
clientId,
clientSecret,
newAuthorization,
twoFactorAuthenticationCode))
: Observable.Return(authorization));
}
static IObservable GetOrCreateAuthorizationUnified(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
string twoFactorAuthenticationCode = null)
{
return string.IsNullOrEmpty(twoFactorAuthenticationCode)
? authorizationsClient.GetOrCreateApplicationAuthentication(clientId, clientSecret, newAuthorization)
: authorizationsClient.GetOrCreateApplicationAuthentication(clientId, clientSecret, newAuthorization, twoFactorAuthenticationCode);
}
static IObservable CreateNewAuthorization(
this IObservableAuthorizationsClient authorizationsClient,
string clientId,
string clientSecret,
NewAuthorization newAuthorization,
string twoFactorAuthenticationCode = null)
{
return string.IsNullOrEmpty(twoFactorAuthenticationCode)
? authorizationsClient.Create(clientId, clientSecret, newAuthorization)
: authorizationsClient.Create(clientId, clientSecret, newAuthorization, twoFactorAuthenticationCode);
}
}
}