public static void EnableTraceLoggingFile(Program program, OperationArguments operationArguments, string logFilePath)
        {
            const int LogFileMaxLength = 8 * 1024 * 1024; // 8 MB

            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }
            if (logFilePath is null)
            {
                throw new ArgumentNullException(nameof(logFilePath));
            }

            string logFileName = Path.Combine(logFilePath, Path.ChangeExtension(Program.ConfigPrefix, ".log"));

            var logFileInfo = new FileInfo(logFileName);

            if (logFileInfo.Exists && logFileInfo.Length > LogFileMaxLength)
            {
                for (int i = 1; i < int.MaxValue; i++)
                {
                    string moveName = string.Format("{0}{1:000}.log", Program.ConfigPrefix, i);
                    string movePath = Path.Combine(logFilePath, moveName);

                    if (!File.Exists(movePath))
                    {
                        logFileInfo.MoveTo(movePath);
                        break;
                    }
                }
            }

            Git.Trace.WriteLine($"trace log destination is '{logFilePath}'.");

            using (var fileStream = File.Open(logFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
            {
                var listener = new StreamWriter(fileStream, Encoding.UTF8);
                Git.Trace.AddListener(listener);

                // write a small header to help with identifying new log entries
                listener.Write('\n');
                listener.Write($"{DateTime.Now:yyyy.MM.dd HH:mm:ss} Microsoft {program.Title} version {program.Version.ToString(3)}\n");
            }
        }
        internal void Get()
        {
            Task.Run(async() =>
            {
                var operationArguments = new OperationArguments(_context);

                // Parse the operations arguments from stdin (this is how git sends commands)
                // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
                // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
                using (var stdin = InStream)
                {
                    await operationArguments.ReadInput(stdin);
                }

                if (operationArguments.TargetUri is null)
                {
                    var inner = new ArgumentNullException(nameof(operationArguments.TargetUri));
                    throw new ArgumentException(inner.Message, nameof(operationArguments), inner);
                }

                // Load operation arguments.
                await LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                // Read the details of any git-remote-http(s).exe parent process, but only if
                // an override hasn't been set which would override the git-remote details.
                if (string.IsNullOrEmpty(operationArguments.UrlOverride))
                {
                    ReadGitRemoteDetails(operationArguments);
                }

                // Set the parent window handle.
                ParentHwnd = operationArguments.ParentHwnd;

                Credential credentials;
                if ((credentials = await QueryCredentials(operationArguments)) == null)
                {
                    Exit(-1, LogonFailedMessage);
                }
                else
                {
                    using (var stdout = OutStream)
                    {
                        operationArguments.WriteToStream(stdout);
                    }
                }
            }).Wait();
        }
Exemplo n.º 3
0
        internal void Store()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = InStream)
            {
                OperationArguments operationArguments = new OperationArguments(stdin);

                Debug.Assert(operationArguments != null, "The operationArguments is null");
                Debug.Assert(operationArguments.Username != null, "The operaionArgument.Username is null");
                Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

                LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                var credentials = operationArguments.Credentials;
                var task        = Task.Run(async() => { return(await CreateAuthentication(operationArguments)); });
                BaseAuthentication authentication = task.Result;

                switch (operationArguments.Authority)
                {
                default:
                case AuthorityType.Basic:
                    Git.Trace.WriteLine($"storing basic credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.Bitbucket:
                    Git.Trace.WriteLine($"storing Bitbucket credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.AzureDirectory:
                case AuthorityType.MicrosoftAccount:
                    Git.Trace.WriteLine($"storing VSTS credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.GitHub:
                    Git.Trace.WriteLine($"storing GitHub credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.Ntlm:
                    Git.Trace.WriteLine($"storing NTLM credentials for '{operationArguments.TargetUri}'.");
                    break;
                }

                authentication.SetCredentials(operationArguments.TargetUri, credentials);
            }
        }
        public static void ReadGitRemoteDetails(Program program, OperationArguments operationArguments)
        {
            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            if (program.Utilities.TryReadGitRemoteHttpDetails(out string commandLine, out _))
            {
                operationArguments.GitRemoteHttpCommandLine = commandLine;
            }
        }
        public static async Task <bool> DeleteCredentials(Program program, OperationArguments operationArguments)
        {
            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            BaseAuthentication authentication = await program.CreateAuthentication(operationArguments);

            switch (operationArguments.Authority)
            {
            default:
            case AuthorityType.Basic:
            {
                program.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
                return(await authentication.DeleteCredentials(operationArguments.TargetUri));
            }

            case AuthorityType.AzureDirectory:
            case AuthorityType.MicrosoftAccount:
            {
                program.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
                var vstsAuth = authentication as Vsts.Authentication;
                return(await vstsAuth.DeleteCredentials(operationArguments.TargetUri));
            }

            case AuthorityType.GitHub:
            {
                program.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
                var ghAuth = authentication as Github.Authentication;
                return(await ghAuth.DeleteCredentials(operationArguments.TargetUri));
            }

            case AuthorityType.Bitbucket:
            {
                program.Trace.WriteLine($"deleting Bitbucket credentials for '{operationArguments.TargetUri}'.");
                var bbAuth = authentication as Bitbucket.Authentication;
                return(await bbAuth.DeleteCredentials(operationArguments.TargetUri, operationArguments.Username));
            }
            }
        }
Exemplo n.º 6
0
        internal void Get()
        {
            // Parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = InStream)
            {
                OperationArguments operationArguments = new OperationArguments(_context);

                Task.Run(async() =>
                {
                    await operationArguments.ReadInput(stdin);

                    if (operationArguments.TargetUri is null)
                    {
                        var inner = new ArgumentNullException(nameof(operationArguments.TargetUri));
                        throw new ArgumentException(inner.Message, nameof(operationArguments), inner);
                    }

                    // Load operation arguments.
                    await LoadOperationArguments(operationArguments);
                    EnableTraceLogging(operationArguments);

                    // Read the details of any git-remote-http(s).exe parent process.
                    ReadGitRemoteDetails(operationArguments);

                    // Set the parent window handle.
                    ParentHwnd = operationArguments.ParentHwnd;

                    Credential credentials;
                    if ((credentials = await QueryCredentials(operationArguments)) == null)
                    {
                        Exit(-1, "Logon failed, use ctrl+c to cancel basic credential prompt.");
                    }
                    else
                    {
                        using (var stdout = OutStream)
                        {
                            operationArguments.WriteToStream(stdout);
                        }
                    }
                }).Wait();
            }
        }
        internal void Erase()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = InStream)
            {
                var operationArguments = new OperationArguments(_context);

                Task.Run(async() =>
                {
                    await operationArguments.ReadInput(stdin);

                    if (operationArguments.TargetUri is null)
                    {
                        var inner = new ArgumentNullException(nameof(operationArguments.TargetUri));
                        throw new ArgumentException(inner.Message, nameof(operationArguments), inner);
                    }

                    // Load operation arguments.
                    await LoadOperationArguments(operationArguments);
                    EnableTraceLogging(operationArguments);

                    // Read the details of any git-remote-http(s).exe parent process, but only if
                    // an override hasn't been set which would override the git-remote details.
                    if (string.IsNullOrEmpty(operationArguments.UrlOverride))
                    {
                        ReadGitRemoteDetails(operationArguments);
                    }

                    // Set the parent window handle.
                    ParentHwnd = operationArguments.ParentHwnd;

                    if (operationArguments.PreserveCredentials)
                    {
                        _context.Trace.WriteLine($"{KeyTypeName(KeyType.PreserveCredentials)} = true, canceling erase request.");
                        return;
                    }

                    await DeleteCredentials(operationArguments);
                }).Wait();
            }
        }
        private static void Store()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = Console.OpenStandardInput())
            {
                OperationArguments operationArguments = new OperationArguments(stdin);

                Debug.Assert(operationArguments != null, "The operationArguments is null");
                Debug.Assert(operationArguments.CredUsername != null, "The operaionArgument.Username is null");
                Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

                LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                Credential         credentials    = new Credential(operationArguments.CredUsername, operationArguments.CredPassword);
                BaseAuthentication authentication = CreateAuthentication(operationArguments);

                switch (operationArguments.Authority)
                {
                default:
                case AuthorityType.Basic:
                    Git.Trace.WriteLine($"storing basic credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.AzureDirectory:
                case AuthorityType.MicrosoftAccount:
                    Git.Trace.WriteLine($"storing VSTS credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.GitHub:
                    Git.Trace.WriteLine($"storing GitHub credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.Ntlm:
                    Git.Trace.WriteLine($"storing NTLM credentials for '{operationArguments.TargetUri}'.");
                    break;
                }

                authentication.SetCredentials(operationArguments.TargetUri, credentials);
            }
        }
        public static void EnableTraceLogging(Program program, OperationArguments operationArguments)
        {
            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            if (operationArguments.WriteLog)
            {
                program.Trace.WriteLine("trace logging enabled.");

                string gitConfigPath;
                if (program.Where.GitLocalConfig(out gitConfigPath))
                {
                    program.Trace.WriteLine($"git local config found at '{gitConfigPath}'.");

                    string gitDirPath = Path.GetDirectoryName(gitConfigPath);

                    if (program.Storage.DirectoryExists(gitDirPath))
                    {
                        program.EnableTraceLogging(operationArguments, gitDirPath);
                    }
                }
                else if (program.Where.GitGlobalConfig(out gitConfigPath))
                {
                    program.Trace.WriteLine($"git global config found at '{gitConfigPath}'.");

                    string homeDirPath = Path.GetDirectoryName(gitConfigPath);

                    if (program.Storage.DirectoryExists(homeDirPath))
                    {
                        program.EnableTraceLogging(operationArguments, homeDirPath);
                    }
                }
            }
#if DEBUG
            program.Trace.WriteLine($"GCM arguments:{Environment.NewLine}{operationArguments}");
#endif
        }
Exemplo n.º 10
0
        private static void Store()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            var stdin = Console.OpenStandardInput();
            OperationArguments operationArguments = new OperationArguments(stdin);

            Debug.Assert(operationArguments != null, "The operationArguments is null");
            Debug.Assert(operationArguments.CredUsername != null, "The operaionArgument.Username is null");
            Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

            LoadOperationArguments(operationArguments);
            EnableTraceLogging(operationArguments);

            BaseAuthentication authentication = CreateAuthentication(operationArguments);
            Credential         credentials    = new Credential(operationArguments.CredUsername, operationArguments.CredPassword);

            authentication.SetCredentials(operationArguments.TargetUri, credentials);
        }
        private static void Get()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = Console.OpenStandardInput())
            {
                OperationArguments operationArguments = new OperationArguments(stdin);

                LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                QueryCredentials(operationArguments);

                using (var stdout = Console.OpenStandardOutput())
                {
                    operationArguments.WriteToStream(stdout);
                }
            }
        }
Exemplo n.º 12
0
        private static void Erase()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            var stdin = Console.OpenStandardInput();
            OperationArguments operationArguments = new OperationArguments(stdin);

            Debug.Assert(operationArguments != null, "The operationArguments is null");
            Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

            LoadOperationArguments(operationArguments);
            EnableTraceLogging(operationArguments);

            if (operationArguments.PreserveCredentials)
            {
                Git.Trace.WriteLine($"{ConfigPreserveCredentialsKey} = true, canceling erase request.");
                return;
            }

            DeleteCredentials(operationArguments);
        }
Exemplo n.º 13
0
        public static void DeleteCredentials(Program program, OperationArguments operationArguments)
        {
            if (operationArguments is null)
            {
                throw new ArgumentNullException("operationArguments");
            }

            var task = Task.Run(async() => { return(await program.CreateAuthentication(operationArguments)); });

            BaseAuthentication authentication = task.Result;

            switch (operationArguments.Authority)
            {
            default:
            case AuthorityType.Basic:
                Git.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
                authentication.DeleteCredentials(operationArguments.TargetUri);
                break;

            case AuthorityType.AzureDirectory:
            case AuthorityType.MicrosoftAccount:
                Git.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
                var vstsAuth = authentication as BaseVstsAuthentication;
                vstsAuth.DeleteCredentials(operationArguments.TargetUri);
                break;

            case AuthorityType.GitHub:
                Git.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
                var ghAuth = authentication as Github.Authentication;
                ghAuth.DeleteCredentials(operationArguments.TargetUri);
                break;

            case AuthorityType.Bitbucket:
                Git.Trace.WriteLine($"deleting Bitbucket credentials for '{operationArguments.TargetUri}'.");
                var bbAuth = authentication as Bitbucket.Authentication;
                bbAuth.DeleteCredentials(operationArguments.TargetUri, operationArguments.CredUsername);
                break;
            }
        }
        public static bool TryReadString(Program program, OperationArguments operationArguments, KeyType key, out string value)
        {
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            if (program.ConfigurationKeys.TryGetValue(key, out string configKey)
                | program.EnvironmentKeys.TryGetValue(key, out string environKey))
            {
                var envars = operationArguments.EnvironmentVariables;

                // Look for an entry in the environment variables.
                string localVal;
                if (!string.IsNullOrWhiteSpace(environKey) &&
                    envars.TryGetValue(environKey, out localVal) &&
                    !string.IsNullOrWhiteSpace(localVal))
                {
                    value = localVal;
                    return(true);
                }

                Git.Configuration config = operationArguments.GitConfiguration;

                // Look for an entry in the git config.
                Git.Configuration.Entry entry;
                if (!string.IsNullOrWhiteSpace(configKey) &&
                    config.TryGetEntry(Program.ConfigPrefix, operationArguments.QueryUri, configKey, out entry) &&
                    !string.IsNullOrWhiteSpace(entry.Value))
                {
                    value = entry.Value;
                    return(true);
                }
            }

            value = null;
            return(false);
        }
Exemplo n.º 15
0
        internal void Erase()
        {
            // parse the operations arguments from stdin (this is how git sends commands)
            // see: https://www.kernel.org/pub/software/scm/git/docs/technical/api-credentials.html
            // see: https://www.kernel.org/pub/software/scm/git/docs/git-credential.html
            using (var stdin = InStream)
            {
                OperationArguments operationArguments = new OperationArguments(stdin);

                Debug.Assert(operationArguments != null, "The operationArguments is null");
                Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

                LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                if (operationArguments.PreserveCredentials)
                {
                    Git.Trace.WriteLine($"{KeyTypeName(KeyType.PreserveCredentials)} = true, canceling erase request.");
                    return;
                }

                DeleteCredentials(operationArguments);
            }
        }
 internal void EnableTraceLogging(OperationArguments operationArguments)
 => _enableTraceLogging(this, operationArguments);
Exemplo n.º 17
0
        private static void Delete()
        {
            Trace.WriteLine("Program::Erase");

            string[] args = Environment.GetCommandLineArgs();

            if (args.Length < 3)
            {
                goto error_parse;
            }

            string url = args[2];
            Uri    uri = null;

            if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
            {
                if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
                {
                    goto error_parse;
                }
            }
            else
            {
                url = String.Format("{0}://{1}", Uri.UriSchemeHttps, url);
                if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
                {
                    goto error_parse;
                }
            }

            var stdin = Console.OpenStandardInput();
            OperationArguments operationArguments = new OperationArguments(stdin);

            operationArguments.QueryUri = uri;

            LoadOperationArguments(operationArguments);

            BaseAuthentication authentication = CreateAuthentication(operationArguments);

            switch (operationArguments.Authority)
            {
            default:
            case AuthorityType.Basic:
                Trace.WriteLine("   deleting basic credentials");
                authentication.DeleteCredentials(operationArguments.TargetUri);
                break;

            case AuthorityType.AzureDirectory:
            case AuthorityType.MicrosoftAccount:
                Trace.WriteLine("   deleting VSTS credentials");
                BaseVstsAuthentication vstsAuth = authentication as BaseVstsAuthentication;
                vstsAuth.DeleteCredentials(operationArguments.TargetUri);
                // call delete twice to purge any stored ADA tokens
                vstsAuth.DeleteCredentials(operationArguments.TargetUri);
                break;

            case AuthorityType.GitHub:
                Trace.WriteLine("   deleting GitHub credentials");
                GitHubAuthentication ghAuth = authentication as GitHubAuthentication;
                ghAuth.DeleteCredentials(operationArguments.TargetUri);
                break;
            }

            return;

error_parse:
            Console.Error.WriteLine("Fatal: unable to parse target URI.");
        }
        private static void Askpass(string[] args)
        {
            if (args == null || args.Length == 0)
                throw new ArgumentException("Arguments cannot be empty.");

            Match match;
            if ((match = AskPasswordRegex.Match(args[0])).Success
                || (match = AskPassphraseRegex.Match(args[0])).Success)
            {
                Git.Trace.WriteLine("querying for passphrase key.");

                if (match.Groups.Count < 2)
                    throw new ArgumentException("Unable to understand command.");

                string request = match.Groups[0].Value;
                string resource = match.Groups[1].Value;

                Git.Trace.WriteLine($"open dialog for '{resource}'.");

                System.Windows.Application application = new System.Windows.Application();
                Gui.PassphraseWindow prompt = new Gui.PassphraseWindow(resource);
                application.Run(prompt);

                if (!prompt.Cancelled && !string.IsNullOrEmpty(prompt.Passphrase))
                {
                    string passphase = prompt.Passphrase;

                    Git.Trace.WriteLine("passphase acquired.");

                    Console.Out.Write(passphase + "\n");
                    return;
                }

                Git.Trace.WriteLine("failed to interactively acquire credentials.");
            }

            if ((match = AskCredentialRegex.Match(args[0])).Success)
            {
                Git.Trace.WriteLine("querying for HTTPS credentials.");

                if (match.Groups.Count < 3)
                    throw new ArgumentException("Unable to understand command.");

                string seeking = match.Groups[1].Value;
                string targetUrl = match.Groups[2].Value;

                Uri targetUri;

                if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri))
                {
                    Git.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'.");

                    // config stored credentials come in the format of <username>[:<password>]@<url> with password being optional
                    // scheme terminator is actually "://" so we need adjust to get the correct index
                    int schemeTerminator = targetUrl.IndexOf(':') + 2;
                    int credentialTerminator = targetUrl.IndexOf('@', schemeTerminator + 1);

                    if (credentialTerminator > 0)
                    {
                        Git.Trace.WriteLine("'@' symbol found in URL, assuming credential prefix.");

                        string username = null;
                        string password = null;

                        int passwordTerminator = targetUrl.IndexOf(':', schemeTerminator + 1);

                        if (passwordTerminator > 0)
                        {
                            Git.Trace.WriteLine("':' symbol found in URL, assuming credential prefix contains password.");

                            username = targetUrl.Substring(schemeTerminator + 1, passwordTerminator - schemeTerminator - 1);
                            password = targetUrl.Substring(passwordTerminator + 1, credentialTerminator - passwordTerminator + 1);

                            // print the password if it sought
                            if (seeking.Equals("Password", StringComparison.OrdinalIgnoreCase))
                            {
                                Console.Out.Write(password + '\n');
                                return;
                            }
                        }
                        else
                        {
                            username = targetUrl.Substring(schemeTerminator + 1, credentialTerminator - schemeTerminator - 1);
                        }

                        // print the username if it sought
                        if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase))
                        {
                            Console.Out.Write(username + '\n');
                            return;
                        }
                    }

                    // create a target Url with the credential portion stripped, because Git doesn't report hosts with credentials
                    targetUrl = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}://{1}", targetUri.Scheme, targetUri.Host);

                    // retain the port if specified
                    if (!targetUri.IsDefaultPort)
                    {
                        targetUrl += $":{targetUri.Port}";
                    }

                    // retain the path if specified
                    if (!String.IsNullOrWhiteSpace(targetUri.LocalPath))
                    {
                        targetUrl += targetUri.LocalPath;
                    }

                    if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri))
                    {
                        Git.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'.");

                        OperationArguments operationArguments = new OperationArguments(targetUri);

                        // load up the operation arguments, enable tracing, and query for credentials
                        LoadOperationArguments(operationArguments);
                        EnableTraceLogging(operationArguments);

                        if (QueryCredentials(operationArguments))
                        {
                            if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase))
                            {
                                Git.Trace.WriteLine($"username for '{targetUrl}' asked for and found.");

                                Console.Out.Write(operationArguments.CredUsername + '\n');
                                return;
                            }

                            if (seeking.Equals("Password", StringComparison.OrdinalIgnoreCase))
                            {
                                Git.Trace.WriteLine($"password for '{targetUrl}' asked for and found.");

                                Console.Out.Write(operationArguments.CredPassword + '\n');
                                return;
                            }
                        }
                    }
                    else
                    {
                        Git.Trace.WriteLine("error: unable to parse target URL.");
                    }
                }
                else
                {
                    Git.Trace.WriteLine("error: unable to parse supplied URL.");
                }

                Git.Trace.WriteLine($"failed to detect {seeking} in target URL.");
            }

            Git.Trace.WriteLine("failed to acquire credentials.");
        }
        internal void Askpass(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                throw new ArgumentException("Arguments cannot be empty.");
            }

            Gui.UserPromptKind promptKind = Gui.UserPromptKind.SshPassphrase;

            Match match;

            if ((match = AskPasswordRegex.Match(args[0])).Success)
            {
                promptKind = Gui.UserPromptKind.CredentialsPassword;
            }
            else if ((match = AskPassphraseRegex.Match(args[0])).Success)
            {
                promptKind = Gui.UserPromptKind.SshPassphrase;
            }

            if (match.Success)
            {
                _context.Trace.WriteLine("querying for passphrase key.");

                if (match.Groups.Count < 2)
                {
                    throw new ArgumentException("Unable to understand command.");
                }

                // string request = match.Groups[0].Value;
                string resource = match.Groups[1].Value;

                _context.Trace.WriteLine($"open dialog for '{resource}'.");

                System.Windows.Application application = new System.Windows.Application();
                Gui.UserPromptDialog       prompt      = new Gui.UserPromptDialog(promptKind, resource);
                application.Run(prompt);

                if (!prompt.Failed && !string.IsNullOrEmpty(prompt.Response))
                {
                    string passphase = prompt.Response;

                    _context.Trace.WriteLine("passphase acquired.");

                    Out.Write(passphase + "\n");
                    return;
                }

                Die("failed to interactively acquire credentials.");
            }

            if ((match = AskCredentialRegex.Match(args[0])).Success)
            {
                _context.Trace.WriteLine("querying for basic credentials.");

                if (match.Groups.Count < 3)
                {
                    throw new ArgumentException("Unable to understand command.");
                }

                string seeking   = match.Groups[1].Value;
                string targetUrl = match.Groups[2].Value;

                string username  = string.Empty;
                string password  = string.Empty;
                Uri    targetUri = null;

                // Since we're looking for HTTP(s) credentials, we can use NetFx `Uri` class.
                if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri))
                {
                    _context.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'.");

                    if (TryParseUrlCredentials(targetUrl, out username, out password))
                    {
                        if (password != null &&
                            seeking.Equals("Password", StringComparison.OrdinalIgnoreCase))
                        {
                            Out.Write(password + '\n');
                            return;
                        }

                        // print the username if it sought
                        if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase))
                        {
                            Out.Write(username + '\n');
                            return;
                        }
                    }

                    // create a target Url with the credential portion stripped, because Git doesn't
                    // report hosts with credentials
                    targetUrl = targetUri.Scheme + "://";

                    // Add the username@ portion of the url if it exists
                    if (username != null)
                    {
                        targetUrl += Uri.EscapeDataString(username);

                        targetUrl += '@';
                    }

                    targetUrl += targetUri.Host;

                    // retain the port if specified
                    if (!targetUri.IsDefaultPort)
                    {
                        targetUrl += $":{targetUri.Port}";
                    }

                    // retain the path if specified
                    if (!string.IsNullOrWhiteSpace(targetUri.LocalPath))
                    {
                        targetUrl += targetUri.LocalPath;
                    }

                    if (Uri.TryCreate(targetUrl, UriKind.Absolute, out targetUri))
                    {
                        _context.Trace.WriteLine($"success parsing URL, targetUri = '{targetUri}'.");

                        OperationArguments operationArguments = new OperationArguments(_context, targetUri);
                        operationArguments.SetCredentials(username ?? string.Empty, password ?? string.Empty);

                        // Load up the operation arguments, enable tracing, and query for credentials.
                        Task.Run(async() =>
                        {
                            await LoadOperationArguments(operationArguments);
                            EnableTraceLogging(operationArguments);

                            Credential credentials;
                            if ((credentials = await QueryCredentials(operationArguments)) != null)
                            {
                                if (seeking.Equals("Username", StringComparison.OrdinalIgnoreCase))
                                {
                                    _context.Trace.WriteLine($"username for '{targetUrl}' asked for and found.");

                                    Out.Write(credentials.Username + '\n');
                                    return;
                                }

                                if (seeking.Equals("Password", StringComparison.OrdinalIgnoreCase))
                                {
                                    _context.Trace.WriteLine($"password for '{targetUrl}' asked for and found.");

                                    Out.Write(credentials.Password + '\n');
                                    return;
                                }
                            }
                            else
                            {
                                _context.Trace.WriteLine($"user cancelled credential dialog.");
                                return;
                            }
                        }).Wait();
                    }
                    else
                    {
                        _context.Trace.WriteLine("error: unable to parse target URL.");
                    }
                }
                else
                {
                    _context.Trace.WriteLine("error: unable to parse supplied URL.");
                }

                Die($"failed to detect {seeking} in target URL.");
            }

            if ((match = AskAuthenticityRegex.Match(args[0])).Success)
            {
                string host        = match.Groups[1].Value;
                string fingerprint = match.Groups[2].Value;

                _context.Trace.WriteLine($"requesting authorization to add {host} ({fingerprint}) to known hosts.");

                System.Windows.Application application = new System.Windows.Application();
                Gui.UserPromptDialog       prompt      = new Gui.UserPromptDialog(host, fingerprint);
                application.Run(prompt);

                if (prompt.Failed)
                {
                    _context.Trace.WriteLine("denied authorization of host.");
                    Out.Write("no\n");
                }
                else
                {
                    _context.Trace.WriteLine("approved authorization of host.");
                    Out.Write("yes\n");
                }

                return;
            }

            Die("failed to acquire credentials.");
        }
        private static void Delete()
        {
            string[] args = Environment.GetCommandLineArgs();

            if (args.Length < 3)
            {
                goto error_parse;
            }

            string url = args[2];
            Uri    uri = null;

            if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
            {
                if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
                {
                    goto error_parse;
                }
            }
            else
            {
                url = String.Format("{0}://{1}", Uri.UriSchemeHttps, url);
                if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
                {
                    goto error_parse;
                }
            }

            using (var stdin = Console.OpenStandardInput())
            {
                OperationArguments operationArguments = new OperationArguments(stdin);
                operationArguments.QueryUri = uri;

                LoadOperationArguments(operationArguments);

                BaseAuthentication authentication = CreateAuthentication(operationArguments);

                switch (operationArguments.Authority)
                {
                default:
                case AuthorityType.Basic:
                    Git.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.AzureDirectory:
                case AuthorityType.MicrosoftAccount:
                    Git.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.GitHub:
                    Git.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
                    break;

                case AuthorityType.Ntlm:
                    Git.Trace.WriteLine($"deleting NTLM credentials for '{operationArguments.TargetUri}'.");
                    break;
                }

                authentication.DeleteCredentials(operationArguments.TargetUri);
            }

            return;

error_parse:
            Die("Unable to parse target URI.");
        }
        public static async Task LoadOperationArguments(Program program, OperationArguments operationArguments)
        {
            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            if (operationArguments.TargetUri == null)
            {
                program.Die("No host information, unable to continue.");
            }

            string value;
            bool?  yesno;

            if (program.TryReadBoolean(operationArguments, KeyType.ConfigNoLocal, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.ConfigNoLocal)} = '{yesno}'.");

                operationArguments.UseConfigLocal = yesno.Value;
            }

            if (program.TryReadBoolean(operationArguments, KeyType.ConfigNoSystem, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.ConfigNoSystem)} = '{yesno}'.");

                operationArguments.UseConfigSystem = yesno.Value;
            }

            // Load/re-load the Git configuration after setting the use local/system config values.
            await operationArguments.LoadConfiguration();

            // If a user-agent has been specified in the environment, set it globally.
            if (program.TryReadString(operationArguments, KeyType.HttpUserAgent, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.HttpUserAgent)} = '{value}'.");

                Global.UserAgent = value;
            }

            // Look for authority settings.
            if (program.TryReadString(operationArguments, KeyType.Authority, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Authority)} = '{value}'.");

                if (Program.ConfigKeyComparer.Equals(value, "MSA") ||
                    Program.ConfigKeyComparer.Equals(value, "Microsoft") ||
                    Program.ConfigKeyComparer.Equals(value, "MicrosoftAccount") ||
                    Program.ConfigKeyComparer.Equals(value, "Live") ||
                    Program.ConfigKeyComparer.Equals(value, "LiveConnect") ||
                    Program.ConfigKeyComparer.Equals(value, "LiveID"))
                {
                    operationArguments.Authority = AuthorityType.MicrosoftAccount;
                }
                else if (Program.ConfigKeyComparer.Equals(value, "AAD") ||
                         Program.ConfigKeyComparer.Equals(value, "Azure") ||
                         Program.ConfigKeyComparer.Equals(value, "AzureDirectory"))
                {
                    operationArguments.Authority = AuthorityType.AzureDirectory;
                }
                else if (Program.ConfigKeyComparer.Equals(value, "Integrated") ||
                         Program.ConfigKeyComparer.Equals(value, "Windows") ||
                         Program.ConfigKeyComparer.Equals(value, "TFS") ||
                         Program.ConfigKeyComparer.Equals(value, "Kerberos") ||
                         Program.ConfigKeyComparer.Equals(value, "NTLM") ||
                         Program.ConfigKeyComparer.Equals(value, "SSO"))
                {
                    operationArguments.Authority = AuthorityType.Ntlm;
                }
                else if (Program.ConfigKeyComparer.Equals(value, "GitHub"))
                {
                    operationArguments.Authority = AuthorityType.GitHub;
                }
                else if (Program.ConfigKeyComparer.Equals(value, "Atlassian") ||
                         Program.ConfigKeyComparer.Equals(value, "Bitbucket"))
                {
                    operationArguments.Authority = AuthorityType.Bitbucket;
                }
                else
                {
                    operationArguments.Authority = AuthorityType.Basic;
                }
            }

            // Look for interactivity config settings.
            if (program.TryReadString(operationArguments, KeyType.Interactive, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Interactive)} = '{value}'.");

                if (Program.ConfigKeyComparer.Equals(value, "always") ||
                    Program.ConfigKeyComparer.Equals(value, "true") ||
                    Program.ConfigKeyComparer.Equals(value, "force"))
                {
                    operationArguments.Interactivity = Interactivity.Always;
                }
                else if (Program.ConfigKeyComparer.Equals(value, "never") ||
                         Program.ConfigKeyComparer.Equals(value, "false"))
                {
                    operationArguments.Interactivity = Interactivity.Never;
                }
            }

            // Look for credential validation config settings.
            if (program.TryReadBoolean(operationArguments, KeyType.Validate, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Validate)} = '{yesno}'.");

                operationArguments.ValidateCredentials = yesno.Value;
            }

            // Look for write log config settings.
            if (program.TryReadBoolean(operationArguments, KeyType.Writelog, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Writelog)} = '{yesno}'.");

                operationArguments.WriteLog = yesno.Value;
            }

            // Look for modal prompt config settings.
            if (program.TryReadBoolean(operationArguments, KeyType.ModalPrompt, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.ModalPrompt)} = '{yesno}'.");

                operationArguments.UseModalUi = yesno.Value;
            }

            // Look for credential preservation config settings.
            if (program.TryReadBoolean(operationArguments, KeyType.PreserveCredentials, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.PreserveCredentials)} = '{yesno}'.");

                operationArguments.PreserveCredentials = yesno.Value;
            }
            else if (operationArguments.EnvironmentVariables.TryGetValue("GCM_PRESERVE_CREDS", out value))
            {
                if (StringComparer.OrdinalIgnoreCase.Equals(value, "true") ||
                    StringComparer.OrdinalIgnoreCase.Equals(value, "yes") ||
                    StringComparer.OrdinalIgnoreCase.Equals(value, "1") ||
                    StringComparer.OrdinalIgnoreCase.Equals(value, "on"))
                {
                    program.Trace.WriteLine($"GCM_PRESERVE_CREDS = '{yesno}'.");

                    operationArguments.PreserveCredentials = true;

                    program.Trace.WriteLine($"WARNING: the 'GCM_PRESERVE_CREDS' variable has been deprecated, use '{ program.KeyTypeName(KeyType.PreserveCredentials) }' instead.");
                }
            }

            // Look for HTTP path usage config settings.
            if (program.TryReadBoolean(operationArguments, KeyType.HttpPath, out yesno))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.HttpPath)} = '{value}'.");

                operationArguments.UseHttpPath = yesno.Value;
            }

            // Look for HTTP proxy config settings.
            if ((operationArguments.TargetUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
                 program.TryReadString(operationArguments, KeyType.HttpsProxy, out value)) ||
                program.TryReadString(operationArguments, KeyType.HttpProxy, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.HttpProxy)} = '{value}'.");

                operationArguments.SetProxy(value);
            }
            // Check environment variables just-in-case.
            else if ((operationArguments.EnvironmentVariables.TryGetValue("GCM_HTTP_PROXY", out value) &&
                      !string.IsNullOrWhiteSpace(value)))
            {
                program.Trace.WriteLine($"GCM_HTTP_PROXY = '{value}'.");

                var keyName = (operationArguments.TargetUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
                    ? "HTTPS_PROXY"
                    : "HTTP_PROXY";
                var warning = $"WARNING: the 'GCM_HTTP_PROXY' variable has been deprecated, use '{ keyName }' instead.";

                program.Trace.WriteLine(warning);
                program.WriteLine(warning);

                operationArguments.SetProxy(value);
            }
            // Check the git-config http.proxy setting just-in-case.
            else
            {
                Git.Configuration.Entry entry;
                if (operationArguments.GitConfiguration.TryGetEntry("http", operationArguments.QueryUri, "proxy", out entry) &&
                    !string.IsNullOrWhiteSpace(entry.Value))
                {
                    program.Trace.WriteLine($"http.proxy = '{entry.Value}'.");

                    operationArguments.SetProxy(entry.Value);
                }
            }

            // Look for custom namespace config settings.
            if (program.TryReadString(operationArguments, KeyType.Namespace, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Namespace)} = '{value}'.");

                operationArguments.CustomNamespace = value;
            }

            // Look for custom token duration settings.
            if (program.TryReadString(operationArguments, KeyType.TokenDuration, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.TokenDuration)} = '{value}'.");

                int hours;
                if (int.TryParse(value, out hours))
                {
                    operationArguments.TokenDuration = TimeSpan.FromHours(hours);
                }
            }

            // Look for custom VSTS scope settings.
            if (program.TryReadString(operationArguments, KeyType.VstsScope, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.VstsScope)} = '{value}'.");

                VstsTokenScope vstsTokenScope = VstsTokenScope.None;

                var scopes = value.Split(TokenScopeSeparatorCharacters.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < scopes.Length; i += 1)
                {
                    scopes[i] = scopes[i].Trim();

                    if (VstsTokenScope.Find(scopes[i], out VstsTokenScope scope))
                    {
                        vstsTokenScope = vstsTokenScope | scope;
                    }
                    else
                    {
                        program.Trace.WriteLine($"Unknown VSTS Token scope: '{scopes[i]}'.");
                    }
                }

                operationArguments.VstsTokenScope = vstsTokenScope;
            }

            // Check for configuration supplied user-info.
            if (program.TryReadString(operationArguments, KeyType.Username, out value))
            {
                program.Trace.WriteLine($"{program.KeyTypeName(KeyType.Username)} = '{value}'.");

                operationArguments.Username = value;
            }
        }
        public static async Task <Credential> QueryCredentials(Program program, OperationArguments operationArguments)
        {
            if (program is null)
            {
                throw new ArgumentNullException(nameof(program));
            }
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }
            if (operationArguments.TargetUri is null)
            {
                var innerException = new NullReferenceException($"{operationArguments.TargetUri} cannot be null.");
                throw new ArgumentException(innerException.Message, nameof(operationArguments), innerException);
            }

            BaseAuthentication authentication = await program.CreateAuthentication(operationArguments);

            Credential credentials = null;

            switch (operationArguments.Authority)
            {
            default:
            case AuthorityType.Basic:
            {
                var basicAuth = authentication as BasicAuthentication;

                // Attempt to get cached credentials or acquire credentials if interactivity is allowed.
                if ((operationArguments.Interactivity != Interactivity.Always &&
                     (credentials = await authentication.GetCredentials(operationArguments.TargetUri)) != null) ||
                    (operationArguments.Interactivity != Interactivity.Never &&
                     (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null))
                {
                    program.Trace.WriteLine("credentials found.");
                    // No need to save the credentials explicitly, as Git will call back
                    // with a store command if the credentials are valid.
                }
                else
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                    program.LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                }
            }
            break;

            case AuthorityType.AzureDirectory:
            {
                var aadAuth    = authentication as VstsAadAuthentication;
                var patOptions = new PersonalAccessTokenOptions()
                {
                    RequireCompactToken = true,
                    TokenDuration       = operationArguments.TokenDuration,
                    TokenScope          = null,
                };

                // Attempt to get cached credentials -> non-interactive logon -> interactive
                // logon note that AAD "credentials" are always scoped access tokens.
                if (((operationArguments.Interactivity != Interactivity.Always &&
                      ((credentials = await aadAuth.GetCredentials(operationArguments.TargetUri)) != null) &&
                      (!operationArguments.ValidateCredentials ||
                       await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) ||
                    (operationArguments.Interactivity != Interactivity.Always &&
                     ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, patOptions)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) ||
                    (operationArguments.Interactivity != Interactivity.Never &&
                     ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                    program.LogEvent($"Azure Directory credentials  for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                }
                else
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                    program.LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                }
            }
            break;

            case AuthorityType.MicrosoftAccount:
            {
                var msaAuth    = authentication as VstsMsaAuthentication;
                var patOptions = new PersonalAccessTokenOptions()
                {
                    RequireCompactToken = true,
                    TokenDuration       = operationArguments.TokenDuration,
                    TokenScope          = null,
                };

                // Attempt to get cached credentials -> interactive logon note that MSA
                // "credentials" are always scoped access tokens.
                if (((operationArguments.Interactivity != Interactivity.Always &&
                      ((credentials = await msaAuth.GetCredentials(operationArguments.TargetUri)) != null) &&
                      (!operationArguments.ValidateCredentials ||
                       await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))) ||
                    (operationArguments.Interactivity != Interactivity.Never &&
                     ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, patOptions)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                    program.LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                }
                else
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                    program.LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                }
            }
            break;

            case AuthorityType.GitHub:
            {
                var ghAuth = authentication as Github.Authentication;

                if ((operationArguments.Interactivity != Interactivity.Always &&
                     ((credentials = await ghAuth.GetCredentials(operationArguments.TargetUri)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))) ||
                    (operationArguments.Interactivity != Interactivity.Never &&
                     ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                    program.LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                }
                else
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                    program.LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                }
            }
            break;

            case AuthorityType.Bitbucket:
            {
                var bbcAuth = authentication as Bitbucket.Authentication;

                if (((operationArguments.Interactivity != Interactivity.Always) &&
                     ((credentials = await bbcAuth.GetCredentials(operationArguments.TargetUri, operationArguments.Username)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null))) ||
                    ((operationArguments.Interactivity != Interactivity.Never) &&
                     ((credentials = await bbcAuth.InteractiveLogon(operationArguments.TargetUri, operationArguments.Username)) != null) &&
                     (!operationArguments.ValidateCredentials ||
                      ((credentials = await bbcAuth.ValidateCredentials(operationArguments.TargetUri, operationArguments.Username, credentials)) != null))))
                {
                    program.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                    // Bitbucket relies on a username + secret, so make sure there is a
                    // username to return.
                    if (operationArguments.Username != null)
                    {
                        credentials = new Credential(operationArguments.Username, credentials.Password);
                    }
                    program.LogEvent($"Bitbucket credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                }
                else
                {
                    program.LogEvent($"Failed to retrieve Bitbucket credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                }
            }
            break;

            case AuthorityType.Ntlm:
            {
                program.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM.");
                credentials = BasicAuthentication.NtlmCredentials;
            }
            break;
            }

            if (credentials != null)
            {
                operationArguments.Credentials = credentials;
            }

            return(credentials);
        }
        private static bool TryReadBoolean(OperationArguments operationArguments, string configKey, string environKey, out bool? value)
        {
            if (ReferenceEquals(operationArguments, null))
                throw new ArgumentNullException(nameof(operationArguments));

            var envars = operationArguments.EnvironmentVariables;

            // look for an entry in the environment variables
            string localVal = null;
            if (!String.IsNullOrWhiteSpace(environKey)
                && envars.TryGetValue(environKey, out localVal)
                && !String.IsNullOrWhiteSpace(localVal))
            {
                goto parse_localval;
            }

            var config = operationArguments.GitConfiguration;

            // look for an entry in the git config
            Configuration.Entry entry;
            if (!String.IsNullOrWhiteSpace(configKey)
                && config.TryGetEntry(ConfigPrefix, operationArguments.QueryUri, configKey, out entry)
                && !String.IsNullOrWhiteSpace(entry.Value))
            {
                goto parse_localval;
            }

            // parse the value into a bool
            parse_localval:

            bool result;
            if (bool.TryParse(localVal, out result))
            {
                value = result;
                return true;
            }
            else
            {
                if (ConfigValueComparer.Equals(localVal, "no"))
                {
                    value = false;
                    return true;
                }
                else if (ConfigValueComparer.Equals(localVal, "yes"))
                {
                    value = true;
                    return true;
                }
            }

            value = null;
            return false;
        }
        private static bool QueryCredentials(OperationArguments operationArguments)
        {
            const string AadMsaAuthFailureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt.";
            const string BasicAuthFaulureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt.";
            const string GitHubAuthFailureMessage = "Logon failed, use ctrl+c to cancel basic credential prompt.";

            if (ReferenceEquals(operationArguments, null))
                throw new ArgumentNullException("operationArguments");
            if (ReferenceEquals(operationArguments.TargetUri, null))
                throw new ArgumentNullException("operationArguments.TargetUri");

            bool credentialsFound = false;
            BaseAuthentication authentication = CreateAuthentication(operationArguments);
            Credential credentials = null;

            switch (operationArguments.Authority)
            {
                default:
                case AuthorityType.Basic:
                    {
                        BasicAuthentication basicAuth = authentication as BasicAuthentication;

                        Task.Run(async () =>
                        {
                            // attempt to get cached creds or acquire creds if interactivity is allowed
                            if ((operationArguments.Interactivity != Interactivity.Always
                                    && (credentials = authentication.GetCredentials(operationArguments.TargetUri)) != null)
                                || (operationArguments.Interactivity != Interactivity.Never
                                    && (credentials = await basicAuth.AcquireCredentials(operationArguments.TargetUri)) != null))
                            {
                                Git.Trace.WriteLine("credentials found.");
                                // set the credentials object
                                // no need to save the credentials explicitly, as Git will call back
                                // with a store command if the credentials are valid.
                                operationArguments.SetCredentials(credentials);
                                credentialsFound = true;
                            }
                            else
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                                Program.WriteLine(BasicAuthFaulureMessage);
                                LogEvent($"Failed to retrieve credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                            }
                        }).Wait();
                    }
                    break;

                case AuthorityType.AzureDirectory:
                    {
                        VstsAadAuthentication aadAuth = authentication as VstsAadAuthentication;

                        Task.Run(async () =>
                        {
                            // attempt to get cached creds -> non-interactive logon -> interactive logon
                            // note that AAD "credentials" are always scoped access tokens
                            if (((operationArguments.Interactivity != Interactivity.Always
                                    && ((credentials = aadAuth.GetCredentials(operationArguments.TargetUri)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                                || (operationArguments.Interactivity != Interactivity.Always
                                        && ((credentials = await aadAuth.NoninteractiveLogon(operationArguments.TargetUri, true)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
                                || (operationArguments.Interactivity != Interactivity.Never
                                    && ((credentials = await aadAuth.InteractiveLogon(operationArguments.TargetUri, true)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await aadAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                                operationArguments.SetCredentials(credentials);
                                credentialsFound = true;
                                LogEvent($"Azure Directory credentials  for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                            }
                            else
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                                Program.WriteLine(AadMsaAuthFailureMessage);
                                LogEvent($"Failed to retrieve Azure Directory credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                            }
                        }).Wait();
                    }
                    break;

                case AuthorityType.MicrosoftAccount:
                    {
                        VstsMsaAuthentication msaAuth = authentication as VstsMsaAuthentication;

                        Task.Run(async () =>
                        {
                            // attempt to get cached creds -> interactive logon
                            // note that MSA "credentials" are always scoped access tokens
                            if (((operationArguments.Interactivity != Interactivity.Always
                                    && ((credentials = msaAuth.GetCredentials(operationArguments.TargetUri)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                                || (operationArguments.Interactivity != Interactivity.Never
                                    && ((credentials = await msaAuth.InteractiveLogon(operationArguments.TargetUri, true)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await msaAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                                operationArguments.SetCredentials(credentials);
                                credentialsFound = true;
                                LogEvent($"Microsoft Live credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                            }
                            else
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                                Program.WriteLine(AadMsaAuthFailureMessage);
                                LogEvent($"Failed to retrieve Microsoft Live credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                            }
                        }).Wait();
                    }
                    break;

                case AuthorityType.GitHub:
                    {
                        GitHubAuthentication ghAuth = authentication as GitHubAuthentication;

                        Task.Run(async () =>
                        {
                            if ((operationArguments.Interactivity != Interactivity.Always
                                    && ((credentials = ghAuth.GetCredentials(operationArguments.TargetUri)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials)))
                                || (operationArguments.Interactivity != Interactivity.Never
                                    && ((credentials = await ghAuth.InteractiveLogon(operationArguments.TargetUri)) != null)
                                    && (!operationArguments.ValidateCredentials
                                        || await ghAuth.ValidateCredentials(operationArguments.TargetUri, credentials))))
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' found.");
                                operationArguments.SetCredentials(credentials);
                                credentialsFound = true;
                                LogEvent($"GitHub credentials for '{operationArguments.TargetUri}' successfully retrieved.", EventLogEntryType.SuccessAudit);
                            }
                            else
                            {
                                Git.Trace.WriteLine($"credentials for '{operationArguments.TargetUri}' not found.");
                                Program.WriteLine(GitHubAuthFailureMessage);
                                LogEvent($"Failed to retrieve GitHub credentials for '{operationArguments.TargetUri}'.", EventLogEntryType.FailureAudit);
                            }
                        }).Wait();
                    }
                    break;

                case AuthorityType.Ntlm:
                    {
                        Git.Trace.WriteLine($"'{operationArguments.TargetUri}' is NTLM.");
                        operationArguments.SetCredentials(BasicAuthentication.NtlmCredentials);
                        credentialsFound = true;
                    }
                    break;
            }

            return credentialsFound;
        }
        private static bool TryReadString(OperationArguments operationArguments, string configKey, string environKey, out string value)
        {
            if (ReferenceEquals(operationArguments, null))
                throw new ArgumentNullException(nameof(operationArguments));

            var envars = operationArguments.EnvironmentVariables;

            // look for an entry in the environment variables
            string localVal;
            if (!String.IsNullOrWhiteSpace(environKey)
                && envars.TryGetValue(environKey, out localVal)
                && !String.IsNullOrWhiteSpace(localVal))
            {
                value = localVal;
                return true;
            }

            var config = operationArguments.GitConfiguration;

            // look for an entry in the git config
            Configuration.Entry entry;
            if (!String.IsNullOrWhiteSpace(configKey)
                && config.TryGetEntry(ConfigPrefix, operationArguments.QueryUri, configKey, out entry)
                && !String.IsNullOrWhiteSpace(entry.Value))
            {
                value = entry.Value;
                return true;
            }

            value = null;
            return false;
        }
        private static BaseAuthentication CreateAuthentication(OperationArguments operationArguments)
        {
            Debug.Assert(operationArguments != null, "The operationArguments is null");
            Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

            var secretsNamespace = operationArguments.CustomNamespace ?? SecretsNamespace;
            var secrets = new SecretStore(secretsNamespace, null, null, Secret.UriToName);
            BaseAuthentication authority = null;

            var basicCredentialCallback = (operationArguments.UseModalUi)
                    ? new AcquireCredentialsDelegate(Program.ModalPromptForCredentials)
                    : new AcquireCredentialsDelegate(Program.BasicCredentialPrompt);

            var githubCredentialCallback = (operationArguments.UseModalUi)
                    ? new GitHubAuthentication.AcquireCredentialsDelegate(GitHub.Authentication.AuthenticationPrompts.CredentialModalPrompt)
                    : new GitHubAuthentication.AcquireCredentialsDelegate(Program.GitHubCredentialPrompt);

            var githubAuthcodeCallback = (operationArguments.UseModalUi)
                    ? new GitHubAuthentication.AcquireAuthenticationCodeDelegate(GitHub.Authentication.AuthenticationPrompts.AuthenticationCodeModalPrompt)
                    : new GitHubAuthentication.AcquireAuthenticationCodeDelegate(Program.GitHubAuthCodePrompt);

            NtlmSupport basicNtlmSupport = NtlmSupport.Auto;

            switch (operationArguments.Authority)
            {
                case AuthorityType.Auto:
                    Git.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");

                    // detect the authority
                    authority = BaseVstsAuthentication.GetAuthentication(operationArguments.TargetUri,
                                                                         VstsCredentialScope,
                                                                         secrets)
                             ?? GitHubAuthentication.GetAuthentication(operationArguments.TargetUri,
                                                                       GitHubCredentialScope,
                                                                       secrets,
                                                                       githubCredentialCallback,
                                                                       githubAuthcodeCallback,
                                                                       null);

                    if (authority != null)
                    {
                        // set the authority type based on the returned value
                        if (authority is VstsMsaAuthentication)
                        {
                            operationArguments.Authority = AuthorityType.MicrosoftAccount;
                            goto case AuthorityType.MicrosoftAccount;
                        }
                        else if (authority is VstsAadAuthentication)
                        {
                            operationArguments.Authority = AuthorityType.AzureDirectory;
                            goto case AuthorityType.AzureDirectory;
                        }
                        else if (authority is GitHubAuthentication)
                        {
                            operationArguments.Authority = AuthorityType.GitHub;
                            goto case AuthorityType.GitHub;
                        }
                    }

                    operationArguments.Authority = AuthorityType.Basic;
                    goto case AuthorityType.Basic;

                case AuthorityType.AzureDirectory:
                    Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");

                    Guid tenantId = Guid.Empty;
                    // return the allocated authority or a generic AAD backed VSTS authentication object
                    return authority ?? new VstsAadAuthentication(Guid.Empty, VstsCredentialScope, secrets);

                case AuthorityType.Basic:
                    // enforce basic authentication only
                    basicNtlmSupport = NtlmSupport.Never;
                    goto default;

                case AuthorityType.GitHub:
                    Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");

                    // return a GitHub authentication object
                    return authority ?? new GitHubAuthentication(GitHubCredentialScope,
                                                                 secrets,
                                                                 githubCredentialCallback,
                                                                 githubAuthcodeCallback,
                                                                 null);

                case AuthorityType.MicrosoftAccount:
                    Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");

                    // return the allocated authority or a generic MSA backed VSTS authentication object
                    return authority ?? new VstsMsaAuthentication(VstsCredentialScope, secrets);

                case AuthorityType.Ntlm:
                    // enforce NTLM authentication only
                    basicNtlmSupport = NtlmSupport.Always;
                    goto default;

                default:
                    Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");

                    // return a generic username + password authentication object
                    return authority ?? new BasicAuthentication(secrets, basicNtlmSupport, basicCredentialCallback, null);
            }
        }
        private static void DeleteCredentials(OperationArguments operationArguments)
        {
            if (ReferenceEquals(operationArguments, null))
                throw new ArgumentNullException("operationArguments");

            BaseAuthentication authentication = CreateAuthentication(operationArguments);

            switch (operationArguments.Authority)
            {
                default:
                case AuthorityType.Basic:
                    Git.Trace.WriteLine($"deleting basic credentials for '{operationArguments.TargetUri}'.");
                    authentication.DeleteCredentials(operationArguments.TargetUri);
                    break;

                case AuthorityType.AzureDirectory:
                case AuthorityType.MicrosoftAccount:
                    Git.Trace.WriteLine($"deleting VSTS credentials for '{operationArguments.TargetUri}'.");
                    BaseVstsAuthentication vstsAuth = authentication as BaseVstsAuthentication;
                    vstsAuth.DeleteCredentials(operationArguments.TargetUri);
                    break;

                case AuthorityType.GitHub:
                    Git.Trace.WriteLine($"deleting GitHub credentials for '{operationArguments.TargetUri}'.");
                    GitHubAuthentication ghAuth = authentication as GitHubAuthentication;
                    ghAuth.DeleteCredentials(operationArguments.TargetUri);
                    break;
            }
        }
        private static void EnableTraceLogging(OperationArguments operationArguments)
        {
            if (operationArguments.WriteLog)
            {
                Git.Trace.WriteLine("trace logging enabled.");

                string gitConfigPath;
                if (Where.GitLocalConfig(out gitConfigPath))
                {
                    Git.Trace.WriteLine($"git local config found at '{gitConfigPath}'.");

                    string gitDirPath = Path.GetDirectoryName(gitConfigPath);

                    if (Directory.Exists(gitDirPath))
                    {
                        EnableTraceLogging(operationArguments, gitDirPath);
                    }
                }
                else if (Where.GitGlobalConfig(out gitConfigPath))
                {
                    Git.Trace.WriteLine($"git global config found at '{gitConfigPath}'.");

                    string homeDirPath = Path.GetDirectoryName(gitConfigPath);

                    if (Directory.Exists(homeDirPath))
                    {
                        EnableTraceLogging(operationArguments, homeDirPath);
                    }
                }
            }
        }
        private static void EnableTraceLogging(OperationArguments operationArguments, string logFilePath)
        {
            const int LogFileMaxLength = 8 * 1024 * 1024; // 8 MB

            string logFileName = Path.Combine(logFilePath, Path.ChangeExtension(ConfigPrefix, ".log"));

            FileInfo logFileInfo = new FileInfo(logFileName);
            if (logFileInfo.Exists && logFileInfo.Length > LogFileMaxLength)
            {
                for (int i = 1; i < Int32.MaxValue; i++)
                {
                    string moveName = String.Format("{0}{1:000}.log", ConfigPrefix, i);
                    string movePath = Path.Combine(logFilePath, moveName);

                    if (!File.Exists(movePath))
                    {
                        logFileInfo.MoveTo(movePath);
                        break;
                    }
                }
            }

            Git.Trace.WriteLine($"trace log destination is '{logFilePath}'.");

            var fileStream = File.Open(logFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
            var listener = new StreamWriter(fileStream, Encoding.UTF8);
            Git.Trace.AddListener(listener);

            // write a small header to help with identifying new log entries
            listener.Write('\n');
            listener.Write($"{DateTime.Now:YYYY.MM.dd HH:mm:ss} Microsoft {Program.Title} version {Version.ToString(3)}\n");
        }
        public static async Task <BaseAuthentication> CreateAuthentication(Program program, OperationArguments operationArguments)
        {
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }
            if (operationArguments.TargetUri is null)
            {
                var innerException = new NullReferenceException($"`{operationArguments.TargetUri}` cannot be null.");
                throw new ArgumentException(innerException.Message, nameof(operationArguments), innerException);
            }

            var secretsNamespace         = operationArguments.CustomNamespace ?? Program.SecretsNamespace;
            BaseAuthentication authority = null;

            var basicCredentialCallback = (operationArguments.UseModalUi)
                    ? new AcquireCredentialsDelegate(program.ModalPromptForCredentials)
                    : new AcquireCredentialsDelegate(program.BasicCredentialPrompt);

            var bitbucketPrompts = new Bitbucket.AuthenticationPrompts(program.Context);

            var bitbucketCredentialCallback = (operationArguments.UseModalUi)
                    ? bitbucketPrompts.CredentialModalPrompt
                    : new Bitbucket.Authentication.AcquireCredentialsDelegate(program.BitbucketCredentialPrompt);

            var bitbucketOauthCallback = (operationArguments.UseModalUi)
                    ? bitbucketPrompts.AuthenticationOAuthModalPrompt
                    : new Bitbucket.Authentication.AcquireAuthenticationOAuthDelegate(program.BitbucketOAuthPrompt);

            var githubPrompts = new Github.AuthenticationPrompts(program.Context);

            var githubCredentialCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireCredentialsDelegate(githubPrompts.CredentialModalPrompt)
                    : new Github.Authentication.AcquireCredentialsDelegate(program.GitHubCredentialPrompt);

            var githubAuthcodeCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireAuthenticationCodeDelegate(githubPrompts.AuthenticationCodeModalPrompt)
                    : new Github.Authentication.AcquireAuthenticationCodeDelegate(program.GitHubAuthCodePrompt);

            NtlmSupport basicNtlmSupport = NtlmSupport.Auto;

            switch (operationArguments.Authority)
            {
            case AuthorityType.Auto:
                program.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");

                // Detect the authority.
                authority = await BaseVstsAuthentication.GetAuthentication(program.Context,
                                                                           operationArguments.TargetUri,
                                                                           Program.VstsCredentialScope,
                                                                           new SecretStore(program.Context, secretsNamespace, BaseVstsAuthentication.UriNameConversion))
                            ?? Github.Authentication.GetAuthentication(program.Context,
                                                                       operationArguments.TargetUri,
                                                                       Program.GitHubCredentialScope,
                                                                       new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
                                                                       githubCredentialCallback,
                                                                       githubAuthcodeCallback,
                                                                       null)
                            ?? Bitbucket.Authentication.GetAuthentication(program.Context,
                                                                          operationArguments.TargetUri,
                                                                          new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                                          bitbucketCredentialCallback,
                                                                          bitbucketOauthCallback);

                if (authority != null)
                {
                    // Set the authority type based on the returned value.
                    if (authority is VstsMsaAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.MicrosoftAccount;
                        goto case AuthorityType.MicrosoftAccount;
                    }
                    else if (authority is VstsAadAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.AzureDirectory;
                        goto case AuthorityType.AzureDirectory;
                    }
                    else if (authority is Github.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.GitHub;
                        goto case AuthorityType.GitHub;
                    }
                    else if (authority is Bitbucket.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.Bitbucket;
                        goto case AuthorityType.Bitbucket;
                    }
                }
                goto default;

            case AuthorityType.AzureDirectory:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");

                Guid tenantId = Guid.Empty;

                // Get the identity of the tenant.
                var result = await BaseVstsAuthentication.DetectAuthority(program.Context, operationArguments.TargetUri);

                if (result.HasValue)
                {
                    tenantId = result.Value;
                }

                // Return the allocated authority or a generic AAD backed VSTS authentication object.
                return(authority ?? new VstsAadAuthentication(program.Context,
                                                              tenantId,
                                                              operationArguments.VstsTokenScope,
                                                              new SecretStore(program.Context, secretsNamespace, VstsAadAuthentication.UriNameConversion)));

            case AuthorityType.Basic:
                // Enforce basic authentication only.
                basicNtlmSupport = NtlmSupport.Never;
                goto default;

            case AuthorityType.GitHub:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");

                // Return a GitHub authentication object.
                return(authority ?? new Github.Authentication(program.Context,
                                                              operationArguments.TargetUri,
                                                              Program.GitHubCredentialScope,
                                                              new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
                                                              githubCredentialCallback,
                                                              githubAuthcodeCallback,
                                                              null));

            case AuthorityType.Bitbucket:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}'  is Bitbucket");

                // Return a Bitbucket authentication object.
                return(authority ?? new Bitbucket.Authentication(program.Context,
                                                                 new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                                 bitbucketCredentialCallback,
                                                                 bitbucketOauthCallback));

            case AuthorityType.MicrosoftAccount:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");

                // Return the allocated authority or a generic MSA backed VSTS authentication object.
                return(authority ?? new VstsMsaAuthentication(program.Context,
                                                              operationArguments.VstsTokenScope,
                                                              new SecretStore(program.Context, secretsNamespace, VstsMsaAuthentication.UriNameConversion)));

            case AuthorityType.Ntlm:
                // Enforce NTLM authentication only.
                basicNtlmSupport = NtlmSupport.Always;
                goto default;

            default:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");

                // Return a generic username + password authentication object.
                return(authority ?? new BasicAuthentication(program.Context,
                                                            new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                            basicNtlmSupport,
                                                            basicCredentialCallback,
                                                            null));
            }
        }
 internal void EnableTraceLogging(OperationArguments operationArguments, string logFilePath)
 => _enableTraceLoggingFile(this, operationArguments, logFilePath);
        public static bool TryReadBoolean(Program program, OperationArguments operationArguments, KeyType key, out bool?value)
        {
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }

            if (program.ConfigurationKeys.TryGetValue(key, out string configKey)
                | program.EnvironmentKeys.TryGetValue(key, out string environKey))
            {
                var envars = operationArguments.EnvironmentVariables;

                // Look for an entry in the environment variables.
                string localVal = null;
                if (!string.IsNullOrWhiteSpace(environKey) &&
                    envars.TryGetValue(environKey, out localVal))
                {
                    goto parse_localval;
                }

                var config = operationArguments.GitConfiguration;

                // Look for an entry in the git config.
                Git.Configuration.Entry entry;
                if (!string.IsNullOrWhiteSpace(configKey) &&
                    config.TryGetEntry(Program.ConfigPrefix, operationArguments.QueryUri, configKey, out entry))
                {
                    localVal = entry.Value;
                    goto parse_localval;
                }

                // Parse the value into a bool.
parse_localval:

                // An empty value is unset / should not be there, so treat it as if it isn't.
                if (string.IsNullOrWhiteSpace(localVal))
                {
                    value = null;
                    return(false);
                }

                // Test `localValue` for a Git 'true' equivalent value.
                if (Program.ConfigValueComparer.Equals(localVal, "yes") ||
                    Program.ConfigValueComparer.Equals(localVal, "true") ||
                    Program.ConfigValueComparer.Equals(localVal, "1") ||
                    Program.ConfigValueComparer.Equals(localVal, "on"))
                {
                    value = true;
                    return(true);
                }

                // Test `localValue` for a Git 'false' equivalent value.
                if (Program.ConfigValueComparer.Equals(localVal, "no") ||
                    Program.ConfigValueComparer.Equals(localVal, "false") ||
                    Program.ConfigValueComparer.Equals(localVal, "0") ||
                    Program.ConfigValueComparer.Equals(localVal, "off"))
                {
                    value = false;
                    return(true);
                }
            }

            value = null;
            return(false);
        }
 internal void ReadGitRemoteDetails(OperationArguments operationArguments)
 => _readGitRemoteDetails(this, operationArguments);
Exemplo n.º 34
0
        internal void Config()
        {
            string[] args = Environment.GetCommandLineArgs();

            // Attempt to parse a target URI from the command line arguments.
            if (args.Length < 3 || !Uri.TryCreate(args[2], UriKind.Absolute, out Uri targetUri))
            {
                targetUri = new Uri("file://localhost");
            }

            // Create operation arguments, and load configuration data.
            OperationArguments operationArguments = new OperationArguments(targetUri);

            LoadOperationArguments(operationArguments);
            EnableTraceLogging(operationArguments);

            // Create a set of irrelevant environment variable entries.
            var irrelevantEntries = new HashSet <string>(StringComparer.OrdinalIgnoreCase)
            {
                "ToastSettings"
            };

            // Write out the environment variables.
            WriteLine("Environment Variables:");
            foreach (var entry in operationArguments.EnvironmentVariables)
            {
                // Skip well-known, irrelevant entries.
                if (irrelevantEntries.Contains(entry.Key))
                {
                    continue;
                }

                WriteLine($"  {entry.Key} = {entry.Value}");
            }
            WriteLine();

            // Write out the Git configuration.
            WriteLine("Git Configuration:");
            foreach (var entry in operationArguments.GitConfiguration)
            {
                WriteLine($"  [{entry.Level}] {entry.Key} = {entry.Value}");
            }
            WriteLine();

            // Write out the effective settings for GCM.
            WriteLine($"Effective Manager Configuration for {operationArguments.QueryUri.ToString()}:");
            WriteLine($"  Executable = {AssemblyTitle} v{Version.ToString(4)} ({ExecutablePath})");
            WriteLine($"  Authority = {operationArguments.Authority}");
            WriteLine($"  CustomNamespace = {operationArguments.CustomNamespace}");
            WriteLine($"  Interactivity = {operationArguments.Interactivity}");
            WriteLine($"  PreserveCredentials = {operationArguments.PreserveCredentials}");
            WriteLine($"  QueryUri = {operationArguments.QueryUri}");
            WriteLine($"  TargetUri = {operationArguments.TargetUri}");
            WriteLine($"  TokenDuration = {operationArguments.TokenDuration}");
            WriteLine($"  UseConfigLocal = {operationArguments.UseConfigLocal}");
            WriteLine($"  UseConfigSystem = {operationArguments.UseConfigSystem}");
            WriteLine($"  UseHttpPath = {operationArguments.UseHttpPath}");
            WriteLine($"  UseModalUi = {operationArguments.UseModalUi}");
            WriteLine($"  ValidateCredentials = {operationArguments.ValidateCredentials}");
            WriteLine($"  WriteLog = {operationArguments.WriteLog}");
        }
 internal bool TryReadBoolean(OperationArguments operationArguments, KeyType key, out bool?value)
 => _tryReadBoolean(this, operationArguments, key, out value);
 internal bool TryReadString(OperationArguments operationArguments, KeyType key, out string value)
 => _tryReadString(this, operationArguments, key, out value);
        private static void LoadOperationArguments(OperationArguments operationArguments)
        {
            if (operationArguments.TargetUri == null)
            {
                Die("No host information, unable to continue.");
            }

            string value;
            bool? yesno;

            if (TryReadBoolean(operationArguments, null, EnvironConfigNoLocalKey, out yesno))
            {
                operationArguments.UseConfigLocal = yesno.Value;
            }

            if (TryReadBoolean(operationArguments, null, EnvironConfigNoSystemKey, out yesno))
            {
                operationArguments.UseConfigSystem = yesno.Value;
            }

            // load/re-load the Git configuration after setting the use local/system config values
            operationArguments.LoadConfiguration();

            // if a user-agent has been specified in the environment, set it globally
            if (TryReadString(operationArguments, null, EnvironHttpUserAgent, out value))
            {
                Global.UserAgent = value;
            }

            // look for authority settings
            if (TryReadString(operationArguments, ConfigAuthortyKey, EnvironAuthorityKey, out value))
            {
                Git.Trace.WriteLine($"{ConfigAuthortyKey} = '{value}'.");

                if (ConfigKeyComparer.Equals(value, "MSA")
                        || ConfigKeyComparer.Equals(value, "Microsoft")
                        || ConfigKeyComparer.Equals(value, "MicrosoftAccount")
                        || ConfigKeyComparer.Equals(value, "Live")
                        || ConfigKeyComparer.Equals(value, "LiveConnect")
                        || ConfigKeyComparer.Equals(value, "LiveID"))
                {
                    operationArguments.Authority = AuthorityType.MicrosoftAccount;
                }
                else if (ConfigKeyComparer.Equals(value, "AAD")
                         || ConfigKeyComparer.Equals(value, "Azure")
                         || ConfigKeyComparer.Equals(value, "AzureDirectory"))
                {
                    operationArguments.Authority = AuthorityType.AzureDirectory;
                }
                else if (ConfigKeyComparer.Equals(value, "Integrated")
                         || ConfigKeyComparer.Equals(value, "Windows")
                         || ConfigKeyComparer.Equals(value, "TFS")
                         || ConfigKeyComparer.Equals(value, "Kerberos")
                         || ConfigKeyComparer.Equals(value, "NTLM")
                         || ConfigKeyComparer.Equals(value, "SSO"))
                {
                    operationArguments.Authority = AuthorityType.Ntlm;
                }
                else if (ConfigKeyComparer.Equals(value, "GitHub"))
                {
                    operationArguments.Authority = AuthorityType.GitHub;
                }
                else
                {
                    operationArguments.Authority = AuthorityType.Basic;
                }
            }

            // look for interactivity config settings
            if (TryReadString(operationArguments, ConfigInteractiveKey, EnvironInteractiveKey, out value))
            {
                Git.Trace.WriteLine($"{EnvironInteractiveKey} = '{value}'.");

                if (ConfigKeyComparer.Equals(value, "always")
                    || ConfigKeyComparer.Equals(value, "true")
                    || ConfigKeyComparer.Equals(value, "force"))
                {
                    operationArguments.Interactivity = Interactivity.Always;
                }
                else if (ConfigKeyComparer.Equals(value, "never")
                         || ConfigKeyComparer.Equals(value, "false"))
                {
                    operationArguments.Interactivity = Interactivity.Never;
                }
            }

            // look for credential validation config settings
            if (TryReadBoolean(operationArguments, ConfigValidateKey, EnvironValidateKey, out yesno))
            {
                operationArguments.ValidateCredentials = yesno.Value;
            }

            // look for write log config settings
            if (TryReadBoolean(operationArguments, ConfigWritelogKey, EnvironWritelogKey, out yesno))
            {
                operationArguments.WriteLog = yesno.Value;
            }

            // look for modal prompt config settings
            if (TryReadBoolean(operationArguments, ConfigUseModalPromptKey, EnvironModalPromptKey, out yesno))
            {
                operationArguments.UseModalUi = yesno.Value;
            }

            // look for credential preservation config settings
            if (TryReadBoolean(operationArguments, ConfigPreserveCredentialsKey, EnvironPreserveCredentialsKey, out yesno))
            {
                operationArguments.PreserveCredentials = yesno.Value;
            }

            // look for http path usage config settings
            if (TryReadBoolean(operationArguments, ConfigUseHttpPathKey, null, out yesno))
            {
                operationArguments.UseHttpPath = yesno.Value;
            }

            // look for http proxy config settings
            if (TryReadString(operationArguments, ConfigHttpProxyKey, EnvironHttpProxyKey, out value))
            {
                Git.Trace.WriteLine($"{ConfigHttpProxyKey} = '{value}'.");

                operationArguments.SetProxy(value);
            }
            else
            {
                // check the git-config http.proxy setting just-in-case
                Configuration.Entry entry;
                if (operationArguments.GitConfiguration.TryGetEntry("http", operationArguments.QueryUri, "proxy", out entry)
                    && !String.IsNullOrWhiteSpace(entry.Value))
                {
                    Git.Trace.WriteLine($"http.proxy = '{entry.Value}'.");

                    operationArguments.SetProxy(entry.Value);
                }
            }

            // look for custom namespace config settings
            if (TryReadString(operationArguments, ConfigNamespaceKey, EnvironNamespaceKey, out value))
            {
                Git.Trace.WriteLine($"{ConfigNamespaceKey} = '{value}'.");

                operationArguments.CustomNamespace = value;
            }
        }
        private static void Clear()
        {
            var    args   = Environment.GetCommandLineArgs();
            string url    = null;
            bool   forced = false;

            if (args.Length <= 2)
            {
                if (!StandardInputIsTty)
                {
                    Git.Trace.WriteLine("standard input is not TTY, abandoning prompt.");

                    return;
                }

                Git.Trace.WriteLine("prompting user for url.");

                Program.WriteLine(" Target Url:");
                url = Console.In.ReadLine();
            }
            else
            {
                url = args[2];

                if (args.Length > 3)
                {
                    bool.TryParse(args[3], out forced);
                }
            }

            Uri uri;

            if (Uri.TryCreate(url, UriKind.Absolute, out uri))
            {
                Git.Trace.WriteLine($"converted '{url}' to '{uri.AbsoluteUri}'.");

                OperationArguments operationArguments = new OperationArguments(uri);

                LoadOperationArguments(operationArguments);
                EnableTraceLogging(operationArguments);

                if (operationArguments.PreserveCredentials && !forced)
                {
                    Git.Trace.WriteLine("attempting to delete preserved credentials without force, prompting user for interactivity.");

                    if (!StandardInputIsTty || !StandardErrorIsTty)
                    {
                        Git.Trace.WriteLine("standard input is not TTY, abandoning prompt.");
                        return;
                    }

                    Program.WriteLine(" credentials are protected by perserve flag, clear anyways? [Y]es, [N]o.");

                    ConsoleKeyInfo key;
                    while ((key = Program.ReadKey(true)).Key != ConsoleKey.Escape)
                    {
                        if (key.KeyChar == 'N' || key.KeyChar == 'n')
                        {
                            return;
                        }

                        if (key.KeyChar == 'Y' || key.KeyChar == 'y')
                        {
                            break;
                        }
                    }
                }

                DeleteCredentials(operationArguments);
            }
            else
            {
                Git.Trace.WriteLine($"unable to parse input '{url}'.");
            }
        }
 internal Task <bool> DeleteCredentials(OperationArguments operationArguments)
 => _deleteCredentials(this, operationArguments);