diff --git a/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs b/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs index a61641d11d..1188606901 100644 --- a/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs @@ -31,6 +31,43 @@ public interface IObservableAuthorizationsClient Justification = "It's fiiiine. It's fine. Trust us.")] IObservable Get(int id); + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + IObservable Create(NewAuthorization newAuthorization); + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + IObservable Create(NewAuthorization newAuthorization, string twoFactorAuthenticationCode); + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs index bbe991c1c1..514c4da9d7 100644 --- a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs @@ -45,6 +45,56 @@ public IObservable Get(int id) return _client.Get(id).ToObservable(); } + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public IObservable Create(NewAuthorization newAuthorization) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + + return _client.Create(newAuthorization).ToObservable(); + } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public IObservable Create( + NewAuthorization newAuthorization, + string twoFactorAuthenticationCode) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + Ensure.ArgumentNotNullOrEmptyString(twoFactorAuthenticationCode, "twoFactorAuthenticationCode"); + + return _client.Create(newAuthorization, twoFactorAuthenticationCode).ToObservable(); + } + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs index 5a3b741d48..5eb0655ede 100644 --- a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs @@ -7,6 +7,40 @@ namespace Octokit.Tests.Integration.Clients { public class AuthorizationClientTests { + [IntegrationTest] + public async Task CanCreatePersonalToken() + { + var github = Helper.GetBasicAuthClient(); + var note = Helper.MakeNameWithTimestamp("Testing authentication"); + var newAuthorization = new NewAuthorization( + note, + new string[] { "user" }); + + var created = await github.Authorization.Create(newAuthorization); + + Assert.False(String.IsNullOrWhiteSpace(created.Token)); + Assert.False(String.IsNullOrWhiteSpace(created.TokenLastEight)); + Assert.False(String.IsNullOrWhiteSpace(created.HashedToken)); + + var get = await github.Authorization.Get(created.Id); + + Assert.Equal(created.Id, get.Id); + Assert.Equal(created.Note, get.Note); + } + + [IntegrationTest] + public async Task CannotCreatePersonalTokenWhenUsingOauthTokenCredentials() + { + var github = Helper.GetAuthenticatedClient(); + var note = Helper.MakeNameWithTimestamp("Testing authentication"); + var newAuthorization = new NewAuthorization( + note, + new string[] { "user" }); + + var error = Assert.ThrowsAsync(() => github.Authorization.Create(newAuthorization)); + Assert.True(error.Result.Message.Contains("username and password Basic Auth")); + } + [ApplicationTest] public async Task CanCreateAndGetAuthorizationWithoutFingerPrint() { diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs index ea86d9dd89..17815e3439 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -36,6 +36,20 @@ public static class Helper return new Credentials(applicationClientId, applicationClientSecret); }); + static readonly Lazy _basicAuthCredentials = new Lazy(() => + { + var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME"); + UserName = githubUsername; + Organization = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBORGANIZATION"); + + var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBPASSWORD"); + + if (githubUsername == null || githubPassword == null) + return null; + + return new Credentials(githubUsername, githubPassword); + }); + static Helper() { // Force reading of environment variables. @@ -51,6 +65,8 @@ static Helper() public static Credentials ApplicationCredentials { get { return _oauthApplicationCredentials.Value; } } + public static Credentials BasicAuthCredentials { get { return _basicAuthCredentials.Value; } } + public static bool IsUsingToken { get @@ -118,6 +134,14 @@ public static IGitHubClient GetAuthenticatedClient() }; } + public static IGitHubClient GetBasicAuthClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = BasicAuthCredentials + }; + } + public static GitHubClient GetAuthenticatedApplicationClient() { return new GitHubClient(new ProductHeaderValue("OctokitTests")) diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index 128586537d..4860c5ae5d 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -56,6 +56,76 @@ public Task Get(int id) return ApiConnection.Get(ApiUrls.Authorizations(id), null); } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public Task Create(NewAuthorization newAuthorization) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + + var requestData = new + { + scopes = newAuthorization.Scopes, + note = newAuthorization.Note, + note_url = newAuthorization.NoteUrl, + fingerprint = newAuthorization.Fingerprint + }; + + var endpoint = ApiUrls.Authorizations(); + + return ApiConnection.Post(endpoint, requestData); + } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public Task Create( + NewAuthorization newAuthorization, + string twoFactorAuthenticationCode) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + Ensure.ArgumentNotNullOrEmptyString(twoFactorAuthenticationCode, "twoFactorAuthenticationCode"); + + var requestData = new + { + scopes = newAuthorization.Scopes, + note = newAuthorization.Note, + note_url = newAuthorization.NoteUrl, + fingerprint = newAuthorization.Fingerprint + }; + + var endpoint = ApiUrls.Authorizations(); + return ApiConnection.Post(endpoint, requestData, null, null, twoFactorAuthenticationCode); + } + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit/Clients/IAuthorizationsClient.cs b/Octokit/Clients/IAuthorizationsClient.cs index 198d3802d5..17e9baf26d 100644 --- a/Octokit/Clients/IAuthorizationsClient.cs +++ b/Octokit/Clients/IAuthorizationsClient.cs @@ -47,6 +47,43 @@ public interface IAuthorizationsClient Justification = "It's fiiiine. It's fine. Trust us.")] Task Get(int id); + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + Task Create(NewAuthorization newAuthorization); + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + Task Create(NewAuthorization newAuthorization, string twoFactorAuthenticationCode); + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails.