ruqqus 1.1.0 → 1.1.1

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: bb4087c263dae6ef0708a07d756733ea19f95e1e6f02983c658c9cfb40a2f475
4
- data.tar.gz: d9d71b14897ec30ea1f5356916d1eb2cc432db02e7c007fb5f8efcea3a3f37fa
3
+ metadata.gz: aef052e6ba89775ce82f8d1474b12b74a0ec84260ae5abcb41b2c098e1befbf2
4
+ data.tar.gz: 79385f50df81574939d19746d8f36e9e66e075553ec980c5daa0d411cd27e60c
5
5
  SHA512:
6
- metadata.gz: f5864e192920e53c59921cf9bdb7d2f2acaf261d77ed4c0d3184a7f601cf967cf87f358c4b396705b8366fcda6ed3d54a9a125b0f13e7e139d0ce3ff0f67535e
7
- data.tar.gz: 73d7d5b8a4551a7bc83efd54b8be72107a010f4023dc9784396dddce8ceae4808049cc6fed37487b07e259b6efc41a1ff75d8184bf5ce28f18f8c261e2ffd0e4
6
+ metadata.gz: 2039cc29cfde59766c5d249c74b49c132b709db04553848d5e8915df242dc276f2b550289bc43b58b322987851e747feede7dbe7ee89ba5ef9f0e6c096afa546
7
+ data.tar.gz: d62ca8506d89f4c8e772fa24daf57c0dca3e6d90c57a473a82eb6b0e89c10ab564058c198c5fb75d038c573b8792945d51633e440857322b2d64f8dc6867386c
data/.gitignore CHANGED
@@ -168,3 +168,4 @@ modules.xml
168
168
 
169
169
  # JSON file containing the token for test user during development
170
170
  /token.json
171
+ /test.rb
@@ -2,6 +2,12 @@
2
2
 
3
3
  Documentation for library API changes.
4
4
 
5
+ ## Version 1.1.1
6
+
7
+ * BUGFIX: Added acceptance of variable args to `Token#to_json`
8
+ * BUGFIX: Fixed regex validator in `ruqqus-oauth` for the client ID
9
+ * Separated the client ID/secret from the `Token` class, and placed within `Client` to now handle this logic
10
+
5
11
  ## Version 1.1.0
6
12
 
7
13
  * Implemented `Ruqqus::Token` class to handle OAuth2 authentication
data/README.md CHANGED
@@ -67,7 +67,11 @@ code = 'XXXXXX' # The generated code (or the one you obtained via tradi
67
67
 
68
68
  # You must implement a responsible way of storing this token for reuse.
69
69
  token = Ruqqus::Token.new(client_id, client_secret, code)
70
- client = Ruqqus::Client.new(token)
70
+ client = Ruqqus::Client.new(client_id, client_secret, token)
71
+
72
+ # Alternatively, you can create a new token and a client with a single call.
73
+ # This will perform the "grant" action of the code while creating it automatically
74
+ client = Ruqqus::Client.new(client_id, client_secret, code)
71
75
  ```
72
76
 
73
77
  The token will automatically refresh itself as-needed, but you will need to handle storing its new value for repeated
@@ -75,12 +79,16 @@ uses. To facilitate this and make it easier, there is a callback that can be sub
75
79
  time the access key is updated.
76
80
 
77
81
  ```ruby
82
+ # Load an existing token that has already been authorized
78
83
  token = Ruqqus::Token.load_json('./token.json')
79
- token.on_refresh do |t|
84
+
85
+ # Create your client
86
+ client = Ruqqus::Client.new(client_id, client_secret, token)
87
+
88
+ # Set the callback block to automatically update the saved token when it refreshes
89
+ client.token_refreshed do |t|
80
90
  t.save_json('./token.json')
81
91
  end
82
-
83
- client = Ruqqus::Client.new(token)
84
92
  ```
85
93
 
86
94
  The token obtains sensitive material, and due to the security issues of storing it in plain text, this functionality is
@@ -89,7 +97,7 @@ and where you store this information so that it is not compromised.
89
97
 
90
98
  ## Usage
91
99
 
92
- See the [documentation](https://www.rubydoc.info/gems/ruqqus) for a complete API reference.
100
+ See the [documentation](https://www.rubydoc.info/gems/ruqqus) for a complete API reference (100% coverage).
93
101
 
94
102
  ### Features
95
103
 
@@ -41,11 +41,11 @@ class RuqqusOAuth
41
41
  end
42
42
 
43
43
  def ask_client_id(prompt)
44
- prompt.ask('Client ID: ') { |q| q.validate(/^[A-Fa-f0-9]+$/, "Invalid client ID") }
44
+ prompt.ask('Client ID: ') { |q| q.validate(/^[A-Za-z0-9_-]+$/, "Invalid client ID") }
45
45
  end
46
46
 
47
47
  def ask_client_secret(prompt)
48
- prompt.ask('Client Secret: ') { |q| q.validate(/^[A-Fa-f0-9]+$/, "Invalid client secret") }
48
+ prompt.ask('Client Secret: ') { |q| q.validate(/^[A-Za-z0-9_-]+$/, "Invalid client secret") }
49
49
  end
50
50
 
51
51
  def ask_client_redirect(prompt)
@@ -9,7 +9,7 @@ module Ruqqus
9
9
 
10
10
  ##
11
11
  # The user-agent the client identified itself as.
12
- USER_AGENT = "ruqqus-ruby/#{Ruqqus::VERSION} (efreed09@gmail.com)".freeze
12
+ USER_AGENT = "ruqqus-ruby/#{Ruqqus::VERSION}".freeze
13
13
 
14
14
  ##
15
15
  # A collection of valid scopes that can be authorized.
@@ -20,22 +20,39 @@ module Ruqqus
20
20
  DEFAULT_HEADERS = { 'User-Agent': USER_AGENT, 'Accept': 'application/json', 'Content-Type': 'application/json' }.freeze
21
21
 
22
22
  ##
23
- # @return [Token] the OAuth2 token that grants the client authentication.
24
- attr_reader :token
23
+ # @!attribute [rw] token
24
+ # @return [Token] the OAuth2 token that grants the client authentication.
25
25
 
26
26
  ##
27
27
  # @!attribute [r] identity
28
28
  # @return [User] the authenticated user this client is performing actions as.
29
29
 
30
30
  ##
31
- # Creates a new instance of the {Client} class.
32
- #
33
- # @param token [Token] a valid access token to authorize the client.
34
- def initialize(token)
35
- @token = token || raise(ArgumentError, 'token cannot be nil')
31
+ # @overload initialize(client_id, client_secret, token)
32
+ # Creates a new instance of the {Client} class with an existing token for authorization.
33
+ # @param client_id [String] the client ID of your of your application, issued after registration on Ruqqus.
34
+ # @param client_secret [String] the client secret of your of your application, issued after registration on Ruqqus.
35
+ # @param token [Token] a valid access token that has previously been granted access for the client.
36
+ #
37
+ # @overload initialize(client_id, client_secret, code)
38
+ # Creates a new instance of the {Client} class with an existing token for authorization.
39
+ # @param client_id [String] the client ID of your of your application, issued after registration on Ruqqus.
40
+ # @param client_secret [String] the client secret of your of your application, issued after registration on Ruqqus.
41
+ # @param code [String] a the code from the Oauth2 redirect to create a new {Token} and grant access to it.
42
+ def initialize(client_id, client_secret, token)
43
+ @client_id = client_id || raise(ArgumentError, 'client ID cannot be nil')
44
+ @client_secret = client_secret || raise(ArgumentError, 'client secret cannot be nil')
45
+
46
+ @token = token.is_a?(Token) ? token : Token.new(client_id, client_secret, token.to_s)
36
47
  @session = nil
37
48
  end
38
49
 
50
+ attr_reader :token
51
+
52
+ def token=(token)
53
+ @token = token || raise(ArgumentError, 'token cannot be nil')
54
+ end
55
+
39
56
  # @!group Object Querying
40
57
 
41
58
  ##
@@ -358,10 +375,25 @@ module Ruqqus
358
375
 
359
376
  # @!endgroup Object Enumeration
360
377
 
378
+ ##
379
+ # @return [User] the authenticated user this client is performing actions as.
361
380
  def identity
362
381
  @me ||= User.from_json(http_get(Routes::IDENTITY))
363
382
  end
364
383
 
384
+ ##
385
+ # @overload token_refreshed(&block)
386
+ # Sets a callback to be invoked when the token is refreshed, and a new access token is assigned.
387
+ # @yieldparam token [Token] yields the newly refreshed {Token} to the block.
388
+ #
389
+ # @overload token_refreshed
390
+ # When called without a block, clears any callback that was previously assigned.
391
+ #
392
+ # @return [void]
393
+ def token_refreshed(&block)
394
+ @refreshed = block_given? ? block : nil
395
+ end
396
+
365
397
  private
366
398
 
367
399
  ##
@@ -444,7 +476,7 @@ module Ruqqus
444
476
  # @return [Hash] the response deserialized into a JSON hash.
445
477
  # @see http_post
446
478
  def http_get(uri, header = nil)
447
- @token.refresh if @token && @token.expired?
479
+ refresh_token
448
480
  header ||= headers
449
481
  response = RestClient.get(uri.chomp('/'), header)
450
482
  @session = response.cookies['session_ruqqus'] if response.cookies['session_ruqqus']
@@ -463,12 +495,21 @@ module Ruqqus
463
495
  # @return [Hash] the response deserialized into a JSON hash.
464
496
  # @see http_get
465
497
  def http_post(uri, params = {}, header = nil)
466
- @token.refresh if @token && @token.expired?
498
+ refresh_token
467
499
  header ||= headers
468
500
  response = RestClient.post(uri.chomp('/'), params, header)
469
501
  @session = response.cookies['session_ruqqus'] if response.cookies['session_ruqqus']
470
502
  raise(Ruqqus::Error, 'HTTP request failed') if response.code < 200 || response.code >= 300
471
503
  JSON.parse(response, symbolize_names: response.body)
472
504
  end
505
+
506
+ ##
507
+ # @api private
508
+ # Checks if token is expired, and refreshes if so, calling the {#token_refreshed} block as if defined.
509
+ def refresh_token
510
+ return unless @token.expired?
511
+ @token.refresh(@client_id, @client_secret)
512
+ @refreshed&.call(@token)
513
+ end
473
514
  end
474
515
  end
@@ -37,15 +37,11 @@ module Ruqqus
37
37
  headers = { 'User-Agent': Client::USER_AGENT, 'Accept': 'application/json', 'Content-Type': 'application/json' }
38
38
  params = { code: code, client_id: client_id, client_secret: client_secret, grant_type: 'code', permanent: persist }
39
39
  resp = RestClient.post('https://ruqqus.com/oauth/grant', params, headers )
40
-
41
- @client_id = client_id
42
- @client_secret = client_secret
43
40
  @data = JSON.parse(resp.body, symbolize_names: true)
44
41
 
45
42
  raise(Ruqqus::Error, 'failed to grant access for token') if @data[:oauth_error]
46
43
  end
47
44
 
48
-
49
45
  def access_token
50
46
  @data[:access_token]
51
47
  end
@@ -70,32 +66,14 @@ module Ruqqus
70
66
  # Refreshes the access token and resets its time of expiration.
71
67
  #
72
68
  # @return [void]
73
- def refresh
69
+ def refresh(client_id, client_secret)
74
70
  headers = { 'User-Agent': Client::USER_AGENT, Authorization: "Bearer #{access_token}" }
75
- params = { client_id: @client_id, client_secret: @client_secret, refresh_token: refresh_token, grant_type: 'refresh' }
71
+ params = { client_id: client_id, client_secret: client_secret, refresh_token: refresh_token, grant_type: 'refresh' }
76
72
  resp = RestClient.post('https://ruqqus.com/oauth/grant', params, headers )
77
73
 
78
74
  data = JSON.parse(resp.body, symbolize_names: true)
79
75
  raise(Ruqqus::Error, 'failed to refresh authentication token') unless resp.code == 200 || data[:oauth_error]
80
76
  @data.merge!(data)
81
- @refreshed&.call(self)
82
- end
83
-
84
- ##
85
- # Sets a callback block that will be invoked when the token is refresh. This can be used to automate saving the
86
- # token after its gets updated.
87
- #
88
- # @yieldparam token [Token] yields the token to the block.
89
- #
90
- # @return [self]
91
- #
92
- # @example Auto-save updated token
93
- # token = Token.load_json('./token.json')
94
- # token.on_refresh { |t| t.save_json('./token.json') }
95
- def on_refresh(&block)
96
- raise(LocalJumpError, "block required") unless block_given?
97
- @refreshed = block
98
- self
99
77
  end
100
78
 
101
79
  ##
@@ -106,8 +84,8 @@ module Ruqqus
106
84
 
107
85
  ##
108
86
  # @return [String] the object as a JSON-formatted string.
109
- def to_json
110
- { client_id: @client_id, client_secret: @client_secret, data: @data }.to_json
87
+ def to_json(*_unused_)
88
+ @data.to_json
111
89
  end
112
90
 
113
91
  ##
@@ -133,15 +111,13 @@ module Ruqqus
133
111
  ##
134
112
  # Loads the object from a JSON-formatted string.
135
113
  #
136
- # @param json [String] a JSON string representing the object.
114
+ # @param json [String,Hash] a JSON string representing the object, or the parsed Hash of the JSON data.
137
115
  #
138
116
  # @return [Object] the loaded object.
139
117
  def self.from_json(payload)
140
- data = JSON.parse(payload, symbolize_names: true)
118
+ data = payload.is_a?(Hash) ? payload: JSON.parse(payload, symbolize_names: true)
141
119
  token = allocate
142
- token.instance_variable_set(:@client_id, data[:client_id])
143
- token.instance_variable_set(:@client_secret, data[:client_secret])
144
- token.instance_variable_set(:@data, data[:data])
120
+ token.instance_variable_set(:@data, data)
145
121
  token
146
122
  end
147
123
  end
@@ -2,7 +2,7 @@ module Ruqqus
2
2
 
3
3
  ##
4
4
  # The Ruqqus gem version.
5
- VERSION = '1.1.0'.freeze
5
+ VERSION = '1.1.1'.freeze
6
6
 
7
7
  ##
8
8
  # Lulz
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.version = Ruqqus::VERSION
8
8
  spec.authors = ['ForeverZer0']
9
9
  spec.email = ['efreed09@gmail.com']
10
- spec.summary = %q{A Ruby API implementation for Ruqqus, an open-source platform for online communities.}
10
+ spec.summary = %q{A Ruby API implementation for Ruqqus, an open-source platform for online communities}
11
11
  spec.description = %q{A Ruby API implementation for Ruqqus, an open-source platform for online communities, free of censorship and moderator abuse by design.}
12
12
  spec.homepage = 'https://github.com/ForeverZer0/ruqqus'
13
13
  spec.license = 'MIT'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruqqus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ForeverZer0
@@ -145,5 +145,5 @@ rubygems_version: 3.1.4
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: A Ruby API implementation for Ruqqus, an open-source platform for online
148
- communities.
148
+ communities
149
149
  test_files: []