Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Easy bypass for Defer 3 Second clock sync issue #2900

Closed
mcmonkey4eva opened this issue Apr 9, 2024 · 5 comments · Fixed by #2932
Closed

Request: Easy bypass for Defer 3 Second clock sync issue #2900

mcmonkey4eva opened this issue Apr 9, 2024 · 5 comments · Fixed by #2932

Comments

@mcmonkey4eva
Copy link

mcmonkey4eva commented Apr 9, 2024

The Issue

This code here:

public static bool CanSendResponse(IDiscordInteraction interaction)
{
return (DateTime.UtcNow - interaction.CreatedAt).TotalSeconds < ResponseTimeLimit;
}

wherein ResponseTimeLimit = 3.0

Is triggered when trying to DeferAsync, and throws an exception if it's false.

This means that the end system clock must be exactly in sync with Discord's server clocks*, otherwise it will misbehave and throw invalid exceptions.
*(If we assume latency of ~1 second from network travel and initial processing, the local system clock only needs to be 2 seconds delayed for this call to be a guaranteed reject every time)

While of course we all dream of running services in datacenters with perfect atomic clock sync, in reality bots are running wherever, even eg on a home computer (that's where I run while testing my bot for example), and in real world applications, a few seconds of offset of the system clock is very normal.

The Proposed Solution

In general I disagree with the idea that this check should be made at all (should let the Discord remote server respond with a refusal if it's too late)*, however I'd be more than happy with just a way to manually disable the check that I would personally be using at least in any dev environment. If I can just DeferAsync(unchecked: true), or set DiscordSocketConfig.NoDeferTimeCheck = true or anything like that, that would suffice.

*(Noting as well that eg if the delay is 2.9 seconds, the check will pass and send along... and then after network latency, Discord will end up rejecting it anyway, ie we already rely on Discord's servers handling appropriate rejections here)

The other valid solution here is to reformulate the check to base the comparison relative to when the interaction was received by Discord.Net rather than relative to Discord's clocks, as that will work as-expected for any/all cases as long as local system clock doesn't jump during processing (can use Environment.TickCount64 to ensure even that case is not mishandled).

@Anu6is
Copy link
Contributor

Anu6is commented Apr 10, 2024

In general I disagree with the idea that this check should be made at all

Agreed, I really don't get why this is being done

@Misha-133
Copy link
Member

This could be made into a bool switch in the DiscordConfig. Feel free to open a PR

@WhyNot180
Copy link
Contributor

Should this be done just for DeferAsync or the other async responses as well?

@mcmonkey4eva
Copy link
Author

Anywhere that extremely tight 3 second time limit defined in CanSendResponse is used.

The 15 minute time limit defined by CanRespondOrFollowup is arguably similar in being more-risk-than-reward for having it there, but is much less likely to cause any issues, as it's much less common for a system clock to be that far off.

@spooksbit
Copy link

What should become of UseInteractionSnowflakeDate that currently exists on DiscordConfig?

/// <summary>
/// Gets or sets whether or not the internal expiration check uses the system date
/// + snowflake date to check if an interaction can be responded to.
/// </summary>
/// <remarks>
/// If set to <see langword="false"/> then the CreatedAt property in an interaction
/// will be set to when it was received instead of the snowflakes date.
/// <br/>
/// <b>This will still require a stable clock on your system.</b>
/// </remarks>
public bool UseInteractionSnowflakeDate { get; set; } = true;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants