using Bit.Core.Enums; using Bit.Core.Models; using Bit.Core.Services; using Bit.Core.Utilities; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Con = System.Console; namespace Bit.Console { public class Program { private static bool _usingArgs = false; private static bool _exit = false; private static string[] _args = null; static void Main(string[] args) { MainAsync(args).Wait(); } private static async Task MainAsync(string[] args) { _args = args; _usingArgs = args.Length > 0; string selection = null; Con.ForegroundColor = ConsoleColor.Cyan; Con.WriteLine(@" _ _ _ _ | |__ (_) |___ ____ _ _ __ __| | ___ _ __ | '_ \| | __\ \ /\ / / _` | '__/ _` |/ _ \ '_ \ | |_) | | |_ \ V V / (_| | | | (_| | __/ | | | |_.__/|_|\__| \_/\_/ \__,_|_| \__,_|\___|_| |_|"); Con.ResetColor(); Con.WriteLine(); Con.WriteLine(Constants.ProgramName); Con.WriteLine("Copyright 2015-{0}, 8bit Solutions LLC", DateTime.Now.Year); Con.WriteLine(); Con.WriteLine("https://bitwarden.com"); Con.WriteLine("https://github.com/bitwarden/directory-connector"); Con.WriteLine(); while(true) { Con.ResetColor(); if(_usingArgs) { selection = args[0]; } else { Con.WriteLine("Main Menu"); Con.WriteLine("================================="); Con.WriteLine("1. Log in to bitwarden"); Con.WriteLine("2. Log out"); Con.WriteLine("3. Configure directory connection"); Con.WriteLine("4. Configure sync"); Con.WriteLine("5. Simulate directory sync"); Con.WriteLine("6. Sync directory"); Con.WriteLine("7. Control background service"); Con.WriteLine("8. Configure environment"); Con.WriteLine("9. Exit"); Con.WriteLine(); Con.Write("What would you like to do? "); selection = Con.ReadLine(); Con.WriteLine(); } switch(selection) { case "1": case "login": case "signin": await LogInAsync(); break; case "2": case "logout": case "signout": await LogOutAsync(); break; case "3": case "cdir": case "configdirectory": await ConfigDirectoryAsync(); break; case "4": case "csync": case "configsync": await ConfigSyncAsync(); break; case "5": case "print": case "sim": case "simulate": await PrintAsync(); break; case "6": case "sync": await SyncAsync(); break; case "7": case "svc": case "service": await ServiceAsync(); break; case "8": case "environnment": case "env": await ConfigEnvironmentAsync(); break; case "9": case "exit": case "quit": case "q": _exit = true; break; case "cache": case "clearcache": await ClearCacheAsync(); break; default: Con.WriteLine("Unknown command."); break; } if(_exit || _usingArgs) { break; } else { Con.WriteLine(); Con.WriteLine(); } } _args = null; } private static async Task LogInAsync() { if(AuthService.Instance.Authenticated) { Con.WriteLine("You are already logged in as {0}.", TokenService.Instance.AccessTokenEmail); return; } string email = null; string masterPassword = null; string token = null; string orgId = null; var provider = TwoFactorProviderType.Authenticator; if(_usingArgs) { var parameters = ParseParameters(); if(parameters.Count >= 2 && parameters.ContainsKey("e") && parameters.ContainsKey("p")) { email = parameters["e"]; masterPassword = parameters["p"]; } if(parameters.Count >= 4 && parameters.ContainsKey("t") && parameters.ContainsKey("tp") && Enum.TryParse(parameters["tp"], out provider)) { token = parameters["t"]; } if(parameters.Count >= 3 && parameters.ContainsKey("o")) { orgId = parameters["o"]; } } else { Con.Write("Email: "); email = Con.ReadLine().Trim(); Con.Write("Master password: "); masterPassword = ReadSecureLine(); } if(string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(masterPassword)) { Con.WriteLine(); Con.WriteLine(); WriteErrorLine("Invalid input parameters."); return; } Con.WriteLine(); Con.WriteLine("Logging in..."); LoginResult result = null; if(string.IsNullOrWhiteSpace(token)) { result = await AuthService.Instance.LogInAsync(email, masterPassword); } else { result = await AuthService.Instance.LogInTwoFactorAsync(provider, token, email, masterPassword); } if(string.IsNullOrWhiteSpace(token) && result.TwoFactorRequired) { Con.WriteLine(); Con.WriteLine(); Con.WriteLine("Two-step login is enabled on this account."); if(result.TwoFactorProviders.Count > 1) { for(var i = 0; i < result.TwoFactorProviders.Count; i++) { Con.WriteLine("{0}. {1}{2}", i + 1, result.TwoFactorProviders.ElementAt(i).Key, result.TwoFactorProviders.ElementAt(i).Key == TwoFactorProviderType.Duo || result.TwoFactorProviders.ElementAt(i).Key == TwoFactorProviderType.U2f ? " - not supported" : string.Empty); } Con.WriteLine(); Con.Write("Which provider would you like to use?: "); var providerIndexInput = Con.ReadLine().Trim(); int providerIndex; if(int.TryParse(providerIndexInput, out providerIndex) && result.TwoFactorProviders.Count >= providerIndex) { provider = result.TwoFactorProviders.ElementAt(providerIndex - 1).Key; } else { provider = result.TwoFactorProviders.First().Key; } } else { provider = result.TwoFactorProviders.First().Key; Con.WriteLine(); } var readingTokenInput = true; if(provider == TwoFactorProviderType.YubiKey) { Con.Write("Tap the button on your YubiKey: "); } else if(provider == TwoFactorProviderType.Email) { if(result.TwoFactorProviders.Count > 1) { await ApiService.Instance.PostTwoFactorSendEmailLoginAsync(new TwoFactorEmailRequest { Email = email, MasterPasswordHash = result.MasterPasswordHash }); } Con.Write("Enter the verification code that was emailed to you: "); } else if(provider == TwoFactorProviderType.Authenticator) { Con.Write("Enter the verification code from your authenticator app: "); } else { Con.WriteLine("The selected two-step login method is not supported on this platform/application. " + "Use a different two step-login method."); readingTokenInput = false; } if(readingTokenInput) { token = Con.ReadLine().Trim(); result = await AuthService.Instance.LogInTwoFactorWithHashAsync(provider, token, email, result.MasterPasswordHash); } } if(result.Success && result.Organizations != null && 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.WriteLine(); Con.Write("Select your organization: "); var orgIndexInput = Con.ReadLine().Trim(); int orgIndex; if(int.TryParse(orgIndexInput, out orgIndex) && result.Organizations.Count >= orgIndex) { org = result.Organizations[orgIndex - 1]; } } if(org == null) { result.Success = false; result.ErrorMessage = "Organization not found."; AuthService.Instance.LogOut(); } else { SettingsService.Instance.Organization = org; } } Con.WriteLine(); Con.WriteLine(); if(result.Success) { if(!result.TwoFactorRequired) { WriteSuccessLine(string.Format("You have successfully logged in as {0}!", TokenService.Instance.AccessTokenEmail)); } else { WriteErrorLine("Unable to log in."); } } else { WriteErrorLine(result.ErrorMessage); } masterPassword = null; } private static Task LogOutAsync() { if(AuthService.Instance.Authenticated) { AuthService.Instance.LogOut(); WriteSuccessLine("You have successfully logged out!"); } else { WriteErrorLine("You are not logged in."); } return Task.FromResult(0); } private static Task ConfigDirectoryAsync() { var config = SettingsService.Instance.Server ?? new ServerConfiguration(); if(_usingArgs) { var parameters = ParseParameters(); if(parameters.ContainsKey("t")) { Core.Enums.DirectoryType dirType; if(Enum.TryParse(parameters["t"], out dirType)) { config.Type = dirType; } else { WriteErrorLine("Unable to parse type parameter."); return Task.FromResult(0); } } if(config.Type == Core.Enums.DirectoryType.AzureActiveDirectory) { config.Azure = new AzureConfiguration(); if(parameters.ContainsKey("i")) { config.Azure.Id = parameters["i"]; } if(parameters.ContainsKey("s")) { config.Azure.Secret = new EncryptedData(parameters["s"]); } if(parameters.ContainsKey("te")) { config.Azure.Tenant = parameters["te"]; } } else if(config.Type == Core.Enums.DirectoryType.GSuite) { config.GSuite = new GSuiteConfiguration(); if(parameters.ContainsKey("f")) { config.GSuite.SecretFile = parameters["f"]; } if(parameters.ContainsKey("u")) { config.GSuite.AdminUser = parameters["u"]; } if(parameters.ContainsKey("d")) { config.GSuite.Domain = parameters["d"]; config.GSuite.Customer = null; } else if(parameters.ContainsKey("c")) { config.GSuite.Customer = parameters["c"]; config.GSuite.Domain = null; } } else { config.Ldap = config.Ldap ?? new LdapConfiguration(); if(parameters.ContainsKey("a")) { config.Ldap.Address = parameters["a"]; } if(parameters.ContainsKey("port")) { config.Ldap.Port = parameters["port"]; } if(parameters.ContainsKey("path")) { config.Ldap.Path = parameters["path"]; } if(parameters.ContainsKey("cu")) { config.Ldap.Username = null; config.Ldap.Password = null; } else { if(parameters.ContainsKey("u")) { config.Ldap.Username = parameters["u"]; } if(parameters.ContainsKey("p")) { config.Ldap.Password = new EncryptedData(parameters["p"]); } } } } else { string input; Con.WriteLine("1. Active Directory"); Con.WriteLine("2. Azure Active Directory "); Con.WriteLine("3. G Suite Directory"); Con.WriteLine("4. Other LDAP Directory"); string currentType; switch(config.Type) { case Core.Enums.DirectoryType.ActiveDirectory: currentType = "1"; break; case Core.Enums.DirectoryType.AzureActiveDirectory: currentType = "2"; break; case Core.Enums.DirectoryType.GSuite: currentType = "3"; break; default: currentType = "4"; break; } Con.WriteLine(); Con.Write("Type [{0}]: ", currentType); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { switch(input) { case "1": config.Type = Core.Enums.DirectoryType.ActiveDirectory; break; case "2": config.Type = Core.Enums.DirectoryType.AzureActiveDirectory; break; case "3": config.Type = Core.Enums.DirectoryType.GSuite; break; default: config.Type = Core.Enums.DirectoryType.Other; break; } } if(config.Type == Core.Enums.DirectoryType.AzureActiveDirectory) { config.Azure = config.Azure ?? new AzureConfiguration(); Con.Write("Tenant [{0}]: ", config.Azure.Tenant); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Azure.Tenant = input.Trim(); } Con.Write("Application Id [{0}]: ", config.Azure.Id); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Azure.Id = input.Trim(); } Con.Write("Secret key: "); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Azure.Secret = new EncryptedData(input.Trim()); input = null; } } else if(config.Type == Core.Enums.DirectoryType.GSuite) { config.GSuite = config.GSuite ?? new GSuiteConfiguration(); Con.Write("Secret file [{0}]: ", config.GSuite.SecretFile); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.GSuite.SecretFile = input.Trim(); } Con.Write("Domain [{0}]: ", config.GSuite.Domain); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.GSuite.Domain = input.Trim(); config.GSuite.Customer = null; } Con.Write("Admin user [{0}]: ", config.GSuite.AdminUser); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.GSuite.AdminUser = input.Trim(); } } else { config.Ldap = config.Ldap ?? new LdapConfiguration(); Con.Write("Address [{0}]: ", config.Ldap.Address); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.Address = input.Trim(); } Con.Write("Port [{0}]: ", config.Ldap.Port); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.Port = input.Trim(); } Con.Write("Path [{0}]: ", config.Ldap.Path); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.Path = input.Trim(); } var currentUser = string.IsNullOrWhiteSpace(config.Ldap.Username) && config.Ldap.Password == null; Con.Write("Authenticate as current user? [{0}]: ", currentUser ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) { currentUser = input == "y" || input == "yes"; } if(currentUser) { config.Ldap.Username = null; config.Ldap.Password = null; } else { Con.Write("Username [{0}]: ", config.Ldap.Username); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.Username = input.Trim(); } Con.Write("Password: "); input = ReadSecureLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.Password = new EncryptedData(input); input = null; } } } input = null; } Con.WriteLine(); Con.WriteLine(); if(config.Ldap != null && string.IsNullOrWhiteSpace(config.Ldap.Address)) { WriteErrorLine("Invalid input parameters."); } else if(config.Azure != null && (string.IsNullOrWhiteSpace(config.Azure.Id) || config.Azure.Secret == null || string.IsNullOrWhiteSpace(config.Azure.Tenant))) { WriteErrorLine("Invalid input parameters."); } else { SettingsService.Instance.Server = config; WriteSuccessLine("Saved directory server configuration."); } return Task.FromResult(0); } private static Task ConfigSyncAsync() { var config = SettingsService.Instance.Sync ?? new SyncConfiguration(SettingsService.Instance.Server.Type); if(_usingArgs) { var parameters = ParseParameters(); config.SyncGroups = parameters.ContainsKey("g"); config.SyncUsers = parameters.ContainsKey("u"); int intervalMinutes; if(parameters.ContainsKey("i") && int.TryParse(parameters["i"], out intervalMinutes)) { config.IntervalMinutes = intervalMinutes; } if(parameters.ContainsKey("uf")) { config.UserFilter = parameters["uf"]; } if(parameters.ContainsKey("gf")) { config.GroupFilter = parameters["gf"]; } config.RemoveDisabledUsers = parameters.ContainsKey("rd"); if(SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.ActiveDirectory || SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.Other) { if(parameters.ContainsKey("go")) { config.Ldap.GroupObjectClass = parameters["go"]; } if(parameters.ContainsKey("gp")) { config.Ldap.GroupPath = parameters["gp"]; } if(parameters.ContainsKey("gn")) { config.Ldap.GroupNameAttribute = parameters["gn"]; } if(parameters.ContainsKey("uo")) { config.Ldap.UserObjectClass = parameters["uo"]; } if(parameters.ContainsKey("up")) { config.Ldap.UserPath = parameters["up"]; } if(parameters.ContainsKey("ue")) { config.Ldap.UserEmailAttribute = parameters["ue"]; } if(parameters.ContainsKey("m")) { config.Ldap.MemberAttribute = parameters["m"]; } config.Ldap.EmailPrefixSuffix = parameters.ContainsKey("ps"); if(parameters.ContainsKey("ep")) { config.Ldap.UserEmailPrefixAttribute = parameters["ep"]; } if(parameters.ContainsKey("es")) { config.Ldap.UserEmailSuffix = parameters["es"]; } if(parameters.ContainsKey("c")) { config.Ldap.CreationDateAttribute = parameters["c"]; } if(parameters.ContainsKey("r")) { config.Ldap.RevisionDateAttribute = parameters["r"]; } } } else { string input; Con.Write("Sync groups? [{0}]: ", config.SyncGroups ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) { config.SyncGroups = input == "y" || input == "yes"; } if(config.SyncGroups && (SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.ActiveDirectory || SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.Other)) { Con.Write("Group path [{0}]: ", config.Ldap.GroupPath); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.GroupPath = input; } Con.Write("Group object class [{0}]: ", config.Ldap.GroupObjectClass); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.GroupObjectClass = input; } Con.Write("Group name attribute [{0}]: ", config.Ldap.GroupNameAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.GroupNameAttribute = input; } Con.Write("Member Attribute [{0}]: ", config.Ldap.MemberAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.MemberAttribute = input; } } if(config.SyncGroups) { Con.Write("Group filter [{0}]: ", config.GroupFilter); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.GroupFilter = input; } } Con.Write("Sync users? [{0}]: ", config.SyncUsers ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) { config.SyncUsers = input == "y" || input == "yes"; } if(config.SyncUsers && (SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.ActiveDirectory || SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.Other)) { Con.Write("User path [{0}]: ", config.Ldap.UserPath); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.UserPath = input; } Con.Write("User object class [{0}]: ", config.Ldap.UserObjectClass); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.UserObjectClass = input; } Con.Write("User email attribute [{0}]: ", config.Ldap.UserEmailAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.GroupNameAttribute = input; } Con.Write("Use email prefix/suffix fallback? [{0}]: ", config.Ldap.EmailPrefixSuffix ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) { config.Ldap.EmailPrefixSuffix = input == "y" || input == "yes"; } if(config.Ldap.EmailPrefixSuffix) { Con.Write("Email prefix attribute [{0}]: ", config.Ldap.UserEmailPrefixAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.UserEmailPrefixAttribute = input; } Con.Write("Email suffix [{0}]: ", config.Ldap.UserEmailSuffix); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.UserEmailSuffix = input; } } } if(config.SyncUsers) { Con.Write("User filter [{0}]: ", config.UserFilter); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.UserFilter = input; } Con.Write("Remove disabled users? [{0}]: ", config.RemoveDisabledUsers ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) { config.RemoveDisabledUsers = input == "y" || input == "yes"; } } if(SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.ActiveDirectory || SettingsService.Instance.Server.Type == Core.Enums.DirectoryType.Other) { Con.Write("Creation Attribute [{0}]: ", config.Ldap.CreationDateAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.CreationDateAttribute = input; } Con.Write("Changed Attribute [{0}]: ", config.Ldap.RevisionDateAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.Ldap.RevisionDateAttribute = input; } } Con.Write("Sync interval (minutes, minimum {1}) [{0}]: ", config.IntervalMinutes, "5"); input = Con.ReadLine(); int intervalMinutes; if(!string.IsNullOrEmpty(input) && int.TryParse(input, out intervalMinutes)) { config.IntervalMinutes = intervalMinutes; } input = null; } Con.WriteLine(); Con.WriteLine(); SettingsService.Instance.Sync = config; WriteSuccessLine("Saved sync configuration."); return Task.FromResult(0); } private static async Task SyncAsync() { if(!AuthService.Instance.Authenticated) { Con.WriteLine("You are not logged in."); } else if(SettingsService.Instance.Server == null) { Con.WriteLine("Server is not configured."); } else { var force = false; if(_usingArgs) { var parameters = ParseParameters(); force = parameters.ContainsKey("f"); } Con.WriteLine("Syncing..."); var result = await Sync.SyncAllAsync(force, true); if(result.Success) { WriteSuccessLine(string.Format("Syncing complete ({0} users, {1} groups).", result.Users?.Count ?? 0, result.Groups?.Count ?? 0)); } else { WriteErrorLine("Syncing failed.\n" + result.ErrorMessage); } } } private static async Task PrintAsync() { if(!AuthService.Instance.Authenticated) { Con.WriteLine("You are not logged in."); } else if(SettingsService.Instance.Server == null) { Con.WriteLine("Server is not configured."); } else { var force = false; if(_usingArgs) { var parameters = ParseParameters(); force = parameters.ContainsKey("f"); } Con.WriteLine("Querying..."); Con.WriteLine(); var result = await Sync.SyncAllAsync(force, false); if(result.Success) { if(result.Groups != null) { Con.WriteLine("Groups:"); foreach(var group in result.Groups) { Con.WriteLine(" {0} - {1}", group.Name, group.ExternalId); foreach(var user in group.UserMemberExternalIds) { Con.WriteLine(" {0}", user); } } } if(result.Users != null) { Con.WriteLine(); Con.WriteLine("Users:"); foreach(var user in result.Users) { Con.WriteLine(" {0}{1}{2}", user.Email ?? user.ExternalId, user.Disabled ? " (-)" : null, user.Deleted ? " (X)" : null); } } } else { WriteErrorLine("Querying failed.\n" + result.ErrorMessage); } } } private static Task ServiceAsync() { try { Con.WriteLine("Service current status: {0}", ControllerService.Instance.StatusString); Con.WriteLine(); } catch { Con.WriteLine("Service unavailable."); return Task.FromResult(0); } var start = false; var stop = false; var status = false; if(_usingArgs) { var parameters = ParseParameters(); if(parameters.ContainsKey("start")) { start = true; } else if(parameters.ContainsKey("stop")) { stop = true; } } else { Con.WriteLine("1. Start service"); Con.WriteLine("2. Stop service"); Con.WriteLine("3. Check service status"); Con.WriteLine("4. Nothing, go back"); Con.WriteLine(); Con.Write("Option: "); var selection = Con.ReadLine(); switch(selection) { case "1": case "start": start = true; break; case "2": case "stop": stop = true; break; case "3": case "status": status = true; break; default: break; } } Con.WriteLine(); if((start || stop) && !Helpers.IsAdministrator()) { WriteErrorLine("You must be an administrator to control the service."); return Task.FromResult(0); } if(start) { Con.WriteLine("Starting service..."); ControllerService.Instance.Start(); } else if(stop) { Con.WriteLine("Stopping service..."); ControllerService.Instance.Stop(); } else if(status) { Con.WriteLine("Status: {0}", ControllerService.Instance.StatusString); } return Task.FromResult(0); } private static Task ConfigEnvironmentAsync() { if(_usingArgs) { var parameters = ParseParameters(); if(parameters.ContainsKey("debug")) { SettingsService.Instance.ApiBaseUrl = "http://localhost:4000"; SettingsService.Instance.IdentityBaseUrl = "http://localhost:33656"; } else { if(parameters.ContainsKey("api")) { SettingsService.Instance.ApiBaseUrl = parameters["api"]; } if(parameters.ContainsKey("id")) { SettingsService.Instance.IdentityBaseUrl = parameters["id"]; } } } else { var input = string.Empty; Con.Write("API [{0}]: ", SettingsService.Instance.ApiBaseUrl); input = Con.ReadLine(); if(input == "debug") { SettingsService.Instance.ApiBaseUrl = "http://localhost:4000"; } else if(!string.IsNullOrEmpty(input)) { SettingsService.Instance.ApiBaseUrl = input; } Con.Write("Identity [{0}]: ", SettingsService.Instance.IdentityBaseUrl); input = Con.ReadLine(); if(input == "debug") { SettingsService.Instance.IdentityBaseUrl = "http://localhost:33656"; } else if(!string.IsNullOrEmpty(input)) { SettingsService.Instance.IdentityBaseUrl = input; } } return Task.FromResult(0); } private static Task ClearCacheAsync() { SettingsService.Instance.GroupDeltaToken = null; SettingsService.Instance.LastGroupSyncDate = null; SettingsService.Instance.UserDeltaToken = null; SettingsService.Instance.LastUserSyncDate = null; SettingsService.Instance.LastSyncHash = null; return Task.FromResult(0); } private static string ReadSecureLine() { var input = string.Empty; while(true) { var i = Con.ReadKey(true); if(i.Key == ConsoleKey.Enter) { break; } else if(i.Key == ConsoleKey.Backspace) { if(input.Length > 0) { input = input.Remove(input.Length - 1); Con.Write("\b \b"); } } else { input = string.Concat(input, i.KeyChar); Con.Write("*"); } } return input; } private static IDictionary ParseParameters() { var dict = new Dictionary(); for(int i = 1; i < _args.Length; i = i + 2) { if(!_args[i].StartsWith("-")) { continue; } dict.Add(_args[i].Substring(1), _args[i + 1]); } return dict; } private static void WriteErrorLine(string message) { Con.ForegroundColor = ConsoleColor.Red; Con.WriteLine(message); Con.ResetColor(); } private static void WriteSuccessLine(string message) { Con.ForegroundColor = ConsoleColor.Green; Con.WriteLine(message); Con.ResetColor(); } } }