public InteractionResultStatus Handle(string data)
        {
            var startsWithSpace = data.StartsWith(" ");
            data = data.TrimStart(' ');
            _viewport.Log("> " + data);

            try
            {
                foreach (var interaction in _interactions)
                {
                    string @alias;
                    string text;
                    if (interaction.WillProcess(data, out @alias, out text))
                    {
                        if (startsWithSpace)
                        {
                            _viewport.Clear();
                        }
                        var request = new InteractionRequest(text, CurrentStoryId, data, _viewport.LookupRef, CurrentStoryName);
                        var response = new InteractionResponse(_viewport, (l, s) =>
                            {
                                CurrentStoryId = l;
                                CurrentStoryName = s;
                            }, _sender);
                        var context = new InteractionContext(request, _storage, response);

                        var result = interaction.Handle(context);
                        if (result.Status == InteractionResultStatus.Error)
                        {
                            _viewport.Error(result.OptionalError);
                        }
                        return result.Status;
                    }
                }
            }
            catch (Exception ex)
            {
                _viewport.Error("Error: {0}", ex.Message);
                return InteractionResultStatus.Error;
            }

            _viewport.Error("Unknown command sequence: {0}", data);
            return InteractionResultStatus.Error;
        }
 public InteractionContext(InteractionRequest request, NuclearStorage storage, InteractionResponse response)
 {
     Request = request;
     Storage = storage;
     Response = response;
 }
        public async Task<InteractionResponse> ProcessConsentAsync(ValidatedAuthorizeRequest request, UserConsent consent)
        {
            if (request.PromptMode == Constants.PromptModes.Consent ||
                await _consent.RequiresConsentAsync(request.Client, request.Subject, request.RequestedScopes))
            {
                var response = new InteractionResponse();

                // did user provide consent
                if (consent == null)
                {
                    // user was not yet shown conset screen
                    response.IsConsent = true;
                }
                else
                {
                    request.WasConsentShown = true;

                    // user was shown consent -- did they say yes or no
                    if (consent.WasConsentGranted == false)
                    {
                        // no need to show consent screen again
                        // build access denied error to return to client
                        response.IsError = true;
                        response.Error = new AuthorizeError { 
                            ErrorType = ErrorTypes.Client,
                            Error = Constants.AuthorizeErrors.AccessDenied,
                            ResponseMode = request.ResponseMode,
                            ErrorUri = request.RedirectUri, 
                            State = request.State
                        };
                    }
                    else
                    {
                        // they said yes, set scopes they chose
                        request.ValidatedScopes.SetConsentedScopes(consent.ScopedConsented);

                        if (!request.ValidatedScopes.GrantedScopes.Any())
                        {
                            // they said yes, but didn't pick any scopes
                            // show consent again and provide error message
                            response.IsConsent = true;
                            response.ConsentError = "Must select at least one permission.";
                        }
                        
                        if (request.Client.AllowRememberConsent)
                        {
                            // remember consent
                            var scopes = Enumerable.Empty<string>();
                            if (consent.RememberConsent)
                            {
                                // remember what user actually selected
                                scopes = request.ValidatedScopes.GrantedScopes.Select(x => x.Name);
                            }
                            
                            await _consent.UpdateConsentAsync(request.Client, request.Subject, scopes);
                        }
                    }
                }
                
                return response;
            }

            return new InteractionResponse();
        }
Example #4
0
        /// <inheritdoc />
        public async Task <Result> RespondAsync
        (
            IInteractionCreate?gatewayEvent,
            CancellationToken ct = default
        )
        {
            if (gatewayEvent is null)
            {
                return(Result.FromSuccess());
            }

            if (!gatewayEvent.Data.HasValue)
            {
                return(Result.FromSuccess());
            }

            if (!gatewayEvent.ChannelID.HasValue)
            {
                return(Result.FromSuccess());
            }

            var user = gatewayEvent.User.HasValue
                ? gatewayEvent.User.Value
                : gatewayEvent.Member.HasValue
                    ? gatewayEvent.Member.Value.User.HasValue
                        ? gatewayEvent.Member.Value.User.Value
                        : null
                    : null;

            if (user is null)
            {
                return(Result.FromSuccess());
            }

            // Signal Discord that we'll be handling this one asynchronously
            var response            = new InteractionResponse(InteractionCallbackType.DeferredChannelMessageWithSource);
            var interactionResponse = await _interactionAPI.CreateInteractionResponseAsync
                                      (
                gatewayEvent.ID,
                gatewayEvent.Token,
                response,
                ct
                                      );

            if (!interactionResponse.IsSuccess)
            {
                return(interactionResponse);
            }

            var interactionData = gatewayEvent.Data.Value !;

            interactionData.UnpackInteraction(out var command, out var parameters);

            var context = new InteractionContext
                          (
                gatewayEvent.GuildID,
                gatewayEvent.ChannelID.Value,
                user,
                gatewayEvent.Member,
                gatewayEvent.Token,
                gatewayEvent.ID,
                gatewayEvent.ApplicationID,
                interactionData.Resolved
                          );

            // Provide the created context to any services inside this scope
            _contextInjection.Context = context;

            // Run any user-provided pre execution events
            var preExecution = await _eventCollector.RunPreExecutionEvents(context, ct);

            if (!preExecution.IsSuccess)
            {
                return(preExecution);
            }

            // Run the actual command
            var searchOptions = new TreeSearchOptions(StringComparison.OrdinalIgnoreCase);
            var executeResult = await _commandService.TryExecuteAsync
                                (
                command,
                parameters,
                _services,
                searchOptions : searchOptions,
                ct : ct
                                );

            if (!executeResult.IsSuccess)
            {
                return(Result.FromError(executeResult));
            }

            // Run any user-provided post execution events
            return(await _eventCollector.RunPostExecutionEvents
                   (
                       context,
                       executeResult.Entity,
                       ct
                   ));
        }
        /// <summary>
        /// Processes the consent logic.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="consent">The consent.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException">Invalid PromptMode</exception>
        protected internal virtual async Task <InteractionResponse> ProcessConsentAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.PromptModes.Any() &&
                !request.PromptModes.Contains(OidcConstants.PromptModes.None) &&
                !request.PromptModes.Contains(OidcConstants.PromptModes.Consent))
            {
                Logger.LogError("Invalid prompt mode: {promptMode}", request.PromptModes.ToSpaceSeparatedString());
                throw new ArgumentException("Invalid PromptMode");
            }

            var consentRequired = await Consent.RequiresConsentAsync(request.Subject, request.Client, request.ValidatedResources.ParsedScopes);

            if (consentRequired && request.PromptModes.Contains(OidcConstants.PromptModes.None))
            {
                Logger.LogInformation("Error: prompt=none requested, but consent is required.");

                return(new InteractionResponse
                {
                    Error = OidcConstants.AuthorizeErrors.ConsentRequired
                });
            }

            if (request.PromptModes.Contains(OidcConstants.PromptModes.Consent) || consentRequired)
            {
                var response = new InteractionResponse();

                // did user provide consent
                if (consent == null)
                {
                    // user was not yet shown conset screen
                    response.IsConsent = true;
                    Logger.LogInformation("Showing consent: User has not yet consented");
                }
                else
                {
                    request.WasConsentShown = true;
                    Logger.LogTrace("Consent was shown to user");

                    // user was shown consent -- did they say yes or no
                    if (consent.Granted == false)
                    {
                        // no need to show consent screen again
                        // build error to return to client
                        Logger.LogInformation("Error: User consent result: {error}", consent.Error);

                        var error = consent.Error switch
                        {
                            AuthorizationError.AccountSelectionRequired => OidcConstants.AuthorizeErrors.AccountSelectionRequired,
                            AuthorizationError.ConsentRequired => OidcConstants.AuthorizeErrors.ConsentRequired,
                            AuthorizationError.InteractionRequired => OidcConstants.AuthorizeErrors.InteractionRequired,
                            AuthorizationError.LoginRequired => OidcConstants.AuthorizeErrors.LoginRequired,
                            _ => OidcConstants.AuthorizeErrors.AccessDenied
                        };

                        response.Error            = error;
                        response.ErrorDescription = consent.ErrorDescription;
                    }
                    else
                    {
                        // double check that required scopes are in the list of consented scopes
                        var requiredScopes = request.ValidatedResources.GetRequiredScopeValues();
                        var valid          = requiredScopes.All(x => consent.ScopesValuesConsented.Contains(x));
                        if (valid == false)
                        {
                            response.Error = OidcConstants.AuthorizeErrors.AccessDenied;
                            Logger.LogInformation("Error: User denied consent to required scopes");
                        }
                        else
                        {
                            // they said yes, set scopes they chose
                            request.Description        = consent.Description;
                            request.ValidatedResources = request.ValidatedResources.Filter(consent.ScopesValuesConsented);
                            Logger.LogInformation("User consented to scopes: {scopes}", consent.ScopesValuesConsented);

                            if (request.Client.AllowRememberConsent)
                            {
                                // remember consent
                                var parsedScopes = Enumerable.Empty <ParsedScopeValue>();
                                if (consent.RememberConsent)
                                {
                                    // remember what user actually selected
                                    parsedScopes = request.ValidatedResources.ParsedScopes;
                                    Logger.LogDebug("User indicated to remember consent for scopes: {scopes}", request.ValidatedResources.RawScopeValues);
                                }

                                await Consent.UpdateConsentAsync(request.Subject, request.Client, parsedScopes);
                            }
                        }
                    }
                }

                return(response);
            }

            return(new InteractionResponse());
        }
Example #6
0
        internal async Task <InteractionResponse> ProcessConsentAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (request.PromptMode != null &&
                request.PromptMode != OidcConstants.PromptModes.None &&
                request.PromptMode != OidcConstants.PromptModes.Consent)
            {
                throw new ArgumentException("Invalid PromptMode");
            }

            var consentRequired = await _consent.RequiresConsentAsync(request.Client, request.Subject, request.RequestedScopes);

            if (consentRequired && request.PromptMode == OidcConstants.PromptModes.None)
            {
                _logger.LogInformation("Prompt=none requested, but consent is required.");

                return(new InteractionResponse
                {
                    Error = new AuthorizeError
                    {
                        ErrorType = ErrorTypes.Client,
                        Error = OidcConstants.AuthorizeErrors.ConsentRequired,
                        ResponseMode = request.ResponseMode,
                        ErrorUri = request.RedirectUri,
                        State = request.State
                    }
                });
            }

            if (request.PromptMode == OidcConstants.PromptModes.Consent || consentRequired)
            {
                var response = new InteractionResponse();

                // did user provide consent
                if (consent == null)
                {
                    // user was not yet shown conset screen
                    response.IsConsent = true;
                }
                else
                {
                    request.WasConsentShown = true;

                    // user was shown consent -- did they say yes or no
                    if (consent.Granted == false)
                    {
                        // no need to show consent screen again
                        // build access denied error to return to client
                        response.Error = new AuthorizeError
                        {
                            ErrorType    = ErrorTypes.Client,
                            Error        = OidcConstants.AuthorizeErrors.AccessDenied,
                            ResponseMode = request.ResponseMode,
                            ErrorUri     = request.RedirectUri,
                            State        = request.State
                        };
                    }
                    else
                    {
                        // double check that required scopes are in the list of consented scopes
                        var valid = request.ValidatedScopes.ValidateRequiredScopes(consent.ScopesConsented);
                        if (valid == false)
                        {
                            response.Error = new AuthorizeError
                            {
                                ErrorType    = ErrorTypes.Client,
                                Error        = OidcConstants.AuthorizeErrors.AccessDenied,
                                ResponseMode = request.ResponseMode,
                                ErrorUri     = request.RedirectUri,
                                State        = request.State
                            };
                        }
                        else
                        {
                            // they said yes, set scopes they chose
                            request.ValidatedScopes.SetConsentedScopes(consent.ScopesConsented);

                            if (request.Client.AllowRememberConsent)
                            {
                                // remember consent
                                var scopes = Enumerable.Empty <string>();
                                if (consent.RememberConsent)
                                {
                                    // remember what user actually selected
                                    scopes = request.ValidatedScopes.GrantedScopes.Select(x => x.Name);
                                }

                                await _consent.UpdateConsentAsync(request.Client, request.Subject, scopes);
                            }
                        }
                    }
                }

                return(response);
            }

            return(new InteractionResponse());
        }
Example #7
0
 public static async Task SendInteractionResponseAsync(BaseDiscordClient client, InteractionResponse response,
     IDiscordInteraction interaction, IMessageChannel channel = null, RequestOptions options = null)
 {
     await client.ApiClient.CreateInteractionResponseAsync(response, interaction.Id, interaction.Token, options).ConfigureAwait(false);
 }