Exemplo n.º 1
0
 private Uri GetApiRequestUri(Uri targetUri, string apiUrl)
 {
     if (GitHubHostProvider.IsGitHubDotCom(targetUri))
     {
         return(new Uri($"https://api.github.com/{apiUrl}"));
     }
     else
     {
         // If we're here, it's GitHub Enterprise via a configured authority
         var baseUrl = targetUri.GetLeftPart(UriPartial.Authority);
         return(new Uri(baseUrl + $"/api/v3/{apiUrl}"));
     }
 }
Exemplo n.º 2
0
        private Uri GetApiRequestUri(Uri targetUri, string apiUrl)
        {
            if (GitHubHostProvider.IsGitHubDotCom(targetUri))
            {
                return(new Uri($"https://api.github.com/{apiUrl}"));
            }
            else
            {
                // If we're here, it's GitHub Enterprise via a configured authority
                var baseUrl = targetUri.GetLeftPart(UriPartial.Authority);

                // Check for 'raw.' in the hostname and remove it to get the correct GHE API URL
                baseUrl = Regex.Replace(baseUrl, @"^(https?://)raw\.", "$1", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

                return(new Uri(baseUrl + $"/api/v3/{apiUrl}"));
            }
        }
Exemplo n.º 3
0
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            // If we don't have a desktop session/GUI then we cannot offer browser
            if (!Context.SessionManager.IsDesktopSession)
            {
                modes = modes & ~AuthenticationModes.Browser;
            }

            // We need at least one mode!
            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException(@$ "Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if (modes == AuthenticationModes.All)
                {
                    promptArgs.Append(" --all");
                }
                else
                {
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        promptArgs.Append(" --basic");
                    }
                    if ((modes & AuthenticationModes.Browser) != 0)
                    {
                        promptArgs.Append(" --browser");
                    }
                    if ((modes & AuthenticationModes.Device) != 0)
                    {
                        promptArgs.Append(" --device");
                    }
                    if ((modes & AuthenticationModes.Pat) != 0)
                    {
                        promptArgs.Append(" --pat");
                    }
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", QuoteCmdArg(targetUri.ToString()));
                }
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    promptArgs.AppendFormat(" --username {0}", QuoteCmdArg(userName));
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "pat":
                    if (!resultDict.TryGetValue("pat", out string pat))
                    {
                        throw new Exception("Missing 'pat' in response");
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Pat, new GitCredential(userName, pat)));

                case "browser":
                    return(new AuthenticationPromptResult(AuthenticationModes.Browser));

                case "device":
                    return(new AuthenticationPromptResult(AuthenticationModes.Device));

                case "basic":
                    if (!resultDict.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Basic, new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Basic, new GitCredential(userName, password)));

                case AuthenticationModes.Browser:
                    return(new AuthenticationPromptResult(AuthenticationModes.Browser));

                case AuthenticationModes.Device:
                    return(new AuthenticationPromptResult(AuthenticationModes.Device));

                case AuthenticationModes.Pat:
                    Context.Terminal.WriteLine("Enter GitHub personal access token for '{0}'...", targetUri);
                    string pat = Context.Terminal.PromptSecret("Token");
                    return(new AuthenticationPromptResult(
                               AuthenticationModes.Pat, new GitCredential(userName, pat)));

                case AuthenticationModes.None:
                    throw new ArgumentOutOfRangeException(nameof(modes), @$ "At least one {nameof(AuthenticationModes)} must be supplied");

                default:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle);

                    TerminalMenuItem browserItem = null;
                    TerminalMenuItem deviceItem  = null;
                    TerminalMenuItem basicItem   = null;
                    TerminalMenuItem patItem     = null;

                    if ((modes & AuthenticationModes.Browser) != 0)
                    {
                        browserItem = menu.Add("Web browser");
                    }
                    if ((modes & AuthenticationModes.Device) != 0)
                    {
                        deviceItem = menu.Add("Device code");
                    }
                    if ((modes & AuthenticationModes.Pat) != 0)
                    {
                        patItem = menu.Add("Personal access token");
                    }
                    if ((modes & AuthenticationModes.Basic) != 0)
                    {
                        basicItem = menu.Add("Username/password");
                    }

                    // Default to the 'first' choice in the menu
                    TerminalMenuItem choice = menu.Show(0);

                    if (choice == browserItem)
                    {
                        goto case AuthenticationModes.Browser;
                    }
                    if (choice == deviceItem)
                    {
                        goto case AuthenticationModes.Device;
                    }
                    if (choice == basicItem)
                    {
                        goto case AuthenticationModes.Basic;
                    }
                    if (choice == patItem)
                    {
                        goto case AuthenticationModes.Pat;
                    }

                    throw new Exception();
                }
            }
        }
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, string userName, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException($"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    promptArgs.Append(" --basic");
                }
                if ((modes & AuthenticationModes.OAuth) != 0)
                {
                    promptArgs.Append(" --oauth");
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", targetUri);
                }
                if (!string.IsNullOrWhiteSpace(userName))
                {
                    promptArgs.AppendFormat("--username {0}", userName);
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "oauth":
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case "basic":
                    if (!resultDict.TryGetValue("username", out userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic | AuthenticationModes.OAuth:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle)
                    {
                        new TerminalMenuItem(1, "Web browser", isDefault: true),
                        new TerminalMenuItem(2, "Username/password")
                    };

                    int option = menu.Show();

                    if (option == 1)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (option == 2)
                    {
                        goto case AuthenticationModes.Basic;
                    }

                    throw new Exception();

                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);

                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        userName = Context.Terminal.Prompt("Username");
                    }
                    else
                    {
                        Context.Terminal.WriteLine("Username: {0}", userName);
                    }

                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                default:
                    throw new ArgumentOutOfRangeException(nameof(modes), $"Unknown {nameof(AuthenticationModes)} value");
                }
            }
        }
Exemplo n.º 5
0
        public async Task <AuthenticationPromptResult> GetAuthenticationAsync(Uri targetUri, AuthenticationModes modes)
        {
            ThrowIfUserInteractionDisabled();

            // If the GitHub auth stack doesn't support flows such as RFC 8628 and we do not have
            // an interactive desktop session, we cannot offer OAuth authentication.
            if ((modes & AuthenticationModes.OAuth) != 0 &&
                !Context.SessionManager.IsDesktopSession &&
                !GitHubConstants.IsOAuthDeviceAuthSupported)
            {
                Context.Trace.WriteLine("Ignoring OAuth authentication mode because we are not in an interactive desktop session. GitHub does not support RFC 8628.");

                modes &= ~AuthenticationModes.OAuth;
            }

            if (modes == AuthenticationModes.None)
            {
                throw new ArgumentException($"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
            }

            if (TryFindHelperExecutablePath(out string helperPath))
            {
                var promptArgs = new StringBuilder("prompt");
                if ((modes & AuthenticationModes.Basic) != 0)
                {
                    promptArgs.Append(" --basic");
                }
                if ((modes & AuthenticationModes.OAuth) != 0)
                {
                    promptArgs.Append(" --oauth");
                }
                if (!GitHubHostProvider.IsGitHubDotCom(targetUri))
                {
                    promptArgs.AppendFormat(" --enterprise-url {0}", targetUri.ToString());
                }

                IDictionary <string, string> resultDict = await InvokeHelperAsync(helperPath, promptArgs.ToString(), null);

                if (!resultDict.TryGetValue("mode", out string responseMode))
                {
                    throw new Exception("Missing 'mode' in response");
                }

                switch (responseMode.ToLowerInvariant())
                {
                case "oauth":
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                case "basic":
                    if (!resultDict.TryGetValue("username", out string userName))
                    {
                        throw new Exception("Missing 'username' in response");
                    }

                    if (!resultDict.TryGetValue("password", out string password))
                    {
                        throw new Exception("Missing 'password' in response");
                    }

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                default:
                    throw new Exception($"Unknown mode value in response '{responseMode}'");
                }
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                switch (modes)
                {
                case AuthenticationModes.Basic | AuthenticationModes.OAuth:
                    var menuTitle = $"Select an authentication method for '{targetUri}'";
                    var menu      = new TerminalMenu(Context.Terminal, menuTitle)
                    {
                        new TerminalMenuItem(1, "Web browser"),
                        new TerminalMenuItem(2, "Username/password", true)
                    };

                    int option = menu.Show();

                    if (option == 1)
                    {
                        goto case AuthenticationModes.OAuth;
                    }
                    if (option == 2)
                    {
                        goto case AuthenticationModes.Basic;
                    }

                    throw new Exception();

                case AuthenticationModes.Basic:
                    Context.Terminal.WriteLine("Enter GitHub credentials for '{0}'...", targetUri);
                    string userName = Context.Terminal.Prompt("Username");
                    string password = Context.Terminal.PromptSecret("Password");

                    return(new AuthenticationPromptResult(new GitCredential(userName, password)));

                case AuthenticationModes.OAuth:
                    return(new AuthenticationPromptResult(AuthenticationModes.OAuth));

                default:
                    throw new ArgumentOutOfRangeException(nameof(modes), $"Unknown {nameof(AuthenticationModes)} value");
                }
            }
        }