Skip to content

Commit 7c27b9b

Browse files
committed
feat(discord): attach a snowflake nonce to outgoing messages
1 parent ff3aad0 commit 7c27b9b

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

src/discord/rest/messages.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,24 @@ pub(super) fn message_request_body(
316316
message_request_body_with_tts(content, reply_to, attachments, false)
317317
}
318318

319+
/// The official client tags every message create with a snowflake nonce. Its
320+
/// absence is a self-bot signal.
321+
fn generate_nonce() -> String {
322+
const DISCORD_EPOCH_MS: u64 = 1_420_070_400_000;
323+
let now_ms = std::time::SystemTime::now()
324+
.duration_since(std::time::UNIX_EPOCH)
325+
.map(|elapsed| elapsed.as_millis() as u64)
326+
.unwrap_or(DISCORD_EPOCH_MS);
327+
(now_ms.saturating_sub(DISCORD_EPOCH_MS) << 22).to_string()
328+
}
329+
319330
pub(super) fn message_request_body_with_tts(
320331
content: &str,
321332
reply_to: Option<ReplyReference>,
322333
attachments: &[MessageAttachmentUpload],
323334
tts: bool,
324335
) -> Value {
325-
let mut body = json!({ "content": content });
336+
let mut body = json!({ "content": content, "nonce": generate_nonce() });
326337
if tts {
327338
body["tts"] = Value::Bool(true);
328339
}

src/discord/rest/tests.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ fn validates_attachment_only_message_payload() {
7777
assert_eq!(body["attachments"][0]["filename"], "cat.png");
7878
}
7979

80+
#[test]
81+
fn message_request_body_carries_snowflake_nonce() {
82+
let body = message_request_body("hi", None, &[]);
83+
let nonce = body["nonce"].as_str().expect("nonce is a string");
84+
assert!(nonce.parse::<u64>().is_ok(), "nonce must be a snowflake");
85+
}
86+
8087
#[test]
8188
fn message_request_body_suppresses_reply_ping_when_disabled() {
8289
let body = message_request_body(

0 commit comments

Comments
 (0)