ruqqus 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c14af41785a17ac1c28bc3e89f778a1ce64571a2943e9ca44d4f5370c502de8
4
- data.tar.gz: b7e33784b89a2df20e85ead8e7097ab53b48d3bf95311f9ef1555a04bc91a975
3
+ metadata.gz: 1274eade9799203bd720c94da255a81a0e0295da9e438519a687626c1db7f0b7
4
+ data.tar.gz: 96fe1b73d77d38004981f476ddca3acde81577755de6939f77c6c4ea65fdc693
5
5
  SHA512:
6
- metadata.gz: a8557e744ce587f4d30c01b3ba954cec4eba4e5b3cd51ab408c202b4b3d6038f4db5e92f02d4667a7b289738d0efc5e578528535105877fb847c735eac162eb2
7
- data.tar.gz: f421f465e5690496b21050950c6a177b01c7724b67752ae896aaf7ef500c972c0643bb88b82c0562285ed7bb4b9f82f8461e1677f2f212dbf25847e474e7649a
6
+ metadata.gz: da793dbcee6ae0cd28b6f5160f85a752804a44ceb00f295291209e2529a3ba39ed26300f43b8b9df95f4ce41b7c3c10b97f60550eed9b9ce5c27c50b4252a638
7
+ data.tar.gz: 92b77622dcaf2fa8129e013465a91186d1de731eb927bcd219fac8160c7afccceb2beecf4f509f7e3b9fe95c8b9431955d301566eeaa5608302a2331ce87743c
@@ -2,6 +2,20 @@
2
2
 
3
3
  Documentation for library API changes.
4
4
 
5
+ Versioning system:
6
+
7
+ `MAJOR.MINOR.REVISION`
8
+
9
+ * `MAJOR` Corresponds to the native Ruqqus API major version
10
+ * `MINOR` Indicates possible breaking API changes for existing code
11
+ * `REVISION` Added functionality, bug-fixes, and other non-breaking alterations
12
+
13
+ ## Version 1.1.3
14
+
15
+ * Implemented browser-based confirmation process
16
+ * Implemented capturing confirmation code from `localhost` OAuth redirects
17
+ * Fixed bug in querying guild/username availability
18
+
5
19
  ## Version 1.1.2
6
20
 
7
21
  * Implemented enumerating comments of guilds and posts
@@ -1,5 +1,9 @@
1
- require 'rest-client'
1
+ require 'base64'
2
2
  require 'json'
3
+ require 'rbconfig'
4
+ require 'rest-client'
5
+ require 'securerandom'
6
+ require 'socket'
3
7
 
4
8
  require_relative 'ruqqus/token'
5
9
  require_relative 'ruqqus/routes'
@@ -49,12 +53,14 @@ module Ruqqus
49
53
  # @return [URI?] the URI of the proxy server in use, or `nil` if none has been set.
50
54
 
51
55
  ##
52
- # Obtains a list of URIs of proxy servers that can be used to route network traffic through.
56
+ # Obtains a list of URIs of free proxy servers that can be used to route network traffic through.
53
57
  #
54
58
  # @param anon [Symbol] anonymity filter for the servers to return, either `:transparent`, `:anonymous`, or `:elite`.
55
59
  # @param country [String,Symbol] country filter for servers to return, an ISO-3166 two digit county code.
56
60
  #
57
61
  # @return [Array<URI>] an array of proxy URIs that match the input filters.
62
+ # @note These proxies are free, keep that in mind. They are refreshed frequently, can go down unexpectedly, be slow,
63
+ # and other manners of inconvenience that can be expected with free services.
58
64
  # @see https://www.nationsonline.org/oneworld/country_code_list.htm
59
65
  def self.proxy_list(anon: :elite, country: nil)
60
66
  raise(ArgumentError, 'invalid anonymity value') unless %i(transparent anonymous elite).include?(anon.to_sym)
@@ -83,7 +89,7 @@ module Ruqqus
83
89
  #
84
90
  # @param client_id [String] an Imgur client ID
85
91
  # @param image_path [String] the path to an image file.
86
- # @params opts [Hash] the options hash.
92
+ # @param opts [Hash] the options hash.
87
93
  # @option opts [String] :title a title to set on the Imgur post
88
94
  # @option opts [String] :description a description to set on the Imgur post
89
95
  #
@@ -111,7 +117,14 @@ module Ruqqus
111
117
  #
112
118
  # @return [Boolean] `true` is name is available, otherwise `false` if it has been reserved or is in use.
113
119
  def self.guild_available?(guild_name)
114
- available?(guild_name, VALID_GUILD, "#{Routes::GUILD_AVAILABLE}#{name}")
120
+ begin
121
+ response = RestClient.get("#{Routes::GUILD_AVAILABLE}#{guild_name}")
122
+ json = JSON.parse(response.body, symbolize_names: true)
123
+ return json[:available]
124
+ rescue
125
+ puts 'err'
126
+ return false
127
+ end
115
128
  end
116
129
 
117
130
  ##
@@ -121,22 +134,145 @@ module Ruqqus
121
134
  #
122
135
  # @return [Boolean] `true` is name is available, otherwise `false` if it has been reserved or is in use.
123
136
  def self.username_available?(username)
124
- available?(username, VALID_USERNAME, "#{Routes::USERNAME_AVAILABLE}#{name}")
137
+ begin
138
+ response = RestClient.get("#{Routes::USERNAME_AVAILABLE}#{username}")
139
+ json = JSON.parse(response.body)
140
+ return json[username]
141
+ rescue
142
+ return false
143
+ end
144
+ end
145
+
146
+ ##
147
+ # Generates a URL for the user to navigate to that will allow them to authorize an application.
148
+ #
149
+ # @param client_id [String] the unique ID of the approved client to authorize.
150
+ # @param redirect [String] the redirect URL where the client sends the OAuth authorization code.
151
+ # @param scopes [Array<Symbol>] a collection of values indicating the permissions the application is requesting from
152
+ # the user. See {Ruqqus::Client::SCOPES} for valid values.
153
+ # @param permanent [Boolean] `true` if authorization should persist until user explicitly revokes it,
154
+ # otherwise `false`.
155
+ # @param csrf [String] a token to authenticate and prevent a cross-site request forgery (CSRF) attack, or `nil` if
156
+ # you do not plan to validate the presence of the cookie in the redirection.
157
+ #
158
+ # @see https://ruqqus.com/settings/apps
159
+ # @see https://owasp.org/www-community/attacks/csrf
160
+ def self.authorize_url(client_id, redirect, scopes, permanent = true, csrf = nil)
161
+
162
+ raise(ArgumentError, 'invalid redirect URI') unless URI.regexp =~ redirect
163
+ raise(ArgumentError, 'scopes cannot be empty') unless scopes && !scopes.empty?
164
+
165
+ scopes = scopes.map(&:to_sym)
166
+ raise(ArgumentError, "invalid scopes specified") unless scopes.all? { |s| Client::SCOPES.include?(s) }
167
+ if scopes.any? { |s| [:create, :update, :guildmaster].include?(s) } && !scopes.include?(:identity)
168
+ # Add identity permission if missing, which is obviously required for a few other permissions
169
+ scopes << :identity
170
+ end
171
+
172
+ url = 'https://ruqqus.com/oauth/authorize'
173
+ url << "?client_id=#{client_id || raise(ArgumentError, 'client ID cannot be nil')}"
174
+ url << "&redirect_uri=#{redirect}"
175
+ url << "&scope=#{scopes.join(',')}"
176
+ url << "&state=#{csrf || Base64.encode64(SecureRandom.uuid).chomp}"
177
+ url << "&permanent=#{permanent}"
178
+ url
125
179
  end
126
180
 
127
- private
128
181
 
129
182
  ##
130
- # Checks if the specified guild or user name is available to be created.
183
+ # Opens a URL in the system's default web browser, using the appropriate command for the host platform.
131
184
  #
132
- # @param name [String] the name of a guild or username to query.
133
- # @param regex [Regex] a validation regex for the name.
134
- # @param route [String] the API endpoint to invoke.
185
+ # @param [String] the URL to open.
135
186
  #
136
- # @return [Boolean] `true` is name is available, otherwise `false` if it has been reserved or is in use.
137
- def self.available?(name, regex, route)
138
- return false unless name && regex.match?(name)
139
- json = JSON.parse(RestClient.get(route))
140
- !!json[name]
187
+ # @return [void]
188
+ def self.open_browser(url)
189
+
190
+ cmd = case RbConfig::CONFIG['host_os']
191
+ when /mswin|mingw|cygwin/ then "start \"\"#{url}\"\""
192
+ when /darwin/ then "open '#{url}'"
193
+ when /linux|bsd/ then "xdg-open '#{url}'"
194
+ else raise(Ruqqus::Error, 'unable to determine how to open URL for current platform')
195
+ end
196
+
197
+ system(cmd)
198
+ end
199
+
200
+ ##
201
+ # If using a `localhost` address for your application's OAuth redirect, this method can be used to open a socket and
202
+ # listen for a request, returning the authorization code once it arrives.
203
+ #
204
+ # @param port [Integer] the port to listen on.
205
+ # @param timeout [Numeric] sets the number of seconds to wait before cancelling and returning `nil`.
206
+ #
207
+ # @return [String?] the authorization code, `nil` if an error occurred.
208
+ # @note This method is blocking, and will *not* return until a connection is made and data is received on the
209
+ # specified port, or the timeout is reached.
210
+ def self.wait_for_code(port, timeout = 30)
211
+
212
+ thread = Thread.new do
213
+ sleep(timeout)
214
+ TCPSocket.open('localhost', port) { |s| s.puts }
215
+ end
216
+
217
+ params = {}
218
+ TCPServer.open('localhost', port) do |server|
219
+
220
+ session = server.accept
221
+ request = session.gets
222
+ match = /^GET [\/?]+(.*) HTTP.*/.match(request)
223
+
224
+ Thread.kill(thread)
225
+ return nil unless match
226
+
227
+ $1.split('&').each do |str|
228
+ key, value = str.split('=')
229
+ next unless key && value
230
+ params[key.to_sym] = value
231
+ end
232
+
233
+ session.puts "HTTP/1.1 200\r\n"
234
+ session.puts "Content-Type: text/html\r\n"
235
+ session.puts "\r\n"
236
+ session.puts create_response(!!params[:code])
237
+
238
+ session.close
239
+ end
240
+
241
+ params[:code]
242
+ end
243
+
244
+ private
245
+
246
+ ##
247
+ # @return [String] a generic confirmation page to display in the user's browser after confirming application access.
248
+ def self.create_response(success)
249
+ args = success ? ['#339966', 'Authorization Confirmed'] : ['#ff0000', 'Authorization Failed']
250
+ format ='<h1 style="text-align: center;"><span style="color: %s;"><strong>%s</strong></span></h1>'
251
+ message = sprintf(format, *args)
252
+ <<-EOS
253
+ <html>
254
+ <head>
255
+ <style>
256
+ .center {
257
+ margin: 0;
258
+ position: absolute;
259
+ top: 50%;
260
+ left: 50%;
261
+ -ms-transform: translate(-50%, -50%);
262
+ transform: translate(-50%, -50%);
263
+ }
264
+ </style>
265
+ </head>
266
+ <body>
267
+ <div class="center">
268
+ <div><img src="https://raw.githubusercontent.com/ruqqus/ruqqus/master/ruqqus/assets/images/logo/ruqqus_text_logo.png" alt="" width="365" height="92" /></div>
269
+ <p style="text-align: center;">&nbsp;</p>
270
+ #{message}
271
+ <p style="text-align: center;">&nbsp;&nbsp;</p>
272
+ <p style="text-align: center;"><span style="color: #808080;">You can safely close the tab/browser and return to the application.</span></p>
273
+ </div>
274
+ </body>
275
+ </html>
276
+ EOS
141
277
  end
142
278
  end
@@ -62,7 +62,7 @@ module Ruqqus
62
62
  #
63
63
  # @return [User] the requested {User}.
64
64
  #
65
- # @raise [ArgumentError] when `username` is `nil` or value does match the {VALID_USERNAME} regular expression.
65
+ # @raise [ArgumentError] when `username` is `nil` or value does match the {Ruqqus::VALID_USERNAME} regular expression.
66
66
  # @raise [Error] thrown when user account does not exist.
67
67
  def user(username)
68
68
  raise(ArgumentError, 'username cannot be nil') unless username
@@ -77,7 +77,7 @@ module Ruqqus
77
77
  #
78
78
  # @return [Guild] the requested {Guild}.
79
79
  #
80
- # @raise [ArgumentError] when `guild_name` is `nil` or value does match the {VALID_GUILD} regular expression.
80
+ # @raise [ArgumentError] when `guild_name` is `nil` or value does match the {Ruqqus::VALID_GUILD} regular expression.
81
81
  # @raise [Error] thrown when guild does not exist.
82
82
  def guild(guild_name)
83
83
  raise(ArgumentError, 'guild_name cannot be nil') unless guild_name
@@ -92,7 +92,7 @@ module Ruqqus
92
92
  #
93
93
  # @return [Post] the requested {Post}.
94
94
  #
95
- # @raise [ArgumentError] when `post_id` is `nil` or value does match the {VALID_POST} regular expression.
95
+ # @raise [ArgumentError] when `post_id` is `nil` or value does match the {Ruqqus::VALID_POST} regular expression.
96
96
  # @raise [Error] thrown when a post with the specified ID does not exist.
97
97
  def post(post_id)
98
98
  raise(ArgumentError, 'post_id cannot be nil') unless post_id
@@ -107,7 +107,7 @@ module Ruqqus
107
107
  #
108
108
  # @return [Comment] the requested {Comment}.
109
109
  #
110
- # @raise [ArgumentError] when `comment_id` is `nil` or value does match the {VALID_POST} regular expression.
110
+ # @raise [ArgumentError] when `comment_id` is `nil` or value does match the {Ruqqus::VALID_POST} regular expression.
111
111
  # @raise [Error] when a comment with the specified ID does not exist.
112
112
  def comment(comment_id)
113
113
  raise(ArgumentError, 'comment_id cannot be nil') unless comment_id
@@ -1,11 +1,15 @@
1
1
  module Ruqqus
2
2
 
3
3
  ##
4
- # The Ruqqus gem version.
5
- VERSION = '1.1.2'.freeze
4
+ # The Ruqqus gem version. Version changes implement the following versioning system:
5
+ #
6
+ # * `MAJOR` Corresponds to the native Ruqqus API major version
7
+ # * `MINOR` Indicates possible breaking API changes for existing code
8
+ # * `REVISION` Added functionality, bug-fixes, and other non-breaking alterations
9
+ VERSION = '1.1.3'.freeze
6
10
 
7
11
  ##
8
- # Lulz
12
+ # Please listen to this song I wrote. The song is called "Endless Summer".
9
13
  ENDLESS_SUMMER = 'https://youtu.be/o_LskiXQ73c'.freeze
10
14
 
11
15
  private_constant(:ENDLESS_SUMMER)
@@ -36,7 +36,8 @@ Gem::Specification.new do |spec|
36
36
  spec.add_runtime_dependency('rest-client', '~> 2.1')
37
37
 
38
38
  spec.add_development_dependency('mechanize', '~> 2.7')
39
- spec.add_development_dependency('rake', '~> 13.0')
40
39
  spec.add_development_dependency('tty-prompt', '~> 0.22')
41
40
  spec.add_development_dependency('yard', '~> 0.9')
41
+
42
+ spec.post_install_message = 'Please listen to this song I wrote. The song is called "Endless Summer".'
42
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruqqus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ForeverZer0
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-07 00:00:00.000000000 Z
11
+ date: 2020-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.7'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '13.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '13.0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: tty-prompt
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -126,7 +112,8 @@ metadata:
126
112
  changelog_uri: https://github.com/ForeverZer0/ruqqus/CHANGELOG.md
127
113
  documentation_uri: https://www.rubydoc.info/gems/ruqqus
128
114
  bug_tracker_uri: https://github.com/ForeverZer0/ruqqus/issues
129
- post_install_message:
115
+ post_install_message: Please listen to this song I wrote. The song is called "Endless
116
+ Summer".
130
117
  rdoc_options: []
131
118
  require_paths:
132
119
  - lib