algoliasearch 1.2.4 → 1.2.5

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
  SHA1:
3
- metadata.gz: 5f84365c51f1592ac0bd372b32ef668eae0831ec
4
- data.tar.gz: 315a6fbb785510696b8a9d1717de2cf09e208fd2
3
+ metadata.gz: ffcea70e1e16052463f966167245f0d0412bb1d1
4
+ data.tar.gz: a37adf050adb92682c8ddd48990b093606ba800d
5
5
  SHA512:
6
- metadata.gz: 3e4bf583e3651c8b02c76e8bc6a50c038c54ab40766bc14ad1ca8ad6f8608e90984827aa4f8a5474d956af1ac4ebf9e5ff48e93696132fd12bb229769ad193e3
7
- data.tar.gz: 6adcdf51f0a2702b5a7adbdebae0387a6d05a2c6957a44cdb388e37c0650aba41df48223ab110dccbaf13b7b53f39f16a5b211b5bbcc991e9d57e1303b7fb49d
6
+ metadata.gz: fc1fbead2ee31e7e503b7864d7779c9455d99f1925de7f5ca765c0a0229dc0c4b81680a9b814c029a0b06152b8729565dae1f8ecb342a07c46f650771ec4df07
7
+ data.tar.gz: 79a73010bbaa3b99227c9693ea9f71ba9c6627b02faf4dd4a9f772bef98b0cb9af637e67e65049fa797d056bd22cafa6415b6a28db23164a1810c1e7a3a3288f
data/ChangeLog CHANGED
@@ -1,5 +1,10 @@
1
1
  CHANGELOG
2
2
 
3
+ 2014-02-24 1.2.5
4
+
5
+ * Ability to generate secured API key from a list of tags + optional user_token
6
+ * Ability to specify a list of indexes targeted by the user key
7
+
3
8
  2014-02-21 1.2.4
4
9
 
5
10
  * Added delete_objects
data/README.md CHANGED
@@ -295,6 +295,8 @@ The server response will look like:
295
295
 
296
296
 
297
297
 
298
+
299
+
298
300
  Get an object
299
301
  -------------
300
302
 
@@ -494,13 +496,18 @@ You can also create an API Key with advanced restrictions:
494
496
  Note: If you are sending the query through your servers, you must use the `Algolia.with_rate_limits("EndUserIP", "APIKeyWithRateLimit") do ... end` block to enable rate-limit.
495
497
 
496
498
  * Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited). This parameter can be used to protect you from attempts at retrieving your entire content by massively querying the index.
499
+ * Specify the list of targeted indexes. Defaults to all indexes if empty of blank.
497
500
 
498
501
  ```ruby
499
502
  # Creates a new global API key that is valid for 300 seconds
500
503
  res = Algolia.add_user_key(["search"], 300)
501
504
  puts res['key']
502
- # Creates a new index specific API key valid for 300 seconds, with a rate limit of 100 calls per hour per IP and a maximum of 20 hits
503
- res = index.add_user_key(["search"], 300, 100, 20)
505
+ # Creates a new index specific API key:
506
+ # - valid for 300 seconds
507
+ # - rate limit of 100 calls per hour per IP
508
+ # - maximum of 20 hits
509
+ # - valid on 'my_index1' and 'my_index2'
510
+ res = index.add_user_key(["search"], 300, 100, 20, ['my_index1', 'my_index2'])
504
511
  puts res['key']
505
512
  ```
506
513
 
@@ -520,6 +527,49 @@ Algolia.delete_user_key("f420238212c54dcfad07ea0aa6d5c45f")
520
527
  index.delete_user_key("71671c38001bf3ac857bc82052485107")
521
528
  ```
522
529
 
530
+ You may have a single index containing per-user data. In that case, all records should be tagged with their associated user_id in order to add a `tagFilters=(public,user_42)` filter at query time to retrieve only what a user has access to. If you're using the [JavaScript client](http://github.com/algolia/algoliasearch-client-js), it will result in a security breach since the user is able to modify the `tagFilters` you've set modifying the code from the browser. To keep using the JavaScript client (recommended for optimal latency) and target secured records, you can generate secured API key from your backend:
531
+
532
+ ```ruby
533
+ # generate a public API key for user 42. Here, records are tagged with:
534
+ # - 'public' if they are visible by all users
535
+ # - 'user_XXXX' if they are visible by user XXXX
536
+ public_key = Algolia.generate_secured_api_key 'YourSearchOnlyApiKey', '(public,user_42)'
537
+ ```
538
+
539
+ This public API key must then be used in your JavaScript code as follow:
540
+
541
+ ```javascript
542
+ <script type="text/javascript">
543
+ var algolia = new AlgoliaSearch('YourApplicationID', '<%= public_api_key %>');
544
+ algolia.setSecurityTags('(public,user_42)'); // must be same than those used at generation-time
545
+ algolia.initIndex('YourIndex').search($('#q').val(), function(success, content) {
546
+ // [...]
547
+ });
548
+ </script>
549
+ ```
550
+
551
+ You can mix rate limits and secured API keys setting an extra `user_token` attribute both at API key generation-time and query-time. When set, a uniq user will be identified by her `IP + user_token` instead of only her `IP`. It allows you to restrict a single user to perform maximum `N` API calls per hour, even if she share her `IP` with another user.
552
+
553
+ ```ruby
554
+ # generate a public API key for user 42. Here, records are tagged with:
555
+ # - 'public' if they are visible by all users
556
+ # - 'user_XXXX' if they are visible by user XXXX
557
+ public_key = Algolia.generate_secured_api_key 'YourRateLimitedApiKey', '(public,user_42)', 'user_42'
558
+ ```
559
+
560
+ This public API key must then be used in your JavaScript code as follow:
561
+
562
+ ```javascript
563
+ <script type="text/javascript">
564
+ var algolia = new AlgoliaSearch('YourApplicationID', '<%= public_api_key %>');
565
+ algolia.setSecurityTags('(public,user_42)'); // must be same than those used at generation-time
566
+ algolia.setUserToken('user_42') // must be same than the one used at generation-time
567
+ algolia.initIndex('YourIndex').search($('#q').val(), function(success, content) {
568
+ // [...]
569
+ });
570
+ </script>
571
+ ```
572
+
523
573
  Copy or rename an index
524
574
  -------------
525
575
 
@@ -6,12 +6,12 @@
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "algoliasearch"
9
- s.version = "1.2.4"
9
+ s.version = "1.2.5"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Algolia"]
14
- s.date = "2014-02-21"
14
+ s.date = "2014-02-24"
15
15
  s.description = "A simple Ruby client for the algolia.com REST API"
16
16
  s.email = "contact@algolia.com"
17
17
  s.extra_rdoc_files = [
@@ -148,6 +148,22 @@ module Algolia
148
148
  end
149
149
  end
150
150
 
151
+ #
152
+ # Generate a secured and public API Key from a list of tagFilters and an
153
+ # optional user token identifying the current user
154
+ #
155
+ # @param private_api_key your private API Key
156
+ # @param tag_filters the list of tags applied to the query (used as security)
157
+ # @param user_token an optional token identifying the current user
158
+ #
159
+ def Algolia.generate_secured_api_key(private_api_key, tag_filters, user_token = nil)
160
+ if tag_filters.is_a?(Array)
161
+ tag_filters = tag_filters.map { |t| t.is_a?(Array) ? "(#{t.join(',')})" : t }.join(',')
162
+ end
163
+ raise ArgumentError.new('Attribute "tag_filters" must be a list of tags') if !tag_filters.is_a?(String)
164
+ Digest::SHA256.hexdigest "#{private_api_key}#{tag_filters}#{user_token.to_s}"
165
+ end
166
+
151
167
  #
152
168
  # List all existing indexes
153
169
  # return an Answer object with answer in the form
@@ -213,9 +229,17 @@ module Algolia
213
229
  # @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key)
214
230
  # @param maxQueriesPerIPPerHour the maximum number of API calls allowed from an IP address per hour (0 means unlimited)
215
231
  # @param maxHitsPerQuery the maximum number of hits this API key can retrieve in one call (0 means unlimited)
232
+ # @param indexes the optional list of targeted indexes
216
233
  #
217
- def Algolia.add_user_key(acls, validity = 0, maxQueriesPerIPPerHour = 0, maxHitsPerQuery = 0)
218
- Algolia.client.post(Protocol.keys_uri, {"acl" => acls, "validity" => validity.to_i, "maxQueriesPerIPPerHour" => maxQueriesPerIPPerHour.to_i, "maxHitsPerQuery" => maxHitsPerQuery.to_i}.to_json)
234
+ def Algolia.add_user_key(acls, validity = 0, maxQueriesPerIPPerHour = 0, maxHitsPerQuery = 0, indexes = nil)
235
+ params = {
236
+ :acl => acls,
237
+ :validity => validity.to_i,
238
+ :maxQueriesPerIPPerHour => maxQueriesPerIPPerHour.to_i,
239
+ :maxHitsPerQuery => maxHitsPerQuery.to_i
240
+ }
241
+ params[:indexes] = indexes if indexes
242
+ Algolia.client.post(Protocol.keys_uri, params.to_json)
219
243
  end
220
244
 
221
245
  # Delete an existing user key
@@ -1,3 +1,3 @@
1
1
  module Algolia
2
- VERSION = "1.2.3"
2
+ VERSION = "1.2.5"
3
3
  end
@@ -214,6 +214,9 @@ describe 'Client' do
214
214
  end
215
215
 
216
216
  it "should get logs" do
217
+ host = Algolia.client.send(:thread_local_hosts).first
218
+ puts host[:session].get(host[:base_url] + Algolia::Protocol.logs(0, 10), { :header => Algolia.client.headers }).content
219
+
217
220
  res = Algolia.get_logs
218
221
 
219
222
  res['logs'].size.should > 0
@@ -561,4 +564,15 @@ describe 'Client' do
561
564
  logs['logs'][0].should have_key('sha1')
562
565
  logs['logs'][0]['sha1'].should be_a(String)
563
566
  end
567
+
568
+ it 'should generate secured api keys' do
569
+ key = Algolia.generate_secured_api_key('my_api_key', '(public,user1)')
570
+ key.should eq(Digest::SHA256.hexdigest 'my_api_key(public,user1)')
571
+ key = Algolia.generate_secured_api_key('my_api_key', '(public,user1)', 42)
572
+ key.should eq(Digest::SHA256.hexdigest 'my_api_key(public,user1)42')
573
+ key = Algolia.generate_secured_api_key('my_api_key', ['public'])
574
+ key.should eq(Digest::SHA256.hexdigest 'my_api_keypublic')
575
+ key = Algolia.generate_secured_api_key('my_api_key', ['public', ['premium','vip']])
576
+ key.should eq(Digest::SHA256.hexdigest 'my_api_keypublic,(premium,vip)')
577
+ end
564
578
  end
metadata CHANGED
@@ -1,85 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algoliasearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Algolia
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-21 00:00:00.000000000 Z
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient
15
- requirement: !ruby/object:Gem::Requirement
15
+ version_requirements: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.3'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
20
+ requirement: !ruby/object:Gem::Requirement
23
21
  requirements:
24
22
  - - ~>
25
23
  - !ruby/object:Gem::Version
26
24
  version: '2.3'
25
+ prerelease: false
26
+ type: :runtime
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: json
29
- requirement: !ruby/object:Gem::Requirement
29
+ version_requirements: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.5.1
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
34
+ requirement: !ruby/object:Gem::Requirement
37
35
  requirements:
38
36
  - - '>='
39
37
  - !ruby/object:Gem::Version
40
38
  version: 1.5.1
39
+ prerelease: false
40
+ type: :runtime
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: travis
43
- requirement: !ruby/object:Gem::Requirement
43
+ version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
51
49
  requirements:
52
50
  - - '>='
53
51
  - !ruby/object:Gem::Version
54
52
  version: '0'
53
+ prerelease: false
54
+ type: :development
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
- requirement: !ruby/object:Gem::Requirement
57
+ version_requirements: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
62
+ requirement: !ruby/object:Gem::Requirement
65
63
  requirements:
66
64
  - - '>='
67
65
  - !ruby/object:Gem::Version
68
66
  version: '0'
67
+ prerelease: false
68
+ type: :development
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rdoc
71
- requirement: !ruby/object:Gem::Requirement
71
+ version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
76
+ requirement: !ruby/object:Gem::Requirement
79
77
  requirements:
80
78
  - - '>='
81
79
  - !ruby/object:Gem::Version
82
80
  version: '0'
81
+ prerelease: false
82
+ type: :development
83
83
  description: A simple Ruby client for the algolia.com REST API
84
84
  email: contact@algolia.com
85
85
  executables: []
@@ -115,7 +115,7 @@ homepage: http://github.com/algolia/algoliasearch-client-ruby
115
115
  licenses:
116
116
  - MIT
117
117
  metadata: {}
118
- post_install_message:
118
+ post_install_message:
119
119
  rdoc_options: []
120
120
  require_paths:
121
121
  - lib
@@ -130,9 +130,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  requirements: []
133
- rubyforge_project:
134
- rubygems_version: 2.1.11
135
- signing_key:
133
+ rubyforge_project:
134
+ rubygems_version: 2.2.1
135
+ signing_key:
136
136
  specification_version: 4
137
137
  summary: A simple Ruby client for the algolia.com REST API
138
138
  test_files: []