dsu3 0.9.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77b2e807e3bfdf9b203d41a55e4311ef75bf30cf93ad649b29f20e1edd8a1519
4
- data.tar.gz: d220312bcff98c284b5727a5dabdc1a429cff6d1528b4bbc913e3b4df181364c
3
+ metadata.gz: 3836a58d3aac7cf05d21fddc541bff2daed7ae535c9afbf57aedccaaa452a11a
4
+ data.tar.gz: 5dec7ec5f4704f993efeccda45900e6824da03bf5c9c9715203d446cb0231a67
5
5
  SHA512:
6
- metadata.gz: bc9df6845ccaa0a71d2e8bdb477b5011c4ac89d3c763a3499338a1b818b00e4b4e9140d69f26fd9ab9819295ef58ea32daf0950579b5adc463b069c853b91c3e
7
- data.tar.gz: 6c2cf6542b310e4b08fcc1b258356d33f291b177bab08b288f5cb435058a526d53e44c1d1462152ad77375558b3cdd07087fd595f6a2ff4cbaa43585e5e3e45e
6
+ metadata.gz: 803eafe94df41b818bb6d90bb068b6f27bc7f0a7c718c854069070c7e381fe62e5f85598cc43ed594bbe63284e6542cf3bbe70cb865daea6a80cd293607b6493
7
+ data.tar.gz: 8872033f7b17ffd4498f4bb35003543f8c8f0f29a11cc480924e92141b0eb577c2a730a49fd31173c56c496e03f14fe213f167613420c17ab7a3355adccd8b1e
data/bin/dsu3 CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'dsu3'
4
5
 
5
- @net = DSU3::Net.new(*File.readlines(ARGV.shift).map(&:chop))
6
+ @net = DSU3::Net.new(*File.read(ARGV.shift).split("\n"))
6
7
 
7
8
  require 'irb'
8
- IRB.start
9
+ IRB.start
@@ -2,11 +2,11 @@
2
2
 
3
3
  module DSU3
4
4
  module API
5
- # Channels resource
5
+ # Channel API calls
6
6
  module Channel
7
7
  module_function
8
8
 
9
- # Types text into a particular channel
9
+ # Types text into a channel
10
10
  # @param [String] token Discord account token
11
11
  # @param [String, Integer] channel Channel ID
12
12
  def type(token, channel)
@@ -15,7 +15,7 @@ module DSU3
15
15
  )
16
16
  end
17
17
 
18
- # Sends a message to a specific channel
18
+ # Sends a message to a channel
19
19
  # @param [String] token Discord account token
20
20
  # @param [String, Integer] channel Channel ID
21
21
  # @param [String, Integer] message Message contents
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DSU3
4
4
  module API
5
- # Guilds resource
5
+ # Guild API calls
6
6
  module Guild
7
7
  module_function
8
8
 
@@ -18,4 +18,4 @@ module DSU3
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DSU3
4
4
  module API
5
- # Invites resource
5
+ # Invite API calls
6
6
  module Invite
7
7
  module_function
8
8
 
@@ -18,4 +18,4 @@ module DSU3
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ module API
5
+ # Message API calls
6
+ module Message
7
+ module_function
8
+
9
+ # Reacts to a message
10
+ # @note To use custom emoji, you must encode it in the format name:id with the emoji name and emoji id
11
+ # @param [String] token Discord account token
12
+ # @param [String, Integer] channel Channel ID
13
+ # @param [String, Integer] message Message ID
14
+ # @param [String] emoji
15
+ def react(token, channel, message, emoji)
16
+ emoji = URI.encode_www_form_component(emoji)
17
+
18
+ DSU3::API.request(
19
+ token, :put,
20
+ "channels/#{channel}/messages/#{message}/reactions/#{emoji}/@me",
21
+ { params: { location: 'Message' } }
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ module API
5
+ # User API calls
6
+ module User
7
+ module_function
8
+
9
+ # Get user
10
+ # @param [String] token Discord account token
11
+ # @param [String, Integer] user User ID
12
+ def get(token, user)
13
+ DSU3::API.request(
14
+ token, :get, "users/#{user}"
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/dsu3/api.rb CHANGED
@@ -2,17 +2,20 @@
2
2
 
3
3
  require 'rest-client'
4
4
  require 'json'
5
- require 'uri'
6
5
 
7
6
  require 'dsu3/props'
7
+ require 'dsu3/errors'
8
8
  require 'dsu3/api/channel'
9
9
  require 'dsu3/api/guild'
10
10
  require 'dsu3/api/invite'
11
+ require 'dsu3/api/message'
11
12
 
12
13
  module DSU3
13
14
  # Namespace for all methods representing Discord API endpoints
14
15
  module API
15
- API_BASE = 'https://discord.com/api/v9'
16
+ API_BASE = 'https://discord.com/api/v9/'
17
+
18
+ @ratelimits = []
16
19
 
17
20
  module_function
18
21
 
@@ -22,32 +25,32 @@ module DSU3
22
25
  # @param [String] route Discord API route
23
26
  # @param [Hash] headers Additional request headers
24
27
  # @param [String] payload
25
- # @return [RestClient::Response] Response object
28
+ # @return [String] Response body
26
29
  def raw_request(token, method, route, headers = {}, payload = nil)
27
30
  RestClient::Request.execute(
28
31
  method: method,
29
- url: URI.join(API_BASE, route).to_s,
32
+ url: API_BASE + route,
30
33
  headers: headers.merge(DSU3::Props::HEADERS, { authorization: token }),
31
34
  payload: payload,
32
35
  proxy: DSU3.proxies.sample
33
- )
36
+ ).body
34
37
  end
35
38
 
36
- # Makes an API request, includes simple error handling
39
+ # Makes an API request, includes handling ratelimits and errors
37
40
  # @param (see #raw_request)
38
41
  # @return (see #raw_request)
39
42
  def request(...)
40
- raw_request(...)
41
- rescue RestClient::ExceptionWithResponse => e
42
- if e.is_a?(RestClient::TooManyRequests)
43
- LOGGER.warn('ratelimit exceeded')
44
- elsif e.response.headers[:content_type] == 'application/json'
45
- data = JSON.parse(e.response.body)
46
- LOGGER.error("#{data['code']}: #{data['message']}")
47
- else
48
- LOGGER.error(e.message)
43
+ begin
44
+ raw_request(...)
45
+ rescue RestClient::ExceptionWithResponse => e
46
+ begin
47
+ data = JSON.parse(e.response.body)
48
+ raise DSU3::RateLimitError('ratelimit exceeded', data['retry_after']) if e.is_a?(RestClient::TooManyRequests)
49
+ raise DSU3::CodeError.new("#{data['code']}: #{data['message']}")
50
+ rescue JSON::ParserError
51
+ raise e
52
+ end
49
53
  end
50
- e.response
51
54
  end
52
55
  end
53
56
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ # Channel object
5
+ class Channel < DObject
6
+ # Types text into a channel
7
+ def type
8
+ @net.request(cooldown: 9, loop: true) { DSU3::API::Channel.type(_1, @id) }
9
+ end
10
+
11
+ # Sends a message to a channel
12
+ # @param [String, Integer] message Message contents
13
+ def send(message)
14
+ @net.request { DSU3::API::Channel.send(_1, @id, message) }
15
+ end
16
+
17
+ # @overload spam(message)
18
+ # Spams to a channel
19
+ # @param [String] message Message contents
20
+ # @overload spam(&block)
21
+ # Every time the decisive moment to send a message comes up,
22
+ # this function calls our block and pigeonholes the value returned by it
23
+ def spam(message)
24
+ @net.request(loop: true) { DSU3::API::Channel.send(_1, @id, message || yield) }
25
+ end
26
+
27
+ # Returns Message instance
28
+ # @param [String, Integer] message Message ID
29
+ def message(message_id)
30
+ DSU3::Message.new(@tokens, @id, message_id)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ # Guild object
5
+ class Guild < DObject
6
+ # Verifies accounts on the server
7
+ def verify
8
+ @net.request(cooldown: 0.5) { DSU3::API::Guild.verify(_1, @id) }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ # Invite object
5
+ class Invite < DObject
6
+ # Joins guild
7
+ def join
8
+ @net.request(cooldown: 0.5) { DSU3::API::Invites.join(token, @id) }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ # Message object
5
+ class Message < DObject
6
+ # @param [DSU3::Channel] channel Channel instance
7
+ # @param [String, Integer] id Message ID
8
+ def initialize(channel, id)
9
+ super(channel.net, id)
10
+ @channel_id = channel.id
11
+ end
12
+
13
+ # Reacts to a message
14
+ # @note To use custom emoji, you must encode it in the format name:id with the emoji name and emoji id
15
+ # @param [String] emoji
16
+ def react(emoji)
17
+ @net.request { DSU3::API::Message.react(_1, @channel_id, @id, emoji) }
18
+ end
19
+ end
20
+ end
data/lib/dsu3/data.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'dsu3/api'
2
+ require 'dsu3/dobject'
3
+ require 'dsu3/data/channel'
4
+ require 'dsu3/data/guild'
5
+ require 'dsu3/data/invite'
6
+ require 'dsu3/data/message'
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ # Discord object
5
+ class DObject
6
+ attr_reader :net, :id
7
+
8
+ # @param [Array] net Net object
9
+ # @param [String, Integer] id
10
+ def initialize(net, id)
11
+ @net = net
12
+ @id = id
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSU3
4
+ class RateLimitError < StandardError
5
+ attr_reader :retry_after
6
+
7
+ def initialize(message, retry_after)
8
+ @message = message
9
+ @retry_after = retry_after
10
+ end
11
+ end
12
+
13
+ CodeError = Class.new(StandardError)
14
+ end
data/lib/dsu3/net.rb CHANGED
@@ -1,55 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dsu3/api'
3
+ require 'dsu3/data'
4
4
 
5
5
  module DSU3
6
6
  # Class used to manage multiple bots
7
7
  class Net
8
+ attr_reader :tokens, :mutex
9
+
8
10
  # @param [Array] tokens List of bot tokens
9
11
  def initialize(*tokens)
10
- @tokens = tokens
11
- end
12
-
13
- # (see DSU3::API::Channel#type)
14
- def typespam(channel)
15
- loop do
16
- @tokens.each { |token| DSU3::API::Channel.type(token, channel) }
17
- sleep 9
18
- end
19
- end
12
+ raise 'There must be at least one token' if tokens.empty?
20
13
 
21
- # (see DSU3::API::Channel#send)
22
- def send(channel, message)
23
- @tokens.each { |token| DSU3::API::Channel.send(token, channel, message) }
14
+ @tokens = tokens
15
+ @mutex = Mutex.new
24
16
  end
25
17
 
26
- # Infinitely calls a block and sends the value it returns to a specific channel
27
- # @param [String] token Discord account token
28
- # @param [String, Integer] channel Channel ID
29
- def spam(channel, &block)
30
- loop do
31
- @tokens.each { |token| DSU3::API::Channel.send(token, channel, block.call) }
32
- end
33
- end
18
+ # An auxiliary method that can be used to make an Discord API call from multiple tokens with ratelimit and thread support
19
+ # @param [Hash] opts Options
20
+ def request(opts = {})
21
+ opts = {cooldown: 0, loop: false}.merge(opts)
34
22
 
35
- # (see DSU3::API::Invite#join)
36
- def join(invite)
37
23
  @tokens.each do |token|
38
- DSU3::API::Invites.join(token, invite)
39
- sleep(0.5)
24
+ Thread.new do
25
+ begin
26
+ @mutex.synchronize { yield token }
27
+ sleep(opts[:cooldown])
28
+ rescue DSU3::RateLimitError => e
29
+ DSU3::LOGGER.warn('ratelimit exceeded')
30
+ @mutex.sleep(e.retry_after)
31
+ retry
32
+ end while opts[:loop]
33
+ end.join
40
34
  end
41
35
  end
42
36
 
43
- # (see DSU3::API::Channel#react)
44
- def react(channel, message, emoji)
45
- @tokens.each { |token| DSU3::API::Channel.react(token, channel, message, emoji) }
46
- end
47
-
48
- # (see DSU3::API::Guild#verify)
49
- def verify(guild, invite)
50
- @tokens.each do |token|
51
- DSU3::API::Guild.verify(token, guild, invite)
52
- sleep(0.5)
37
+ # I'm too lazy to try to document it
38
+ %w{channel guild invite}.each do |s|
39
+ define_method s do |id|
40
+ DSU3.const_get(s.capitalize).new(self, id)
53
41
  end
54
42
  end
55
43
  end
data/lib/dsu3/props.rb CHANGED
@@ -8,30 +8,34 @@ module DSU3
8
8
  # user-agent header
9
9
  USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0'
10
10
 
11
- DATAMINING_COMMITS_URL = 'https://api.github.com/repos/Discord-Datamining/Discord-Datamining/commits/master'
11
+ module_function
12
12
 
13
13
  # Fetches Discord client build number
14
- def self.fetch_build_number
15
- JSON.parse(RestClient.get(DATAMINING_COMMITS_URL))['commit']['message'].match(/Build (\d+)/)[1]
14
+ def fetch_build_number
15
+ JSON.parse(
16
+ RestClient.get('https://api.github.com/repos/Discord-Datamining/Discord-Datamining/commits/master')
17
+ )['commit']['message'].match(/Build (\d+)/)[1]
16
18
  end
17
19
 
18
- # Decoded x-super-properties header
19
- SUPER_PROPERTIES = {
20
- os: 'Linux',
21
- browser: 'Firefox',
22
- device: '',
23
- system_locale: 'en',
24
- browser_user_agent: USER_AGENT,
25
- browser_version: '91.0',
26
- os_version: '',
27
- referrer: '',
28
- referring_domain: '',
29
- referrer_current: '',
30
- referring_domain_current: '',
31
- release_channel: 'stable',
32
- client_build_number: fetch_build_number,
33
- client_event_source: nil
34
- }.freeze
20
+ # Generates x-super-properties header
21
+ def generate_x_super_properties
22
+ Base64.strict_encode64(JSON.generate(
23
+ os: 'Linux',
24
+ browser: 'Firefox',
25
+ device: '',
26
+ system_locale: 'en',
27
+ browser_user_agent: USER_AGENT,
28
+ browser_version: '91.0',
29
+ os_version: '',
30
+ referrer: '',
31
+ referring_domain: '',
32
+ referrer_current: '',
33
+ referring_domain_current: '',
34
+ release_channel: 'stable',
35
+ client_build_number: fetch_build_number,
36
+ client_event_source: nil
37
+ ))
38
+ end
35
39
 
36
40
  resp = RestClient.get('https://discord.com/api/v9/experiments')
37
41
 
@@ -50,7 +54,7 @@ module DSU3
50
54
  user_agent: USER_AGENT,
51
55
  x_debug_options: 'bugReporterEnabled',
52
56
  x_discord_locale: 'en-US',
53
- x_super_properties: Base64.strict_encode64(SUPER_PROPERTIES.to_json),
57
+ x_super_properties: generate_x_super_properties,
54
58
  content_type: 'application/json',
55
59
  cookie: HTTP::Cookie.cookie_value(resp.cookie_jar.cookies),
56
60
  x_fingerprint: JSON.parse(resp.body)['fingerprint']
data/lib/dsu3/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSU3
4
- VERSION = '0.9.3'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsu3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur Sheremetjev IV
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-12 00:00:00.000000000 Z
11
+ date: 2022-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -39,6 +39,15 @@ files:
39
39
  - lib/dsu3/api/channel.rb
40
40
  - lib/dsu3/api/guild.rb
41
41
  - lib/dsu3/api/invite.rb
42
+ - lib/dsu3/api/message.rb
43
+ - lib/dsu3/api/user.rb
44
+ - lib/dsu3/data.rb
45
+ - lib/dsu3/data/channel.rb
46
+ - lib/dsu3/data/guild.rb
47
+ - lib/dsu3/data/invite.rb
48
+ - lib/dsu3/data/message.rb
49
+ - lib/dsu3/dobject.rb
50
+ - lib/dsu3/errors.rb
42
51
  - lib/dsu3/net.rb
43
52
  - lib/dsu3/props.rb
44
53
  - lib/dsu3/version.rb