diff --git a/src/Console/Program.cs b/src/Console/Program.cs
index 8fb786ab..353f598b 100644
--- a/src/Console/Program.cs
+++ b/src/Console/Program.cs
@@ -111,6 +111,7 @@ namespace Bit.Console
string email = null;
string masterPassword = null;
string token = null;
+ string orgId = null;
if(_usingArgs)
{
@@ -120,10 +121,14 @@ namespace Bit.Console
email = parameters["e"];
masterPassword = parameters["p"];
}
- if(parameters.Count == 3 && parameters.ContainsKey("t"))
+ if(parameters.Count >= 3 && parameters.ContainsKey("t"))
{
token = parameters["t"];
}
+ if(parameters.Count >= 3 && parameters.ContainsKey("o"))
+ {
+ orgId = parameters["o"];
+ }
}
else
{
@@ -160,7 +165,44 @@ namespace Bit.Console
Con.WriteLine("Two-step login is enabled on this account. Please enter your verification code.");
Con.Write("Verification code: ");
token = Con.ReadLine().Trim();
- result = await Core.Services.AuthService.Instance.LogInTwoFactorAsync(token, email, result.MasterPasswordHash);
+ result = await Core.Services.AuthService.Instance.LogInTwoFactorWithHashAsync(token, email,
+ result.MasterPasswordHash);
+ }
+
+ if(result.Success && result.Organizations.Count > 1)
+ {
+ Organization org = null;
+ if(string.IsNullOrWhiteSpace(orgId))
+ {
+ org = result.Organizations.FirstOrDefault(o => o.Id == orgId);
+ }
+ else
+ {
+ Con.WriteLine();
+ Con.WriteLine();
+ for(int i = 0; i < result.Organizations.Count; i++)
+ {
+ Con.WriteLine("{0}. {1}", i + 1, result.Organizations[i].Name);
+ }
+ Con.Write("Select your organization: ");
+ var orgIndexInput = Con.ReadLine().Trim();
+ int orgIndex;
+ if(int.TryParse(orgIndexInput, out orgIndex))
+ {
+ org = result.Organizations[orgIndex];
+ }
+ }
+
+ if(org == null)
+ {
+ result.Success = false;
+ result.ErrorMessage = "Organization not found.";
+ Core.Services.AuthService.Instance.LogOut();
+ }
+ else
+ {
+ Core.Services.SettingsService.Instance.Organization = org;
+ }
}
Con.WriteLine();
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 9ed20f81..bc41741e 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -55,6 +55,7 @@
+
diff --git a/src/Core/Models/LoginResult.cs b/src/Core/Models/LoginResult.cs
index 61609855..d84fb0b6 100644
--- a/src/Core/Models/LoginResult.cs
+++ b/src/Core/Models/LoginResult.cs
@@ -12,5 +12,6 @@ namespace Bit.Core.Models
public string ErrorMessage { get; set; }
public bool TwoFactorRequired { get; set; }
public string MasterPasswordHash { get; set; }
+ public List Organizations { get; set; }
}
}
diff --git a/src/Core/Models/Organization.cs b/src/Core/Models/Organization.cs
new file mode 100644
index 00000000..d5179e04
--- /dev/null
+++ b/src/Core/Models/Organization.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bit.Core.Models
+{
+ public class Organization
+ {
+ public Organization(ProfileOrganizationResponseModel org)
+ {
+ Name = org.Name;
+ Id = org.Id;
+ }
+
+ public string Name { get; set; }
+ public string Id { get; set; }
+ }
+}
diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs
index 63dcb66a..91c49be0 100644
--- a/src/Core/Services/AuthService.cs
+++ b/src/Core/Services/AuthService.cs
@@ -1,4 +1,5 @@
-using Bit.Core.Models;
+using Bit.Core.Enums;
+using Bit.Core.Models;
using Bit.Core.Utilities;
using System;
using System.Collections.Generic;
@@ -29,6 +30,7 @@ namespace Bit.Core.Services
}
public bool Authenticated => !string.IsNullOrWhiteSpace(TokenService.Instance.AccessToken);
+ public bool OrganizationSet => SettingsService.Instance.Organization != null;
public void LogOut()
{
@@ -68,8 +70,7 @@ namespace Bit.Core.Services
return result;
}
- await ProcessLogInSuccessAsync(response.Result);
- return result;
+ return await ProcessLogInSuccessAsync(response.Result);
}
public async Task LogInTwoFactorAsync(string token, string email, string masterPassword)
@@ -97,24 +98,54 @@ namespace Bit.Core.Services
var response = await ApiService.Instance.PostTokenAsync(request);
- var result = new LoginResult();
if(!response.Succeeded)
{
+ var result = new LoginResult();
result.Success = false;
result.ErrorMessage = response.Errors.FirstOrDefault()?.Message;
return result;
}
- result.Success = true;
- await ProcessLogInSuccessAsync(response.Result);
- return result;
+ return await ProcessLogInSuccessAsync(response.Result);
}
- private Task ProcessLogInSuccessAsync(TokenResponse response)
+ private async Task ProcessLogInSuccessAsync(TokenResponse response)
{
TokenService.Instance.AccessToken = response.AccessToken;
TokenService.Instance.RefreshToken = response.RefreshToken;
- return Task.FromResult(0);
+
+ var result = new LoginResult();
+
+ var profile = await ApiService.Instance.GetProfileAsync();
+ if(profile.Succeeded)
+ {
+ var adminOrgs = profile.Result.Organizations.Where(o =>
+ o.Status == OrganizationUserStatusType.Confirmed &&
+ o.Type != OrganizationUserType.User);
+ if(!adminOrgs.Any())
+ {
+ LogOut();
+ result.Success = false;
+ result.ErrorMessage = "You are not an admin of any organizations.";
+ return result;
+ }
+
+ result.Organizations = adminOrgs.Select(o => new Organization(o)).ToList();
+ if(result.Organizations.Count == 1)
+ {
+ SettingsService.Instance.Organization = new Organization(adminOrgs.First());
+ }
+
+ result.Success = true;
+ return result;
+ }
+ else
+ {
+ LogOut();
+ result.Success = false;
+ result.ErrorMessage = "Could not load profile.";
+ return result;
+ }
}
}
}
diff --git a/src/Core/Services/SettingsService.cs b/src/Core/Services/SettingsService.cs
index 892f7793..77a13655 100644
--- a/src/Core/Services/SettingsService.cs
+++ b/src/Core/Services/SettingsService.cs
@@ -127,6 +127,19 @@ namespace Bit.Core.Services
}
}
+ public Organization Organization
+ {
+ get
+ {
+ return Settings.Organization;
+ }
+ set
+ {
+ Settings.Organization = value;
+ SaveSettings();
+ }
+ }
+
public ServerConfiguration Server
{
get
@@ -147,6 +160,7 @@ namespace Bit.Core.Services
public EncryptedData AccessToken { get; set; }
public EncryptedData RefreshToken { get; set; }
public ServerConfiguration Server { get; set; }
+ public Organization Organization { get; set; }
}
}
}