Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
26fa50c
Functionality to swith to authentication view on api failure
StanleyGoldman Sep 11, 2017
90d1f0c
Adding an additional exception
StanleyGoldman Sep 11, 2017
553977c
Throwing an exception when the cached username does not match the one…
StanleyGoldman Oct 11, 2017
7568a55
Validating the user and throwing custom exceptions
StanleyGoldman Oct 12, 2017
0d00e78
Merge branch 'master' into fixes/api-failure-switch-auth-view
StanleyGoldman Oct 12, 2017
2612883
Merge branch 'fixes/proper-authorization-checks' into fixes/api-failu…
StanleyGoldman Oct 12, 2017
682fb99
Using custom exceptions and popping up dialog to proceed or switch ac…
StanleyGoldman Oct 12, 2017
b0cc696
Initial routine in PopupWindow to handle authentication before presen…
StanleyGoldman Oct 12, 2017
b084541
Attempting to fix the close operation
StanleyGoldman Oct 12, 2017
e9f7f09
Attempting to close properly after publish
StanleyGoldman Oct 12, 2017
79507a3
Controlling the close action with a flag
StanleyGoldman Oct 13, 2017
380ede9
Displaying a message on the Authentication window and setting the cac…
StanleyGoldman Oct 13, 2017
1c46709
Merge branch 'fixes/long-publish-error-message' into fixes/api-failur…
StanleyGoldman Oct 13, 2017
3e4e699
Merge branch 'fixes/long-publish-error-message' into fixes/api-failur…
StanleyGoldman Oct 13, 2017
5aa8092
Clearing the message at the right time
StanleyGoldman Oct 13, 2017
df68478
Merge branch 'fixes/long-publish-error-message' into fixes/api-failur…
StanleyGoldman Oct 16, 2017
494f552
Bring back auth header styles
donokuda Oct 17, 2017
3ce244a
Merge branch 'fixes/long-publish-error-message' into fixes/api-failur…
StanleyGoldman Oct 19, 2017
23498ce
Turning messages into constants; Changing account refresh message
StanleyGoldman Oct 19, 2017
c03a55d
Merge branch 'master' into fixes/api-failure-switch-auth-view
StanleyGoldman Oct 19, 2017
e00c98c
Returning the exception message
StanleyGoldman Oct 19, 2017
97273c4
Merge master into fixes/api-failure-switch-auth-view
Oct 23, 2017
a2859d1
Merge master into fixes/api-failure-switch-auth-view
Oct 23, 2017
85969ad
Preventing the exposure of Octokit objects to the codebase
StanleyGoldman Oct 23, 2017
6482545
:fire: extra cruft from auth view
donokuda Oct 26, 2017
58b48aa
Use a HelpBox instead
donokuda Oct 26, 2017
20e137a
Adjust some spacing
donokuda Oct 26, 2017
8b260dd
Remove unneeded spacing
donokuda Oct 27, 2017
cafb7e7
Merge pull request #386 from github-for-unity/fixes/api-client-octoki…
shana Nov 2, 2017
58cb052
AuthenticationView can handle its own message logic
shana Nov 2, 2017
3709d52
Resetting the UI when going back or finishing
shana Nov 2, 2017
209de48
Merge pull request #400 from github-for-unity/fixes/auth-view-cleanup
StanleyGoldman Nov 2, 2017
788118b
Merge branch 'master' into fixes/api-failure-switch-auth-view
StanleyGoldman Nov 2, 2017
474dcc7
Changing the title content when the view changes
StanleyGoldman Nov 2, 2017
16031fe
Firing OnEnable when we switch the ActiveView
StanleyGoldman Nov 2, 2017
d0c6426
Calling Redraw when we switch the ActiveView
StanleyGoldman Nov 2, 2017
8c6cdfa
Redraw after organizations are loaded
StanleyGoldman Nov 2, 2017
b108e06
Changing the log output for KeychainEmptyException
StanleyGoldman Nov 2, 2017
5e87e9a
Removing unused code
StanleyGoldman Nov 2, 2017
684659d
Removing some unused constant strings
StanleyGoldman Nov 2, 2017
4009c55
Doing the same view switching logic that Window has
shana Nov 3, 2017
1fb2034
Relayout code
shana Nov 3, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 104 additions & 58 deletions src/GitHub.Api/Application/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,14 @@ public static IApiClient Create(UriString repositoryUrl, IKeychain keychain)
new GitHubClient(AppConfiguration.ProductHeader, credentialStore, hostAddress.ApiUri));
}

private static readonly Unity.ILogging logger = Unity.Logging.GetLogger<ApiClient>();
private static readonly ILogging logger = Logging.GetLogger<ApiClient>();
public HostAddress HostAddress { get; }
public UriString OriginalUrl { get; }

private readonly IKeychain keychain;
private readonly IGitHubClient githubClient;
private readonly ILoginManager loginManager;

IList<Organization> organizationsCache;
Octokit.User userCache;

public ApiClient(UriString hostUrl, IKeychain keychain, IGitHubClient githubClient)
{
Guard.ArgumentNotNull(hostUrl, nameof(hostUrl));
Expand All @@ -53,7 +50,7 @@ private async Task LogoutInternal(UriString host)
await loginManager.Logout(host);
}

public async Task CreateRepository(NewRepository newRepository, Action<Octokit.Repository, Exception> callback, string organization = null)
public async Task CreateRepository(NewRepository newRepository, Action<GitHubRepository, Exception> callback, string organization = null)
{
Guard.ArgumentNotNull(callback, "callback");
try
Expand All @@ -67,21 +64,27 @@ public async Task CreateRepository(NewRepository newRepository, Action<Octokit.R
}
}

public async Task GetOrganizations(Action<IList<Organization>> callback)
public async Task GetOrganizations(Action<Organization[]> onSuccess, Action<Exception> onError = null)
{
Guard.ArgumentNotNull(callback, "callback");
var organizations = await GetOrganizationInternal();
callback(organizations);
Guard.ArgumentNotNull(onSuccess, nameof(onSuccess));
await GetOrganizationInternal(onSuccess, onError);
}

public async Task LoadKeychain(Action<bool> callback)
public async Task ValidateCurrentUser(Action onSuccess, Action<Exception> onError = null)
{
Guard.ArgumentNotNull(callback, "callback");
var hasLoadedKeys = await LoadKeychainInternal();
callback(hasLoadedKeys);
Guard.ArgumentNotNull(onSuccess, nameof(onSuccess));
try
{
await ValidateCurrentUserInternal();
onSuccess();
}
catch (Exception e)
{
onError?.Invoke(e);
}
}

public async Task GetCurrentUser(Action<Octokit.User> callback)
public async Task GetCurrentUser(Action<GitHubUser> callback)
{
Guard.ArgumentNotNull(callback, "callback");
var user = await GetCurrentUserInternal();
Expand Down Expand Up @@ -184,29 +187,27 @@ public async Task<bool> ContinueLoginAsync(LoginResult loginResult, Func<LoginRe
return result.Code == LoginResultCodes.Success;
}

private async Task<Octokit.Repository> CreateRepositoryInternal(NewRepository newRepository, string organization)
private async Task<GitHubRepository> CreateRepositoryInternal(NewRepository newRepository, string organization)
{
try
{
logger.Trace("Creating repository");

if (!await LoadKeychainInternal())
{
throw new InvalidOperationException("The keychain did not load");
}
await ValidateKeychain();
await ValidateCurrentUserInternal();

Octokit.Repository repository;
GitHubRepository repository;
if (!string.IsNullOrEmpty(organization))
{
logger.Trace("Creating repository for organization");

repository = await githubClient.Repository.Create(organization, newRepository);
repository = (await githubClient.Repository.Create(organization, newRepository)).ToGitHubRepository();
}
else
{
logger.Trace("Creating repository for user");

repository = await githubClient.Repository.Create(newRepository);
repository = (await githubClient.Repository.Create(newRepository)).ToGitHubRepository();
}

logger.Trace("Created Repository");
Expand All @@ -219,66 +220,78 @@ public async Task<bool> ContinueLoginAsync(LoginResult loginResult, Func<LoginRe
}
}

private async Task<IList<Organization>> GetOrganizationInternal()
private async Task GetOrganizationInternal(Action<Organization[]> onSuccess, Action<Exception> onError = null)
{
try
{
logger.Trace("Getting Organizations");

if (!await LoadKeychainInternal())
{
return new List<Organization>();
}
await ValidateKeychain();
await ValidateCurrentUserInternal();

var organizations = await githubClient.Organization.GetAllForCurrent();

logger.Trace("Obtained {0} Organizations", organizations?.Count.ToString() ?? "NULL");

if (organizations != null)
{
organizationsCache = organizations.ToArray();
var array = organizations.Select(organization => new Organization() {
Name = organization.Name,
Login = organization.Login
}).ToArray();
onSuccess(array);
}
}
catch(Exception ex)
{
logger.Error(ex, "Error Getting Organizations");
throw;
onError?.Invoke(ex);
}

return organizationsCache;
}

private async Task<Octokit.User> GetCurrentUserInternal()
private async Task<GitHubUser> GetCurrentUserInternal()
{
try
{
logger.Trace("Getting Organizations");

if (!await LoadKeychainInternal())
{
return null;
}
logger.Trace("Getting Current User");
await ValidateKeychain();

userCache = await githubClient.User.Current();
return (await githubClient.User.Current()).ToGitHubUser();
}
catch(Exception ex)
catch (KeychainEmptyException)
{
logger.Warning("Keychain is empty");
throw;
}
catch (Exception ex)
{
logger.Error(ex, "Error Getting Current User");
throw;
}
}

private async Task ValidateCurrentUserInternal()
{
logger.Trace("Validating User");

return userCache;
var apiUser = await GetCurrentUserInternal();
var apiUsername = apiUser.Login;

var cachedUsername = keychain.Connections.First().Username;

if (apiUsername != cachedUsername)
{
throw new TokenUsernameMismatchException(cachedUsername, apiUsername);
}
}

private async Task<bool> LoadKeychainInternal()
{
logger.Trace("LoadKeychainInternal");

if (keychain.HasKeys)
{
if (!keychain.NeedsLoad)
{
logger.Trace("LoadKeychainInternal: Has keys does not need load");
logger.Trace("LoadKeychainInternal: Previously Loaded");
return true;
}

Expand All @@ -288,6 +301,8 @@ private async Task<bool> LoadKeychainInternal()
var uriString = keychain.Connections.First().Host;
var keychainAdapter = await keychain.Load(uriString);

logger.Trace("LoadKeychainInternal: Loaded");

return keychainAdapter.OctokitCredentials != Credentials.Anonymous;
}

Expand All @@ -296,23 +311,54 @@ private async Task<bool> LoadKeychainInternal()
return false;
}

public async Task<bool> ValidateCredentials()
private async Task ValidateKeychain()
{
try
if (!await LoadKeychainInternal())
{
var store = keychain.Connect(OriginalUrl);

if (store.OctokitCredentials != Credentials.Anonymous)
{
var credential = store.Credential;
await githubClient.Authorization.CheckApplicationAuthentication(ApplicationInfo.ClientId, credential.Token);
}
throw new KeychainEmptyException();
}
catch
{
return false;
}
return true;
}
}

class GitHubUser
{
public string Name { get; set; }
public string Login { get; set; }
}

class GitHubRepository
{
public string Name { get; set; }
public string CloneUrl { get; set; }
}

class ApiClientException : Exception
{
public ApiClientException()
{ }

public ApiClientException(string message) : base(message)
{ }

public ApiClientException(string message, Exception innerException) : base(message, innerException)
{ }
}

class TokenUsernameMismatchException : ApiClientException
{
public string CachedUsername { get; }
public string CurrentUsername { get; }

public TokenUsernameMismatchException(string cachedUsername, string currentUsername)
{
CachedUsername = cachedUsername;
CurrentUsername = currentUsername;
}
}

class KeychainEmptyException : ApiClientException
{
public KeychainEmptyException()
{ }
}
}
9 changes: 4 additions & 5 deletions src/GitHub.Api/Application/IApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ interface IApiClient
{
HostAddress HostAddress { get; }
UriString OriginalUrl { get; }
Task CreateRepository(NewRepository newRepository, Action<Octokit.Repository, Exception> callback, string organization = null);
Task GetOrganizations(Action<IList<Organization>> callback);
Task CreateRepository(NewRepository newRepository, Action<GitHubRepository, Exception> callback, string organization = null);
Task GetOrganizations(Action<Organization[]> onSuccess, Action<Exception> onError = null);
Task Login(string username, string password, Action<LoginResult> need2faCode, Action<bool, string> result);
Task ContinueLogin(LoginResult loginResult, string code);
Task<bool> LoginAsync(string username, string password, Func<LoginResult, string> need2faCode);
Task<bool> ValidateCredentials();
Task Logout(UriString host);
Task GetCurrentUser(Action<Octokit.User> callback);
Task LoadKeychain(Action<bool> callback);
Task GetCurrentUser(Action<GitHubUser> callback);
Task ValidateCurrentUser(Action onSuccess, Action<Exception> onError = null);
}
}
21 changes: 21 additions & 0 deletions src/GitHub.Api/Application/OctokitExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace GitHub.Unity
{
static class OctokitExtensions
{
public static GitHubUser ToGitHubUser(this Octokit.User user)
{
return new GitHubUser() {
Name = user.Name,
Login = user.Login,
};
}

public static GitHubRepository ToGitHubRepository(this Octokit.Repository repository)
{
return new GitHubRepository {
Name = repository.Name,
CloneUrl = repository.CloneUrl
};
}
}
}
8 changes: 8 additions & 0 deletions src/GitHub.Api/Application/Organization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GitHub.Unity
{
class Organization
{
public string Name { get; set; }
public string Login { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/GitHub.Api/Authentication/Keychain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public async Task<IKeychainAdapter> Load(UriString host)
{
if (keychainItem.Username != cachedConnection.Username)
{
logger.Warning("Keychain Username: {0} does not match; Hopefully it works", keychainItem.Username);
logger.Warning("Keychain Username:\"{0}\" does not match cached Username:\"{1}\"; Hopefully it works", keychainItem.Username, cachedConnection.Username);
}

logger.Trace("Loaded from Credential Manager Host:\"{0}\" Username:\"{1}\"", keychainItem.Host, keychainItem.Username);
Expand Down
2 changes: 2 additions & 0 deletions src/GitHub.Api/GitHub.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
<Compile Include="Application\ApplicationInfo.cs" />
<Compile Include="Application\LoginResult.cs" />
<Compile Include="Application\AppConfiguration.cs" />
<Compile Include="Application\OctokitExtensions.cs" />
<Compile Include="Application\Organization.cs" />
<Compile Include="Extensions\ListExtensions.cs" />
<Compile Include="Git\Tasks\GitLfsVersionTask.cs" />
<Compile Include="Git\Tasks\GitVersionTask.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,6 @@ public static GUIStyle AuthHeaderBoxStyle
{
authHeaderBoxStyle = new GUIStyle(HeaderBoxStyle);
authHeaderBoxStyle.name = "AuthHeaderBoxStyle";
authHeaderBoxStyle.padding = new RectOffset(10, 10, 0, 5);
}
return authHeaderBoxStyle;
}
Expand Down
Loading