Added Intents.None, partial support for selfbot, required changes
This commit is contained in:
parent
4228cd8f52
commit
3a3af635c6
8 changed files with 137 additions and 33 deletions
|
@ -1,5 +1,7 @@
|
||||||
# discord-deno
|
# discord-deno
|
||||||
|
|
||||||
|
![banner](banner.png)
|
||||||
|
|
||||||
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
|
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
|
||||||
|
|
||||||
**An easy to use Discord API Library for Deno.**
|
**An easy to use Discord API Library for Deno.**
|
||||||
|
@ -36,16 +38,19 @@ import { Client, Message, Intents } from 'https://raw.githubusercontent.com/disc
|
||||||
|
|
||||||
const client = new Client()
|
const client = new Client()
|
||||||
|
|
||||||
|
// Listen for event when client is ready (Identified through gateway / Resumed)
|
||||||
client.on('ready', () => {
|
client.on('ready', () => {
|
||||||
console.log(`Ready! User: ${client.user?.tag}`)
|
console.log(`Ready! User: ${client.user?.tag}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Listen for event whenever a Message is sent
|
||||||
client.on('messageCreate', (msg: Message): void => {
|
client.on('messageCreate', (msg: Message): void => {
|
||||||
if (msg.content === '!ping') {
|
if (msg.content === '!ping') {
|
||||||
msg.channel.send(`Pong! WS Ping: ${client.ping}`)
|
msg.channel.send(`Pong! WS Ping: ${client.ping}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Connect to gateway
|
||||||
// Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers)
|
// Replace with your bot's token and intents (Intents.All, Intents.Presence, Intents.GuildMembers)
|
||||||
client.connect('super secret token comes here', Intents.All)
|
client.connect('super secret token comes here', Intents.All)
|
||||||
```
|
```
|
||||||
|
|
|
@ -21,8 +21,8 @@ if(!token) {
|
||||||
Deno.exit();
|
Deno.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const intents = prompt("Input Intents (0 = All, 1 = Presence, 2 = Server Members):");
|
const intents = prompt("Input Intents (0 = All, 1 = Presence, 2 = Server Members, 3 = None):");
|
||||||
if(!intents || !["0", "1", "2"].includes(intents)) {
|
if(!intents || !["0", "1", "2", "3"].includes(intents)) {
|
||||||
console.log("No intents provided");
|
console.log("No intents provided");
|
||||||
Deno.exit();
|
Deno.exit();
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,10 @@ if(intents == "0") {
|
||||||
ints = Intents.All;
|
ints = Intents.All;
|
||||||
} else if(intents == "1") {
|
} else if(intents == "1") {
|
||||||
ints = Intents.Presence;
|
ints = Intents.Presence;
|
||||||
} else {
|
} else if(intents == "2") {
|
||||||
ints = Intents.GuildMembers;
|
ints = Intents.GuildMembers;
|
||||||
|
} else {
|
||||||
|
ints = Intents.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.connect(token, ints);
|
client.connect(token, ints);
|
|
@ -1,4 +1,4 @@
|
||||||
import { unzlib } from 'https://deno.land/x/denoflate/mod.ts'
|
import { unzlib } from 'https://deno.land/x/denoflate@1.1/mod.ts'
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import {
|
import {
|
||||||
DISCORD_GATEWAY_URL,
|
DISCORD_GATEWAY_URL,
|
||||||
|
@ -140,7 +140,7 @@ class Gateway {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onclose (event: CloseEvent): void {
|
private onclose(event: CloseEvent): void {
|
||||||
this.debug(`Connection Closed with code: ${event.code}`)
|
this.debug(`Connection Closed with code: ${event.code}`)
|
||||||
|
|
||||||
if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) {
|
if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) {
|
||||||
|
@ -189,28 +189,31 @@ class Gateway {
|
||||||
console.log(eventError)
|
console.log(eventError)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendIdentify (forceNewSession?: boolean): Promise<void> {
|
private async sendIdentify(forceNewSession?: boolean): Promise<void> {
|
||||||
this.debug('Fetching /gateway/bot...')
|
if (this.client.bot === true) {
|
||||||
const info = await this.client.rest.get(GATEWAY_BOT())
|
this.debug('Fetching /gateway/bot...')
|
||||||
if (info.session_start_limit.remaining === 0)
|
const info = await this.client.rest.get(GATEWAY_BOT())
|
||||||
throw new Error(
|
if (info.session_start_limit.remaining === 0)
|
||||||
`Session Limit Reached. Retry After ${info.session_start_limit.reset_after}ms`
|
throw new Error(
|
||||||
|
`Session Limit Reached. Retry After ${info.session_start_limit.reset_after}ms`
|
||||||
|
)
|
||||||
|
this.debug(`Recommended Shards: ${info.shards}`)
|
||||||
|
this.debug('=== Session Limit Info ===')
|
||||||
|
this.debug(
|
||||||
|
`Remaining: ${info.session_start_limit.remaining}/${info.session_start_limit.total}`
|
||||||
)
|
)
|
||||||
this.debug(`Recommended Shards: ${info.shards}`)
|
this.debug(`Reset After: ${info.session_start_limit.reset_after}ms`)
|
||||||
this.debug('=== Session Limit Info ===')
|
if (forceNewSession === undefined || !forceNewSession) {
|
||||||
this.debug(
|
const sessionIDCached = await this.cache.get('session_id')
|
||||||
`Remaining: ${info.session_start_limit.remaining}/${info.session_start_limit.total}`
|
if (sessionIDCached !== undefined) {
|
||||||
)
|
this.debug(`Found Cached SessionID: ${sessionIDCached}`)
|
||||||
this.debug(`Reset After: ${info.session_start_limit.reset_after}ms`)
|
this.sessionID = sessionIDCached
|
||||||
if (forceNewSession === undefined || !forceNewSession) {
|
return await this.sendResume()
|
||||||
const sessionIDCached = await this.cache.get('session_id')
|
}
|
||||||
if (sessionIDCached !== undefined) {
|
|
||||||
this.debug(`Found Cached SessionID: ${sessionIDCached}`)
|
|
||||||
this.sessionID = sessionIDCached
|
|
||||||
return await this.sendResume()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.send({
|
|
||||||
|
let payload: any = {
|
||||||
op: GatewayOpcodes.IDENTIFY,
|
op: GatewayOpcodes.IDENTIFY,
|
||||||
d: {
|
d: {
|
||||||
token: this.token,
|
token: this.token,
|
||||||
|
@ -227,7 +230,24 @@ class Gateway {
|
||||||
),
|
),
|
||||||
presence: this.client.presence.create()
|
presence: this.client.presence.create()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if(this.client.bot === false) {
|
||||||
|
// TODO: Complete Selfbot support
|
||||||
|
this.debug("Modify Identify Payload for Self-bot..")
|
||||||
|
// delete payload.d['intents']
|
||||||
|
// payload.d.intents = Intents.None
|
||||||
|
payload.d.presence = null
|
||||||
|
payload.d.properties = {
|
||||||
|
$os: "Windows",
|
||||||
|
$browser: "Firefox",
|
||||||
|
$device: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debug("Warn: Support for selfbots is incomplete")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendResume(): Promise<void> {
|
private async sendResume(): Promise<void> {
|
||||||
|
@ -248,11 +268,11 @@ class Gateway {
|
||||||
this.send(resumePayload)
|
this.send(resumePayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug (msg: string): void {
|
debug(msg: string): void {
|
||||||
this.client.debug('Gateway', msg)
|
this.client.debug('Gateway', msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
async reconnect (forceNew?: boolean): Promise<void> {
|
async reconnect(forceNew?: boolean): Promise<void> {
|
||||||
clearInterval(this.heartbeatIntervalID)
|
clearInterval(this.heartbeatIntervalID)
|
||||||
if (forceNew === undefined || !forceNew)
|
if (forceNew === undefined || !forceNew)
|
||||||
await this.cache.delete('session_id')
|
await this.cache.delete('session_id')
|
||||||
|
@ -315,7 +335,7 @@ class Gateway {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendHeartbeat()
|
this.sendHeartbeat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ export interface ClientOptions {
|
||||||
cache?: ICacheAdapter,
|
cache?: ICacheAdapter,
|
||||||
forceNewSession?: boolean,
|
forceNewSession?: boolean,
|
||||||
presence?: ClientPresence | ClientActivity | ActivityGame
|
presence?: ClientPresence | ClientActivity | ActivityGame
|
||||||
|
bot?: boolean
|
||||||
|
canary?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +39,8 @@ export class Client extends EventEmitter {
|
||||||
channels: ChannelsManager = new ChannelsManager(this)
|
channels: ChannelsManager = new ChannelsManager(this)
|
||||||
messages: MessagesManager = new MessagesManager(this)
|
messages: MessagesManager = new MessagesManager(this)
|
||||||
emojis: EmojisManager = new EmojisManager(this)
|
emojis: EmojisManager = new EmojisManager(this)
|
||||||
|
bot: boolean = true
|
||||||
|
canary: boolean = false
|
||||||
|
|
||||||
presence: ClientPresence = new ClientPresence()
|
presence: ClientPresence = new ClientPresence()
|
||||||
|
|
||||||
|
@ -47,6 +51,8 @@ export class Client extends EventEmitter {
|
||||||
this.forceNewSession = options.forceNewSession
|
this.forceNewSession = options.forceNewSession
|
||||||
if (options.cache !== undefined) this.cache = options.cache
|
if (options.cache !== undefined) this.cache = options.cache
|
||||||
if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence)
|
if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence)
|
||||||
|
if (options.bot === false) this.bot = false
|
||||||
|
if (options.canary === true) this.canary = true
|
||||||
}
|
}
|
||||||
|
|
||||||
setAdapter (adapter: ICacheAdapter): Client {
|
setAdapter (adapter: ICacheAdapter): Client {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { delay } from '../utils/index.ts'
|
import { delay } from '../utils/index.ts'
|
||||||
import * as baseEndpoints from '../consts/urlsAndVersions.ts'
|
import * as baseEndpoints from '../consts/urlsAndVersions.ts'
|
||||||
import { Client } from './client.ts'
|
import { Client } from './client.ts'
|
||||||
|
import { getBuildInfo } from "../utils/buildInfo.ts"
|
||||||
|
|
||||||
export enum HttpResponseCode {
|
export enum HttpResponseCode {
|
||||||
Ok = 200,
|
Ok = 200,
|
||||||
|
@ -175,11 +176,29 @@ export class RESTManager {
|
||||||
headers['Content-Type'] = 'application/json'
|
headers['Content-Type'] = 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
let data: { [name: string]: any } = {
|
||||||
headers,
|
headers,
|
||||||
body: body?.file ?? JSON.stringify(body),
|
body: body?.file ?? JSON.stringify(body),
|
||||||
method: method.toUpperCase()
|
method: method.toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.client.bot === false) {
|
||||||
|
// This is a selfbot. Use requests similar to Discord Client
|
||||||
|
data.headers['authorization'] = this.client.token as string
|
||||||
|
data.headers['accept-language'] = 'en-US'
|
||||||
|
data.headers['accept'] = '*/*'
|
||||||
|
data.headers['sec-fetch-dest'] = 'empty'
|
||||||
|
data.headers['sec-fetch-mode'] = 'cors'
|
||||||
|
data.headers['sec-fetch-site'] = 'same-origin'
|
||||||
|
data.headers['x-super-properties'] = btoa(JSON.stringify(getBuildInfo(this.client)))
|
||||||
|
delete data.headers['User-Agent']
|
||||||
|
delete data.headers['Authorization']
|
||||||
|
headers['credentials'] = 'include'
|
||||||
|
headers['mode'] = 'cors'
|
||||||
|
headers['referrerPolicy'] = 'no-referrer-when-downgrade'
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkRatelimits (url: string): Promise<number | false> {
|
async checkRatelimits (url: string): Promise<number | false> {
|
||||||
|
@ -230,9 +249,14 @@ export class RESTManager {
|
||||||
)
|
)
|
||||||
.join('&')
|
.join('&')
|
||||||
: ''
|
: ''
|
||||||
const urlToUse =
|
let urlToUse =
|
||||||
method === 'get' && query !== '' ? `${url}?${query}` : url
|
method === 'get' && query !== '' ? `${url}?${query}` : url
|
||||||
|
|
||||||
|
if(this.client.canary) {
|
||||||
|
let split = urlToUse.split('//')
|
||||||
|
urlToUse = split[0] + '//canary.' + split[1]
|
||||||
|
}
|
||||||
|
|
||||||
const requestData = this.createRequestBody(body, method)
|
const requestData = this.createRequestBody(body, method)
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Client, GuildTextChannel, Message, RedisCacheAdapter, ClientPresence, Member, Role, GuildChannel, TextChannel, Embed, Guild } from '../../mod.ts';
|
import { Client, Intents, GuildTextChannel, Message, ClientPresence, Member, Role, GuildChannel, Embed, Guild } from '../../mod.ts';
|
||||||
import { Intents } from "../utils/intents.ts";
|
|
||||||
import { TOKEN } from './config.ts'
|
import { TOKEN } from './config.ts'
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
|
@ -7,6 +6,7 @@ const client = new Client({
|
||||||
name: 'Pokémon Sword',
|
name: 'Pokémon Sword',
|
||||||
type: 'COMPETING'
|
type: 'COMPETING'
|
||||||
}),
|
}),
|
||||||
|
// bot: false,
|
||||||
// cache: new RedisCacheAdapter({
|
// cache: new RedisCacheAdapter({
|
||||||
// hostname: '127.0.0.1',
|
// hostname: '127.0.0.1',
|
||||||
// port: 6379
|
// port: 6379
|
||||||
|
@ -30,6 +30,7 @@ client.on('channelUpdate', (before: GuildTextChannel, after: GuildTextChannel) =
|
||||||
|
|
||||||
client.on('messageCreate', async (msg: Message) => {
|
client.on('messageCreate', async (msg: Message) => {
|
||||||
if (msg.author.bot === true) return
|
if (msg.author.bot === true) return
|
||||||
|
console.log(`${msg.author.tag}: ${msg.content}`)
|
||||||
if (msg.content === '!ping') {
|
if (msg.content === '!ping') {
|
||||||
msg.reply(`Pong! Ping: ${client.ping}ms`)
|
msg.reply(`Pong! Ping: ${client.ping}ms`)
|
||||||
} else if (msg.content === '!members') {
|
} else if (msg.content === '!members') {
|
||||||
|
@ -58,4 +59,4 @@ client.on('messageCreate', async (msg: Message) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
client.connect(TOKEN, Intents.All)
|
client.connect(TOKEN, Intents.None)
|
||||||
|
|
30
src/utils/buildInfo.ts
Normal file
30
src/utils/buildInfo.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { Client } from "../models/client.ts";
|
||||||
|
|
||||||
|
export const getBuildInfo = (client: Client) => {
|
||||||
|
let os = 'Windows'
|
||||||
|
let os_version = '10'
|
||||||
|
let client_build_number = 71073
|
||||||
|
let client_event_source = null
|
||||||
|
let release_channel = 'stable'
|
||||||
|
if (client.canary) {
|
||||||
|
release_channel = 'canary'
|
||||||
|
client_build_number = 71076
|
||||||
|
}
|
||||||
|
let browser = 'Firefox'
|
||||||
|
let browser_version = '83.0'
|
||||||
|
let browser_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 ' + browser + '/' + browser_version
|
||||||
|
// TODO: Use current OS properties, but also browser_user_agent accordingly
|
||||||
|
// if(Deno.build.os === 'darwin') os = 'MacOS'
|
||||||
|
// else if(Deno.build.os === 'linux') os = 'Ubuntu'
|
||||||
|
|
||||||
|
return {
|
||||||
|
os,
|
||||||
|
os_version,
|
||||||
|
browser,
|
||||||
|
browser_version,
|
||||||
|
browser_user_agent,
|
||||||
|
client_build_number,
|
||||||
|
client_event_source,
|
||||||
|
release_channel,
|
||||||
|
}
|
||||||
|
};
|
|
@ -52,4 +52,20 @@ export class Intents {
|
||||||
GatewayIntents.GUILD_VOICE_STATES,
|
GatewayIntents.GUILD_VOICE_STATES,
|
||||||
GatewayIntents.GUILD_WEBHOOKS
|
GatewayIntents.GUILD_WEBHOOKS
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static None: number[] = [
|
||||||
|
GatewayIntents.GUILD_MESSAGES,
|
||||||
|
GatewayIntents.DIRECT_MESSAGES,
|
||||||
|
GatewayIntents.DIRECT_MESSAGE_REACTIONS,
|
||||||
|
GatewayIntents.DIRECT_MESSAGE_TYPING,
|
||||||
|
GatewayIntents.GUILDS,
|
||||||
|
GatewayIntents.GUILD_BANS,
|
||||||
|
GatewayIntents.GUILD_EMOJIS,
|
||||||
|
GatewayIntents.GUILD_INTEGRATIONS,
|
||||||
|
GatewayIntents.GUILD_INVITES,
|
||||||
|
GatewayIntents.GUILD_MESSAGE_REACTIONS,
|
||||||
|
GatewayIntents.GUILD_MESSAGE_TYPING,
|
||||||
|
GatewayIntents.GUILD_VOICE_STATES,
|
||||||
|
GatewayIntents.GUILD_WEBHOOKS
|
||||||
|
]
|
||||||
}
|
}
|
Loading…
Reference in a new issue