예제 #1
0
        public async Task <OAuth2TokenResult> GetOAuthTokenViaBrowserAsync(Uri targetUri, IEnumerable <string> scopes)
        {
            ThrowIfUserInteractionDisabled();

            var oauthClient = new GitHubOAuth2Client(HttpClient, Context.Settings, targetUri);

            // We require a desktop session to launch the user's default web browser
            if (!Context.SessionManager.IsDesktopSession)
            {
                throw new InvalidOperationException("Browser authentication requires a desktop session");
            }

            var browserOptions = new OAuth2WebBrowserOptions
            {
                SuccessResponseHtml       = GitHubResources.AuthenticationResponseSuccessHtml,
                FailureResponseHtmlFormat = GitHubResources.AuthenticationResponseFailureHtmlFormat
            };
            var browser = new OAuth2SystemWebBrowser(Context.Environment, browserOptions);

            // Write message to the terminal (if any is attached) for some feedback that we're waiting for a web response
            Context.Terminal.WriteLine("info: please complete authentication in your browser...");

            OAuth2AuthorizationCodeResult authCodeResult =
                await oauthClient.GetAuthorizationCodeAsync(scopes, browser, CancellationToken.None);

            return(await oauthClient.GetTokenByAuthorizationCodeAsync(authCodeResult, CancellationToken.None));
        }
예제 #2
0
        public async Task <OAuth2TokenResult> GetOAuthTokenViaDeviceCodeAsync(Uri targetUri, IEnumerable <string> scopes)
        {
            ThrowIfUserInteractionDisabled();

            var oauthClient            = new GitHubOAuth2Client(HttpClient, Context.Settings, targetUri);
            OAuth2DeviceCodeResult dcr = await oauthClient.GetDeviceCodeAsync(scopes, CancellationToken.None);

            // If we have a desktop session show the device code in a dialog
            if (Context.Settings.IsGuiPromptsEnabled && Context.SessionManager.IsDesktopSession &&
                TryFindHelperExecutablePath(out string helperPath))
            {
                var args = new StringBuilder("device");
                args.AppendFormat(" --code {0} ", QuoteCmdArg(dcr.UserCode));
                args.AppendFormat(" --url {0}", QuoteCmdArg(dcr.VerificationUri.ToString()));

                var promptCts = new CancellationTokenSource();
                var tokenCts  = new CancellationTokenSource();

                // Show the dialog with the device code but don't await its closure
                Task promptTask = InvokeHelperAsync(helperPath, args.ToString(), null, promptCts.Token);

                // Start the request for an OAuth token but don't wait
                Task <OAuth2TokenResult> tokenTask = oauthClient.GetTokenByDeviceCodeAsync(dcr, tokenCts.Token);

                Task t = await Task.WhenAny(promptTask, tokenTask);

                // If the dialog was closed the user wishes to cancel the request
                if (t == promptTask)
                {
                    tokenCts.Cancel();
                }

                OAuth2TokenResult tokenResult;
                try
                {
                    tokenResult = await tokenTask;
                }
                catch (OperationCanceledException)
                {
                    throw new Exception("User canceled device code authentication");
                }

                // Close the dialog
                promptCts.Cancel();

                return(tokenResult);
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                string deviceMessage = $"To complete authentication please visit {dcr.VerificationUri} and enter the following code:" +
                                       Environment.NewLine +
                                       dcr.UserCode;
                Context.Terminal.WriteLine(deviceMessage);

                return(await oauthClient.GetTokenByDeviceCodeAsync(dcr, CancellationToken.None));
            }
        }
예제 #3
0
        public async Task <OAuth2TokenResult> GetOAuthTokenAsync(Uri targetUri, IEnumerable <string> scopes)
        {
            ThrowIfUserInteractionDisabled();

            var oauthClient = new GitHubOAuth2Client(HttpClient, Context.Settings, targetUri);

            // If we have a desktop session try authentication using the user's default web browser
            if (Context.SessionManager.IsDesktopSession)
            {
                var browserOptions = new OAuth2WebBrowserOptions
                {
                    SuccessResponseHtml       = GitHubResources.AuthenticationResponseSuccessHtml,
                    FailureResponseHtmlFormat = GitHubResources.AuthenticationResponseFailureHtmlFormat
                };
                var browser = new OAuth2SystemWebBrowser(browserOptions);

                // Write message to the terminal (if any is attached) for some feedback that we're waiting for a web response
                Context.Terminal.WriteLine("info: please complete authentication in your browser...");

                OAuth2AuthorizationCodeResult authCodeResult = await oauthClient.GetAuthorizationCodeAsync(scopes, browser, CancellationToken.None);

                return(await oauthClient.GetTokenByAuthorizationCodeAsync(authCodeResult, CancellationToken.None));
            }
            else
            {
                ThrowIfTerminalPromptsDisabled();

                if (GitHubConstants.IsOAuthDeviceAuthSupported)
                {
                    OAuth2DeviceCodeResult deviceCodeResult = await oauthClient.GetDeviceCodeAsync(scopes, CancellationToken.None);

                    string deviceMessage = $"To complete authentication please visit {deviceCodeResult.VerificationUri} and enter the following code:" +
                                           Environment.NewLine +
                                           deviceCodeResult.UserCode;
                    Context.Terminal.WriteLine(deviceMessage);

                    return(await oauthClient.GetTokenByDeviceCodeAsync(deviceCodeResult, CancellationToken.None));
                }

                // We'd like to try using an OAuth2 flow that does not require a web browser on this device
                // such as the device code flow (RFC 8628) but GitHub's auth stack does not support this.
                throw new NotSupportedException("GitHub OAuth authentication is not supported without an interactive desktop session.");
            }
        }