Added Intents.None, partial support for selfbot, required changes

This commit is contained in:
DjDeveloperr 2020-11-06 16:12:00 +05:30
parent 4228cd8f52
commit 3a3af635c6
8 changed files with 137 additions and 33 deletions

View file

@ -1,5 +1,7 @@
# 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)
**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()
// Listen for event when client is ready (Identified through gateway / Resumed)
client.on('ready', () => {
console.log(`Ready! User: ${client.user?.tag}`)
})
// Listen for event whenever a Message is sent
client.on('messageCreate', (msg: Message): void => {
if (msg.content === '!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)
client.connect('super secret token comes here', Intents.All)
```

View file

@ -21,8 +21,8 @@ if(!token) {
Deno.exit();
}
const intents = prompt("Input Intents (0 = All, 1 = Presence, 2 = Server Members):");
if(!intents || !["0", "1", "2"].includes(intents)) {
const intents = prompt("Input Intents (0 = All, 1 = Presence, 2 = Server Members, 3 = None):");
if(!intents || !["0", "1", "2", "3"].includes(intents)) {
console.log("No intents provided");
Deno.exit();
}
@ -32,8 +32,10 @@ if(intents == "0") {
ints = Intents.All;
} else if(intents == "1") {
ints = Intents.Presence;
} else {
} else if(intents == "2") {
ints = Intents.GuildMembers;
} else {
ints = Intents.None;
}
client.connect(token, ints);

View file

@ -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 {
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}`)
if (event.code === GatewayCloseCodes.UNKNOWN_ERROR) {
@ -189,28 +189,31 @@ class Gateway {
console.log(eventError)
}
private async sendIdentify (forceNewSession?: boolean): Promise<void> {
this.debug('Fetching /gateway/bot...')
const info = await this.client.rest.get(GATEWAY_BOT())
if (info.session_start_limit.remaining === 0)
throw new Error(
`Session Limit Reached. Retry After ${info.session_start_limit.reset_after}ms`
private async sendIdentify(forceNewSession?: boolean): Promise<void> {
if (this.client.bot === true) {
this.debug('Fetching /gateway/bot...')
const info = await this.client.rest.get(GATEWAY_BOT())
if (info.session_start_limit.remaining === 0)
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('=== Session Limit Info ===')
this.debug(
`Remaining: ${info.session_start_limit.remaining}/${info.session_start_limit.total}`
)
this.debug(`Reset After: ${info.session_start_limit.reset_after}ms`)
if (forceNewSession === undefined || !forceNewSession) {
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.debug(`Reset After: ${info.session_start_limit.reset_after}ms`)
if (forceNewSession === undefined || !forceNewSession) {
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,
d: {
token: this.token,
@ -227,7 +230,24 @@ class Gateway {
),
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> {
@ -248,11 +268,11 @@ class Gateway {
this.send(resumePayload)
}
debug (msg: string): void {
debug(msg: string): void {
this.client.debug('Gateway', msg)
}
async reconnect (forceNew?: boolean): Promise<void> {
async reconnect(forceNew?: boolean): Promise<void> {
clearInterval(this.heartbeatIntervalID)
if (forceNew === undefined || !forceNew)
await this.cache.delete('session_id')
@ -315,7 +335,7 @@ class Gateway {
return
}
this.sendHeartbeat()
this.sendHeartbeat()
}
}

View file

@ -18,6 +18,8 @@ export interface ClientOptions {
cache?: ICacheAdapter,
forceNewSession?: boolean,
presence?: ClientPresence | ClientActivity | ActivityGame
bot?: boolean
canary?: boolean
}
/**
@ -37,6 +39,8 @@ export class Client extends EventEmitter {
channels: ChannelsManager = new ChannelsManager(this)
messages: MessagesManager = new MessagesManager(this)
emojis: EmojisManager = new EmojisManager(this)
bot: boolean = true
canary: boolean = false
presence: ClientPresence = new ClientPresence()
@ -47,6 +51,8 @@ export class Client extends EventEmitter {
this.forceNewSession = options.forceNewSession
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.bot === false) this.bot = false
if (options.canary === true) this.canary = true
}
setAdapter (adapter: ICacheAdapter): Client {

View file

@ -1,6 +1,7 @@
import { delay } from '../utils/index.ts'
import * as baseEndpoints from '../consts/urlsAndVersions.ts'
import { Client } from './client.ts'
import { getBuildInfo } from "../utils/buildInfo.ts"
export enum HttpResponseCode {
Ok = 200,
@ -175,11 +176,29 @@ export class RESTManager {
headers['Content-Type'] = 'application/json'
}
return {
let data: { [name: string]: any } = {
headers,
body: body?.file ?? JSON.stringify(body),
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> {
@ -230,9 +249,14 @@ export class RESTManager {
)
.join('&')
: ''
const urlToUse =
let urlToUse =
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 response = await fetch(

View file

@ -1,5 +1,4 @@
import { Client, GuildTextChannel, Message, RedisCacheAdapter, ClientPresence, Member, Role, GuildChannel, TextChannel, Embed, Guild } from '../../mod.ts';
import { Intents } from "../utils/intents.ts";
import { Client, Intents, GuildTextChannel, Message, ClientPresence, Member, Role, GuildChannel, Embed, Guild } from '../../mod.ts';
import { TOKEN } from './config.ts'
const client = new Client({
@ -7,6 +6,7 @@ const client = new Client({
name: 'Pokémon Sword',
type: 'COMPETING'
}),
// bot: false,
// cache: new RedisCacheAdapter({
// hostname: '127.0.0.1',
// port: 6379
@ -30,6 +30,7 @@ client.on('channelUpdate', (before: GuildTextChannel, after: GuildTextChannel) =
client.on('messageCreate', async (msg: Message) => {
if (msg.author.bot === true) return
console.log(`${msg.author.tag}: ${msg.content}`)
if (msg.content === '!ping') {
msg.reply(`Pong! Ping: ${client.ping}ms`)
} 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
View 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,
}
};

View file

@ -52,4 +52,20 @@ export class Intents {
GatewayIntents.GUILD_VOICE_STATES,
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
]
}